You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

JavaEnvUtils.java 22 kB

10 years ago
10 years ago
10 years ago
10 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601
  1. /*
  2. * Licensed to the Apache Software Foundation (ASF) under one or more
  3. * contributor license agreements. See the NOTICE file distributed with
  4. * this work for additional information regarding copyright ownership.
  5. * The ASF licenses this file to You under the Apache License, Version 2.0
  6. * (the "License"); you may not use this file except in compliance with
  7. * the License. You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. *
  17. */
  18. package org.apache.tools.ant.util;
  19. import java.io.BufferedWriter;
  20. import java.io.File;
  21. import java.io.FileWriter;
  22. import java.io.IOException;
  23. import java.util.Vector;
  24. import org.apache.tools.ant.taskdefs.condition.Os;
  25. /**
  26. * A set of helper methods related to locating executables or checking
  27. * conditions of a given Java installation.
  28. *
  29. * <p>Starting with Java 10 we've stopped adding <code>JAVA_</code>
  30. * and <code>VERSION_</code> attributes for new major version numbers
  31. * of the JVM.</p>
  32. *
  33. * @since Ant 1.5
  34. */
  35. public final class JavaEnvUtils {
  36. private JavaEnvUtils() {
  37. }
  38. /** Are we on a DOS-based system */
  39. private static final boolean IS_DOS = Os.isFamily("dos");
  40. /** Are we on Novell NetWare */
  41. private static final boolean IS_NETWARE = Os.isName("netware");
  42. /** Are we on AIX */
  43. private static final boolean IS_AIX = Os.isName("aix");
  44. /** shortcut for System.getProperty("java.home") */
  45. private static final String JAVA_HOME = System.getProperty("java.home");
  46. /** FileUtils instance for path normalization */
  47. private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
  48. /** Version of currently running VM. */
  49. private static String javaVersion;
  50. /** floating version of the JVM */
  51. private static int javaVersionNumber;
  52. /** Version of currently running VM. */
  53. private static final DeweyDecimal parsedJavaVersion;
  54. /** Version constant for Java 1.0 */
  55. public static final String JAVA_1_0 = "1.0";
  56. /** Number Version constant for Java 1.0 */
  57. public static final int VERSION_1_0 = 10;
  58. /** Version constant for Java 1.1 */
  59. public static final String JAVA_1_1 = "1.1";
  60. /** Number Version constant for Java 1.1 */
  61. public static final int VERSION_1_1 = 11;
  62. /** Version constant for Java 1.2 */
  63. public static final String JAVA_1_2 = "1.2";
  64. /** Number Version constant for Java 1.2 */
  65. public static final int VERSION_1_2 = 12;
  66. /** Version constant for Java 1.3 */
  67. public static final String JAVA_1_3 = "1.3";
  68. /** Number Version constant for Java 1.3 */
  69. public static final int VERSION_1_3 = 13;
  70. /** Version constant for Java 1.4 */
  71. public static final String JAVA_1_4 = "1.4";
  72. /** Number Version constant for Java 1.4 */
  73. public static final int VERSION_1_4 = 14;
  74. /** Version constant for Java 1.5 */
  75. public static final String JAVA_1_5 = "1.5";
  76. /** Number Version constant for Java 1.5 */
  77. public static final int VERSION_1_5 = 15;
  78. /** Version constant for Java 1.6 */
  79. public static final String JAVA_1_6 = "1.6";
  80. /** Number Version constant for Java 1.6 */
  81. public static final int VERSION_1_6 = 16;
  82. /** Version constant for Java 1.7 */
  83. public static final String JAVA_1_7 = "1.7";
  84. /** Number Version constant for Java 1.7 */
  85. public static final int VERSION_1_7 = 17;
  86. /** Version constant for Java 1.8 */
  87. public static final String JAVA_1_8 = "1.8";
  88. /** Number Version constant for Java 1.8 */
  89. public static final int VERSION_1_8 = 18;
  90. /**
  91. * Version constant for Java 1.9
  92. * @deprecated use #JAVA_9 instead
  93. */
  94. @Deprecated
  95. public static final String JAVA_1_9 = "1.9";
  96. /**
  97. * Number Version constant for Java 1.9
  98. * @deprecated use #VERSION_9 instead
  99. */
  100. @Deprecated
  101. public static final int VERSION_1_9 = 19;
  102. /**
  103. * Version constant for Java 9
  104. * @since Ant 1.9.8
  105. */
  106. public static final String JAVA_9 = "9";
  107. /**
  108. * Number Version constant for Java 9
  109. * @since Ant 1.9.8
  110. */
  111. public static final int VERSION_9 = 90;
  112. /** Whether this is the Kaffe VM */
  113. private static boolean kaffeDetected;
  114. /** Whether this is a GNU Classpath based VM */
  115. private static boolean classpathDetected;
  116. /** Whether this is the GNU VM (gcj/gij) */
  117. private static boolean gijDetected;
  118. /** Whether this is Apache Harmony */
  119. private static boolean harmonyDetected;
  120. /** array of packages in the runtime */
  121. private static Vector<String> jrePackages;
  122. static {
  123. // Determine the Java version by looking at available classes
  124. // java.net.Proxy was introduced in JDK 1.5
  125. // java.lang.CharSequence was introduced in JDK 1.4
  126. // java.lang.StrictMath was introduced in JDK 1.3
  127. // java.lang.ThreadLocal was introduced in JDK 1.2
  128. // java.lang.Void was introduced in JDK 1.1
  129. // Count up version until a NoClassDefFoundError ends the try
  130. try {
  131. javaVersion = JAVA_1_0;
  132. javaVersionNumber = VERSION_1_0;
  133. Class.forName("java.lang.Void");
  134. javaVersion = JAVA_1_1;
  135. javaVersionNumber++;
  136. Class.forName("java.lang.ThreadLocal");
  137. javaVersion = JAVA_1_2;
  138. javaVersionNumber++;
  139. Class.forName("java.lang.StrictMath");
  140. javaVersion = JAVA_1_3;
  141. javaVersionNumber++;
  142. Class.forName("java.lang.CharSequence");
  143. javaVersion = JAVA_1_4;
  144. javaVersionNumber++;
  145. Class.forName("java.net.Proxy");
  146. javaVersion = JAVA_1_5;
  147. javaVersionNumber++;
  148. Class.forName("java.net.CookieStore");
  149. javaVersion = JAVA_1_6;
  150. javaVersionNumber++;
  151. Class.forName("java.nio.file.FileSystem");
  152. javaVersion = JAVA_1_7;
  153. javaVersionNumber++;
  154. Class.forName("java.lang.reflect.Executable");
  155. javaVersion = JAVA_1_8;
  156. javaVersionNumber++;
  157. Class.forName("java.lang.module.ModuleDescriptor");
  158. javaVersion = JAVA_9;
  159. javaVersionNumber = VERSION_9;
  160. // at least Java9 and this should properly support the purely numeric version property
  161. String v = System.getProperty("java.specification.version");
  162. DeweyDecimal pv = new DeweyDecimal(v);
  163. javaVersionNumber = pv.get(0) * 10;
  164. if (pv.getSize() > 1) {
  165. javaVersionNumber += pv.get(1);
  166. }
  167. javaVersion = pv.toString();
  168. } catch (Throwable t) {
  169. // swallow as we've hit the max class version that
  170. // we have
  171. }
  172. parsedJavaVersion = new DeweyDecimal(javaVersion);
  173. kaffeDetected = false;
  174. try {
  175. Class.forName("kaffe.util.NotImplemented");
  176. kaffeDetected = true;
  177. } catch (Throwable t) {
  178. // swallow as this simply doesn't seem to be Kaffe
  179. }
  180. classpathDetected = false;
  181. try {
  182. Class.forName("gnu.classpath.Configuration");
  183. classpathDetected = true;
  184. } catch (Throwable t) {
  185. // swallow as this simply doesn't seem to be GNU classpath based.
  186. }
  187. gijDetected = false;
  188. try {
  189. Class.forName("gnu.gcj.Core");
  190. gijDetected = true;
  191. } catch (Throwable t) {
  192. // swallow as this simply doesn't seem to be gcj/gij
  193. }
  194. harmonyDetected = false;
  195. try {
  196. Class.forName("org.apache.harmony.luni.util.Base64");
  197. harmonyDetected = true;
  198. } catch (Throwable t) {
  199. // swallow as this simply doesn't seem to be Apache Harmony
  200. }
  201. }
  202. /**
  203. * Returns the version of Java this class is running under.
  204. *
  205. * <p>Up until Java 8 Java version numbers were 1.VERSION -
  206. * e.g. 1.8.x for Java 8, starting with Java 9 it became 9.x.</p>
  207. *
  208. * @return the version of Java as a String, e.g. "1.6" or "9"
  209. */
  210. public static String getJavaVersion() {
  211. return javaVersion;
  212. }
  213. /**
  214. * Returns the version of Java this class is running under.
  215. * <p>This number can be used for comparisons.</p>
  216. * @return the version of Java as a number 10x the major/minor,
  217. * e.g Java1.5 has a value of 15 and Java9 the value 90 - major
  218. * will be 1 for all versions of Java prior to Java 9, minor will
  219. * be 0 for all versions of Java starting with Java 9.
  220. * @deprecated use #getParsedJavaVersion instead
  221. */
  222. @Deprecated
  223. public static int getJavaVersionNumber() {
  224. return javaVersionNumber;
  225. }
  226. /**
  227. * Returns the version of Java this class is running under.
  228. * <p>This number can be used for comparisons.</p>
  229. * @return the version of Java as major.minor, e.g Java1.5 has a
  230. * value of 1.5 and Java9 the value 9 - major will be 1 for all
  231. * versions of Java prior to Java 9, minor will be 0 for all
  232. * versions of Java starting with Java 9.
  233. */
  234. public static DeweyDecimal getParsedJavaVersion() {
  235. return parsedJavaVersion;
  236. }
  237. /**
  238. * Compares the current Java version to the passed in String -
  239. * assumes the argument is one of the constants defined in this
  240. * class.
  241. * Note that Ant now requires JDK 1.5+ so {@link #JAVA_1_0} through
  242. * {@link #JAVA_1_4} need no longer be tested for.
  243. * @param version the version to check against the current version.
  244. * @return true if the version of Java is the same as the given version.
  245. * @since Ant 1.5
  246. */
  247. public static boolean isJavaVersion(String version) {
  248. return javaVersion.equals(version)
  249. || (javaVersion.equals(JAVA_9) && JAVA_1_9.equals(version));
  250. }
  251. /**
  252. * Compares the current Java version to the passed in String -
  253. * assumes the argument is one of the constants defined in this
  254. * class.
  255. * Note that Ant now requires JDK 1.5+ so {@link #JAVA_1_0} through
  256. * {@link #JAVA_1_4} need no longer be tested for.
  257. * @param version the version to check against the current version.
  258. * @return true if the version of Java is the same or higher than the
  259. * given version.
  260. * @since Ant 1.7
  261. */
  262. public static boolean isAtLeastJavaVersion(String version) {
  263. return parsedJavaVersion.compareTo(new DeweyDecimal(version)) >= 0;
  264. }
  265. /**
  266. * Checks whether the current Java VM is Kaffe.
  267. * @return true if the current Java VM is Kaffe.
  268. * @since Ant 1.6.3
  269. * @see <a href="http://www.kaffe.org/">http://www.kaffe.org/</a>
  270. */
  271. public static boolean isKaffe() {
  272. return kaffeDetected;
  273. }
  274. /**
  275. * Checks whether the current Java VM is GNU Classpath
  276. * @since Ant 1.9.1
  277. * @return true if the version of Java is GNU Classpath
  278. */
  279. public static boolean isClasspathBased() {
  280. return classpathDetected;
  281. }
  282. /**
  283. * Checks whether the current Java VM is the GNU interpreter gij
  284. * or we are running in a gcj precompiled binary.
  285. * @since Ant 1.8.2
  286. * @return true if the current Java VM is gcj/gij.
  287. */
  288. public static boolean isGij() {
  289. return gijDetected;
  290. }
  291. /**
  292. * Checks whether the current VM is Apache Harmony.
  293. * @since Ant 1.8.2
  294. * @return true if the current VM is Apache Harmony.
  295. */
  296. public static boolean isApacheHarmony() {
  297. return harmonyDetected;
  298. }
  299. /**
  300. * Finds an executable that is part of a JRE installation based on
  301. * the java.home system property.
  302. *
  303. * <p><code>java</code>, <code>keytool</code>,
  304. * <code>policytool</code>, <code>orbd</code>, <code>rmid</code>,
  305. * <code>rmiregistry</code>, <code>servertool</code> and
  306. * <code>tnameserv</code> are JRE executables on Sun based
  307. * JRE's.</p>
  308. *
  309. * <p>You typically find them in <code>JAVA_HOME/jre/bin</code> if
  310. * <code>JAVA_HOME</code> points to your JDK installation. JDK
  311. * &lt; 1.2 has them in the same directory as the JDK
  312. * executables.</p>
  313. * @param command the java executable to find.
  314. * @return the path to the command.
  315. * @since Ant 1.5
  316. */
  317. public static String getJreExecutable(String command) {
  318. if (IS_NETWARE) {
  319. // Extrapolating from:
  320. // "NetWare may have a "java" in that directory, but 99% of
  321. // the time, you don't want to execute it" -- Jeff Tulley
  322. // <JTULLEY@novell.com>
  323. return command;
  324. }
  325. File jExecutable = null;
  326. if (IS_AIX) {
  327. // On IBM's JDK 1.2 the directory layout is different, 1.3 follows
  328. // Sun's layout.
  329. jExecutable = findInDir(JAVA_HOME + "/sh", command);
  330. }
  331. if (jExecutable == null) {
  332. jExecutable = findInDir(JAVA_HOME + "/bin", command);
  333. }
  334. if (jExecutable != null) {
  335. return jExecutable.getAbsolutePath();
  336. } else {
  337. // Unfortunately on Windows java.home doesn't always refer
  338. // to the correct location, so we need to fall back to
  339. // assuming java is somewhere on the PATH.
  340. return addExtension(command);
  341. }
  342. }
  343. /**
  344. * Finds an executable that is part of a JDK installation based on
  345. * the java.home system property.
  346. *
  347. * <p>You typically find them in <code>JAVA_HOME/bin</code> if
  348. * <code>JAVA_HOME</code> points to your JDK installation.</p>
  349. * @param command the java executable to find.
  350. * @return the path to the command.
  351. * @since Ant 1.5
  352. */
  353. public static String getJdkExecutable(String command) {
  354. if (IS_NETWARE) {
  355. // Extrapolating from:
  356. // "NetWare may have a "java" in that directory, but 99% of
  357. // the time, you don't want to execute it" -- Jeff Tulley
  358. // <JTULLEY@novell.com>
  359. return command;
  360. }
  361. File jExecutable = null;
  362. if (IS_AIX) {
  363. // On IBM's JDK 1.2 the directory layout is different, 1.3 follows
  364. // Sun's layout.
  365. jExecutable = findInDir(JAVA_HOME + "/../sh", command);
  366. }
  367. if (jExecutable == null) {
  368. jExecutable = findInDir(JAVA_HOME + "/../bin", command);
  369. }
  370. if (jExecutable != null) {
  371. return jExecutable.getAbsolutePath();
  372. } else {
  373. // fall back to JRE bin directory, also catches JDK 1.0 and 1.1
  374. // where java.home points to the root of the JDK and Mac OS X where
  375. // the whole directory layout is different from Sun's
  376. // and also catches JDK 9 (and probably later) which
  377. // merged JDK and JRE dirs
  378. return getJreExecutable(command);
  379. }
  380. }
  381. /**
  382. * Adds a system specific extension to the name of an executable.
  383. *
  384. * @since Ant 1.5
  385. */
  386. private static String addExtension(String command) {
  387. // This is the most common extension case - exe for windows and OS/2,
  388. // nothing for *nix.
  389. return command + (IS_DOS ? ".exe" : "");
  390. }
  391. /**
  392. * Look for an executable in a given directory.
  393. *
  394. * @return null if the executable cannot be found.
  395. */
  396. private static File findInDir(String dirName, String commandName) {
  397. File dir = FILE_UTILS.normalize(dirName);
  398. File executable = null;
  399. if (dir.exists()) {
  400. executable = new File(dir, addExtension(commandName));
  401. if (!executable.exists()) {
  402. executable = null;
  403. }
  404. }
  405. return executable;
  406. }
  407. /**
  408. * demand creation of the package list.
  409. * When you add a new package, add a new test below.
  410. */
  411. private static void buildJrePackages() {
  412. jrePackages = new Vector<String>();
  413. if (isAtLeastJavaVersion(JAVA_1_1)) {
  414. //things like sun.reflection, sun.misc, sun.net
  415. jrePackages.addElement("sun");
  416. jrePackages.addElement("java");
  417. jrePackages.addElement("javax");
  418. }
  419. if (isAtLeastJavaVersion(JAVA_1_2)) {
  420. jrePackages.addElement("com.sun.java");
  421. jrePackages.addElement("com.sun.image");
  422. // are there any here that we forgot?
  423. }
  424. if (isAtLeastJavaVersion(JAVA_1_3)) {
  425. jrePackages.addElement("org.omg");
  426. jrePackages.addElement("com.sun.corba");
  427. jrePackages.addElement("com.sun.jndi");
  428. jrePackages.addElement("com.sun.media");
  429. jrePackages.addElement("com.sun.naming");
  430. jrePackages.addElement("com.sun.org.omg");
  431. jrePackages.addElement("com.sun.rmi");
  432. jrePackages.addElement("sunw.io");
  433. jrePackages.addElement("sunw.util");
  434. }
  435. if (isAtLeastJavaVersion(JAVA_1_4)) {
  436. if (javaVersionNumber == VERSION_1_4) {
  437. jrePackages.addElement("org.apache.crimson");
  438. jrePackages.addElement("org.apache.xalan");
  439. jrePackages.addElement("org.apache.xml");
  440. jrePackages.addElement("org.apache.xpath");
  441. }
  442. jrePackages.addElement("org.ietf.jgss");
  443. jrePackages.addElement("org.w3c.dom");
  444. jrePackages.addElement("org.xml.sax");
  445. }
  446. if (isAtLeastJavaVersion(JAVA_1_5)) {
  447. //In Java1.5, the apache stuff moved.
  448. jrePackages.addElement("com.sun.org.apache");
  449. }
  450. if (isAtLeastJavaVersion(JAVA_1_7)) {
  451. jrePackages.addElement("jdk");
  452. }
  453. }
  454. /**
  455. * Testing helper method; kept here for unification of changes.
  456. * @return a list of test classes depending on the java version.
  457. */
  458. public static Vector<String> getJrePackageTestCases() {
  459. Vector<String> tests = new Vector<String>();
  460. tests.addElement("java.lang.Object");
  461. if (isAtLeastJavaVersion(JAVA_1_1)) {
  462. //things like sun.reflection, sun.misc, sun.net
  463. tests.addElement("sun.reflect.SerializationConstructorAccessorImpl");
  464. tests.addElement("sun.net.www.http.HttpClient");
  465. tests.addElement("sun.audio.AudioPlayer");
  466. }
  467. if (isAtLeastJavaVersion(JAVA_1_2)) {
  468. tests.addElement("javax.accessibility.Accessible");
  469. tests.addElement("sun.misc.BASE64Encoder");
  470. tests.addElement("com.sun.image.codec.jpeg.JPEGCodec");
  471. }
  472. if (isAtLeastJavaVersion(JAVA_1_3)) {
  473. tests.addElement("org.omg.CORBA.Any");
  474. tests.addElement("com.sun.corba.se.internal.corba.AnyImpl");
  475. tests.addElement("com.sun.jndi.ldap.LdapURL");
  476. tests.addElement("com.sun.media.sound.Printer");
  477. tests.addElement("com.sun.naming.internal.VersionHelper");
  478. tests.addElement("com.sun.org.omg.CORBA.Initializer");
  479. tests.addElement("sunw.io.Serializable");
  480. tests.addElement("sunw.util.EventListener");
  481. }
  482. if (isAtLeastJavaVersion(JAVA_1_4)) {
  483. tests.addElement("sun.audio.AudioPlayer");
  484. if (javaVersionNumber == VERSION_1_4) {
  485. // only for 1.4, not for higher versions
  486. tests.addElement("org.apache.crimson.parser.ContentModel");
  487. tests.addElement("org.apache.xalan.processor.ProcessorImport");
  488. tests.addElement("org.apache.xml.utils.URI");
  489. tests.addElement("org.apache.xpath.XPathFactory");
  490. }
  491. tests.addElement("org.ietf.jgss.Oid");
  492. tests.addElement("org.w3c.dom.Attr");
  493. tests.addElement("org.xml.sax.XMLReader");
  494. }
  495. if (isAtLeastJavaVersion(JAVA_1_5)) {
  496. tests.addElement("com.sun.org.apache.xerces.internal.jaxp.datatype.DatatypeFactoryImpl");
  497. }
  498. if (isAtLeastJavaVersion(JAVA_1_7)) {
  499. tests.addElement("jdk.net.Sockets");
  500. }
  501. return tests;
  502. }
  503. /**
  504. * get a vector of strings of packages built into
  505. * that platforms runtime jar(s)
  506. * @return list of packages.
  507. */
  508. public static Vector<String> getJrePackages() {
  509. if (jrePackages == null) {
  510. buildJrePackages();
  511. }
  512. return jrePackages;
  513. }
  514. /**
  515. * Writes the command into a temporary DCL script and returns the
  516. * corresponding File object.
  517. * It is the job of the caller to delete the file on exit.
  518. * @param cmds the command.
  519. * @return the file containing the command.
  520. * @throws IOException if there is an error writing to the file.
  521. */
  522. public static File createVmsJavaOptionFile(String[] cmds)
  523. throws IOException {
  524. File script = FILE_UTILS.createTempFile("ANT", ".JAVA_OPTS", null, false, true);
  525. BufferedWriter out = null;
  526. try {
  527. out = new BufferedWriter(new FileWriter(script));
  528. for (int i = 0; i < cmds.length; i++) {
  529. out.write(cmds[i]);
  530. out.newLine();
  531. }
  532. } finally {
  533. FileUtils.close(out);
  534. }
  535. return script;
  536. }
  537. /**
  538. * Return the value of ${java.home}
  539. * @return the java home value.
  540. */
  541. public static String getJavaHome() {
  542. return JAVA_HOME;
  543. }
  544. }