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