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.

Diagnostics.java 22 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633
  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;
  19. import org.apache.tools.ant.util.LoaderUtils;
  20. import org.apache.tools.ant.util.FileUtils;
  21. import org.apache.tools.ant.util.JAXPUtils;
  22. import org.apache.tools.ant.util.ProxySetup;
  23. import org.apache.tools.ant.util.JavaEnvUtils;
  24. import org.apache.tools.ant.launch.Launcher;
  25. import org.xml.sax.XMLReader;
  26. import javax.xml.parsers.SAXParserFactory;
  27. import javax.xml.parsers.SAXParser;
  28. import java.io.File;
  29. import java.io.FilenameFilter;
  30. import java.io.PrintStream;
  31. import java.io.InputStream;
  32. import java.io.IOException;
  33. import java.io.FileOutputStream;
  34. import java.util.Enumeration;
  35. import java.util.Properties;
  36. import java.util.Calendar;
  37. import java.util.TimeZone;
  38. import java.lang.reflect.Method;
  39. import java.lang.reflect.InvocationTargetException;
  40. /**
  41. * A little diagnostic helper that output some information that may help
  42. * in support. It should quickly give correct information about the
  43. * jar existing in ant.home/lib and the jar versions...
  44. *
  45. * @since Ant 1.5
  46. */
  47. public final class Diagnostics {
  48. /**
  49. * value for which a difference between clock and temp file time triggers
  50. * a warning.
  51. * {@value}
  52. */
  53. private static final int BIG_DRIFT_LIMIT = 10000;
  54. /**
  55. * How big a test file to write.
  56. * {@value}
  57. */
  58. private static final int TEST_FILE_SIZE = 32;
  59. private static final int KILOBYTE = 1024;
  60. private static final int SECONDS_PER_MILLISECOND = 1000;
  61. private static final int SECONDS_PER_MINUTE = 60;
  62. private static final int MINUTES_PER_HOUR = 60;
  63. private static final String TEST_CLASS = "org.apache.tools.ant.taskdefs.optional.Test";
  64. /**
  65. * The error text when a security manager blocks access to a property.
  66. * {@value}
  67. */
  68. protected static final String ERROR_PROPERTY_ACCESS_BLOCKED
  69. = "Access to this property blocked by a security manager";
  70. /** utility class */
  71. private Diagnostics() {
  72. // hidden constructor
  73. }
  74. /**
  75. * Check if optional tasks are available. Not that it does not check
  76. * for implementation version. Use <tt>validateVersion()</tt> for this.
  77. * @return <tt>true</tt> if optional tasks are available.
  78. */
  79. public static boolean isOptionalAvailable() {
  80. try {
  81. Class.forName(TEST_CLASS);
  82. } catch (ClassNotFoundException e) {
  83. return false;
  84. }
  85. return true;
  86. }
  87. /**
  88. * Check if core and optional implementation version do match.
  89. * @throws BuildException if the implementation version of optional tasks
  90. * does not match the core implementation version.
  91. */
  92. public static void validateVersion() throws BuildException {
  93. try {
  94. Class optional = Class.forName(TEST_CLASS);
  95. String coreVersion = getImplementationVersion(Main.class);
  96. String optionalVersion = getImplementationVersion(optional);
  97. if (coreVersion != null && !coreVersion.equals(optionalVersion)) {
  98. throw new BuildException("Invalid implementation version "
  99. + "between Ant core and Ant optional tasks.\n" + " core : "
  100. + coreVersion + "\n" + " optional: " + optionalVersion);
  101. }
  102. } catch (ClassNotFoundException e) {
  103. // ignore
  104. ignoreThrowable(e);
  105. }
  106. }
  107. /**
  108. * return the list of jar files existing in ANT_HOME/lib
  109. * and that must have been picked up by Ant script.
  110. * @return the list of jar files existing in ant.home/lib or
  111. * <tt>null</tt> if an error occurs.
  112. */
  113. public static File[] listLibraries() {
  114. String home = System.getProperty(MagicNames.ANT_HOME);
  115. if (home == null) {
  116. return null;
  117. }
  118. File libDir = new File(home, "lib");
  119. return listJarFiles(libDir);
  120. }
  121. /**
  122. * get a list of all JAR files in a directory
  123. * @param libDir directory
  124. * @return array of files (or null for no such directory)
  125. */
  126. private static File[] listJarFiles(File libDir) {
  127. FilenameFilter filter = new FilenameFilter() {
  128. public boolean accept(File dir, String name) {
  129. return name.endsWith(".jar");
  130. }
  131. };
  132. File[] files = libDir.listFiles(filter);
  133. return files;
  134. }
  135. /**
  136. * main entry point for command line
  137. * @param args command line arguments.
  138. */
  139. public static void main(String[] args) {
  140. doReport(System.out);
  141. }
  142. /**
  143. * Helper method to get the implementation version.
  144. * @param clazz the class to get the information from.
  145. * @return null if there is no package or implementation version.
  146. * '?.?' for JDK 1.0 or 1.1.
  147. */
  148. private static String getImplementationVersion(Class clazz) {
  149. return clazz.getPackage().getImplementationVersion();
  150. }
  151. /**
  152. * what parser are we using.
  153. * @return the classname of the parser
  154. */
  155. private static String getXmlParserName() {
  156. SAXParser saxParser = getSAXParser();
  157. if (saxParser == null) {
  158. return "Could not create an XML Parser";
  159. }
  160. // check to what is in the classname
  161. String saxParserName = saxParser.getClass().getName();
  162. return saxParserName;
  163. }
  164. /**
  165. * Create a JAXP SAXParser
  166. * @return parser or null for trouble
  167. */
  168. private static SAXParser getSAXParser() {
  169. SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();
  170. if (saxParserFactory == null) {
  171. return null;
  172. }
  173. SAXParser saxParser = null;
  174. try {
  175. saxParser = saxParserFactory.newSAXParser();
  176. } catch (Exception e) {
  177. // ignore
  178. ignoreThrowable(e);
  179. }
  180. return saxParser;
  181. }
  182. /**
  183. * get the location of the parser
  184. * @return path or null for trouble in tracking it down
  185. */
  186. private static String getXMLParserLocation() {
  187. SAXParser saxParser = getSAXParser();
  188. if (saxParser == null) {
  189. return null;
  190. }
  191. String location = getClassLocation(saxParser.getClass());
  192. return location;
  193. }
  194. private static String getNamespaceParserName() {
  195. try {
  196. XMLReader reader = JAXPUtils.getNamespaceXMLReader();
  197. return reader.getClass().getName();
  198. } catch (BuildException e) {
  199. //ignore
  200. ignoreThrowable(e);
  201. return null;
  202. }
  203. }
  204. private static String getNamespaceParserLocation() {
  205. try {
  206. XMLReader reader = JAXPUtils.getNamespaceXMLReader();
  207. return getClassLocation(reader.getClass());
  208. } catch (BuildException e) {
  209. //ignore
  210. ignoreThrowable(e);
  211. return null;
  212. }
  213. }
  214. /**
  215. * ignore exceptions. This is to allow future
  216. * implementations to log at a verbose level
  217. * @param thrown
  218. */
  219. private static void ignoreThrowable(Throwable thrown) {
  220. }
  221. /**
  222. * get the location of a class. Stolen from axis/webapps/happyaxis.jsp
  223. * @param clazz
  224. * @return the jar file or path where a class was found, or null
  225. */
  226. private static String getClassLocation(Class clazz) {
  227. File f = LoaderUtils.getClassSource(clazz);
  228. return f == null ? null : f.getAbsolutePath();
  229. }
  230. /**
  231. * Print a report to the given stream.
  232. * @param out the stream to print the report to.
  233. */
  234. public static void doReport(PrintStream out) {
  235. out.println("------- Ant diagnostics report -------");
  236. out.println(Main.getAntVersion());
  237. header(out, "Implementation Version");
  238. out.println("core tasks : " + getImplementationVersion(Main.class));
  239. Class optional = null;
  240. try {
  241. optional = Class.forName(TEST_CLASS);
  242. out.println("optional tasks : " + getImplementationVersion(optional));
  243. } catch (ClassNotFoundException e) {
  244. ignoreThrowable(e);
  245. out.println("optional tasks : not available");
  246. }
  247. header(out, "ANT PROPERTIES");
  248. doReportAntProperties(out);
  249. header(out, "ANT_HOME/lib jar listing");
  250. doReportAntHomeLibraries(out);
  251. header(out, "USER_HOME/.ant/lib jar listing");
  252. doReportUserHomeLibraries(out);
  253. header(out, "Tasks availability");
  254. doReportTasksAvailability(out);
  255. header(out, "org.apache.env.Which diagnostics");
  256. doReportWhich(out);
  257. header(out, "XML Parser information");
  258. doReportParserInfo(out);
  259. header(out, "System properties");
  260. doReportSystemProperties(out);
  261. header(out, "Temp dir");
  262. doReportTempDir(out);
  263. header(out, "Locale information");
  264. doReportLocale(out);
  265. header(out, "Proxy information");
  266. doReportProxy(out);
  267. out.println();
  268. }
  269. private static void header(PrintStream out, String section) {
  270. out.println();
  271. out.println("-------------------------------------------");
  272. out.print(" ");
  273. out.println(section);
  274. out.println("-------------------------------------------");
  275. }
  276. /**
  277. * Report a listing of system properties existing in the current vm.
  278. * @param out the stream to print the properties to.
  279. */
  280. private static void doReportSystemProperties(PrintStream out) {
  281. Properties sysprops = null;
  282. try {
  283. sysprops = System.getProperties();
  284. } catch (SecurityException e) {
  285. ignoreThrowable(e);
  286. out.println("Access to System.getProperties() blocked " + "by a security manager");
  287. }
  288. for (Enumeration keys = sysprops.propertyNames();
  289. keys.hasMoreElements();) {
  290. String key = (String) keys.nextElement();
  291. String value = getProperty(key);
  292. out.println(key + " : " + value);
  293. }
  294. }
  295. /**
  296. * Get the value of a system property. If a security manager
  297. * blocks access to a property it fills the result in with an error
  298. * @param key
  299. * @return the system property's value or error text
  300. * @see #ERROR_PROPERTY_ACCESS_BLOCKED
  301. */
  302. private static String getProperty(String key) {
  303. String value;
  304. try {
  305. value = System.getProperty(key);
  306. } catch (SecurityException e) {
  307. value = ERROR_PROPERTY_ACCESS_BLOCKED;
  308. }
  309. return value;
  310. }
  311. /**
  312. * Report the content of ANT_HOME/lib directory
  313. * @param out the stream to print the content to
  314. */
  315. private static void doReportAntProperties(PrintStream out) {
  316. Project p = new Project();
  317. p.initProperties();
  318. out.println(MagicNames.ANT_VERSION + ": " + p.getProperty(MagicNames.ANT_VERSION));
  319. out.println(MagicNames.ANT_JAVA_VERSION + ": "
  320. + p.getProperty(MagicNames.ANT_JAVA_VERSION));
  321. out.println(MagicNames.ANT_LIB + ": " + p.getProperty(MagicNames.ANT_LIB));
  322. out.println(MagicNames.ANT_HOME + ": " + p.getProperty(MagicNames.ANT_HOME));
  323. }
  324. /**
  325. * Report the content of ANT_HOME/lib directory
  326. * @param out the stream to print the content to
  327. */
  328. private static void doReportAntHomeLibraries(PrintStream out) {
  329. out.println(MagicNames.ANT_HOME + ": " + System.getProperty(MagicNames.ANT_HOME));
  330. File[] libs = listLibraries();
  331. printLibraries(libs, out);
  332. }
  333. /**
  334. * Report the content of ~/.ant/lib directory
  335. *
  336. * @param out the stream to print the content to
  337. */
  338. private static void doReportUserHomeLibraries(PrintStream out) {
  339. String home = System.getProperty(Launcher.USER_HOMEDIR);
  340. out.println("user.home: " + home);
  341. File libDir = new File(home, Launcher.USER_LIBDIR);
  342. File[] libs = listJarFiles(libDir);
  343. printLibraries(libs, out);
  344. }
  345. /**
  346. * list the libraries
  347. * @param libs array of libraries (can be null)
  348. * @param out output stream
  349. */
  350. private static void printLibraries(File[] libs, PrintStream out) {
  351. if (libs == null) {
  352. out.println("No such directory.");
  353. return;
  354. }
  355. for (int i = 0; i < libs.length; i++) {
  356. out.println(libs[i].getName() + " (" + libs[i].length() + " bytes)");
  357. }
  358. }
  359. /**
  360. * Call org.apache.env.Which if available
  361. * @param out the stream to print the content to.
  362. */
  363. private static void doReportWhich(PrintStream out) {
  364. Throwable error = null;
  365. try {
  366. Class which = Class.forName("org.apache.env.Which");
  367. Method method = which.getMethod("main", new Class[] { String[].class });
  368. method.invoke(null, new Object[]{new String[]{}});
  369. } catch (ClassNotFoundException e) {
  370. out.println("Not available.");
  371. out.println("Download it at http://xml.apache.org/commons/");
  372. } catch (InvocationTargetException e) {
  373. error = e.getTargetException() == null ? e : e.getTargetException();
  374. } catch (Throwable e) {
  375. error = e;
  376. }
  377. // report error if something weird happens...this is diagnostic.
  378. if (error != null) {
  379. out.println("Error while running org.apache.env.Which");
  380. error.printStackTrace();
  381. }
  382. }
  383. /**
  384. * Create a report about non-available tasks that are defined in the
  385. * mapping but could not be found via lookup. It might generally happen
  386. * because Ant requires multiple libraries to compile and one of them
  387. * was missing when compiling Ant.
  388. * @param out the stream to print the tasks report to
  389. * <tt>null</tt> for a missing stream (ie mapping).
  390. */
  391. private static void doReportTasksAvailability(PrintStream out) {
  392. InputStream is = Main.class.getResourceAsStream(
  393. MagicNames.TASKDEF_PROPERTIES_RESOURCE);
  394. if (is == null) {
  395. out.println("None available");
  396. } else {
  397. Properties props = new Properties();
  398. try {
  399. props.load(is);
  400. for (Enumeration keys = props.keys(); keys.hasMoreElements();) {
  401. String key = (String) keys.nextElement();
  402. String classname = props.getProperty(key);
  403. try {
  404. Class.forName(classname);
  405. props.remove(key);
  406. } catch (ClassNotFoundException e) {
  407. out.println(key + " : Not Available "
  408. + "(the implementation class is not present)");
  409. } catch (NoClassDefFoundError e) {
  410. String pkg = e.getMessage().replace('/', '.');
  411. out.println(key + " : Missing dependency " + pkg);
  412. } catch (LinkageError e) {
  413. out.println(key + " : Initialization error");
  414. }
  415. }
  416. if (props.size() == 0) {
  417. out.println("All defined tasks are available");
  418. } else {
  419. out.println("A task being missing/unavailable should only "
  420. + "matter if you are trying to use it");
  421. }
  422. } catch (IOException e) {
  423. out.println(e.getMessage());
  424. }
  425. }
  426. }
  427. /**
  428. * tell the user about the XML parser
  429. * @param out
  430. */
  431. private static void doReportParserInfo(PrintStream out) {
  432. String parserName = getXmlParserName();
  433. String parserLocation = getXMLParserLocation();
  434. printParserInfo(out, "XML Parser", parserName, parserLocation);
  435. printParserInfo(out, "Namespace-aware parser", getNamespaceParserName(),
  436. getNamespaceParserLocation());
  437. }
  438. private static void printParserInfo(PrintStream out, String parserType, String parserName,
  439. String parserLocation) {
  440. if (parserName == null) {
  441. parserName = "unknown";
  442. }
  443. if (parserLocation == null) {
  444. parserLocation = "unknown";
  445. }
  446. out.println(parserType + " : " + parserName);
  447. out.println(parserType + " Location: " + parserLocation);
  448. }
  449. /**
  450. * try and create a temp file in our temp dir; this
  451. * checks that it has space and access.
  452. * We also do some clock reporting.
  453. * @param out
  454. */
  455. private static void doReportTempDir(PrintStream out) {
  456. String tempdir = System.getProperty("java.io.tmpdir");
  457. if (tempdir == null) {
  458. out.println("Warning: java.io.tmpdir is undefined");
  459. return;
  460. }
  461. out.println("Temp dir is " + tempdir);
  462. File tempDirectory = new File(tempdir);
  463. if (!tempDirectory.exists()) {
  464. out.println("Warning, java.io.tmpdir directory does not exist: " + tempdir);
  465. return;
  466. }
  467. //create the file
  468. long now = System.currentTimeMillis();
  469. File tempFile = null;
  470. FileOutputStream fileout = null;
  471. try {
  472. tempFile = File.createTempFile("diag", "txt", tempDirectory);
  473. //do some writing to it
  474. fileout = new FileOutputStream(tempFile);
  475. byte[] buffer = new byte[KILOBYTE];
  476. for (int i = 0; i < TEST_FILE_SIZE; i++) {
  477. fileout.write(buffer);
  478. }
  479. fileout.close();
  480. fileout = null;
  481. long filetime = tempFile.lastModified();
  482. tempFile.delete();
  483. out.println("Temp dir is writeable");
  484. long drift = filetime - now;
  485. out.println("Temp dir alignment with system clock is " + drift + " ms");
  486. if (Math.abs(drift) > BIG_DRIFT_LIMIT) {
  487. out.println("Warning: big clock drift -maybe a network filesystem");
  488. }
  489. } catch (IOException e) {
  490. ignoreThrowable(e);
  491. out.println("Failed to create a temporary file in the temp dir " + tempdir);
  492. out.println("File " + tempFile + " could not be created/written to");
  493. } finally {
  494. FileUtils.close(fileout);
  495. if (tempFile != null && tempFile.exists()) {
  496. tempFile.delete();
  497. }
  498. }
  499. }
  500. /**
  501. * Report locale information
  502. * @param out stream to print to
  503. */
  504. private static void doReportLocale(PrintStream out) {
  505. //calendar stuff.
  506. Calendar cal = Calendar.getInstance();
  507. TimeZone tz = cal.getTimeZone();
  508. out.println("Timezone "
  509. + tz.getDisplayName()
  510. + " offset="
  511. + tz.getOffset(cal.get(Calendar.ERA), cal.get(Calendar.YEAR), cal
  512. .get(Calendar.MONTH), cal.get(Calendar.DAY_OF_MONTH), cal
  513. .get(Calendar.DAY_OF_WEEK), ((cal.get(Calendar.HOUR_OF_DAY)
  514. * MINUTES_PER_HOUR + cal.get(Calendar.MINUTE))
  515. * SECONDS_PER_MINUTE + cal.get(Calendar.SECOND))
  516. * SECONDS_PER_MILLISECOND + cal.get(Calendar.MILLISECOND)));
  517. }
  518. /**
  519. * print a property name="value" pair if the property is set;
  520. * print nothing if it is null
  521. * @param out stream to print on
  522. * @param key property name
  523. */
  524. private static void printProperty(PrintStream out, String key) {
  525. String value = getProperty(key);
  526. if (value != null) {
  527. out.print(key);
  528. out.print(" = ");
  529. out.print('"');
  530. out.print(value);
  531. out.println('"');
  532. }
  533. }
  534. /**
  535. * Report proxy information
  536. *
  537. * @param out stream to print to
  538. * @since Ant1.7
  539. */
  540. private static void doReportProxy(PrintStream out) {
  541. printProperty(out, ProxySetup.HTTP_PROXY_HOST);
  542. printProperty(out, ProxySetup.HTTP_PROXY_PORT);
  543. printProperty(out, ProxySetup.HTTP_PROXY_USERNAME);
  544. printProperty(out, ProxySetup.HTTP_PROXY_PASSWORD);
  545. printProperty(out, ProxySetup.HTTP_NON_PROXY_HOSTS);
  546. printProperty(out, ProxySetup.HTTPS_PROXY_HOST);
  547. printProperty(out, ProxySetup.HTTPS_PROXY_PORT);
  548. printProperty(out, ProxySetup.HTTPS_NON_PROXY_HOSTS);
  549. printProperty(out, ProxySetup.FTP_PROXY_HOST);
  550. printProperty(out, ProxySetup.FTP_PROXY_PORT);
  551. printProperty(out, ProxySetup.FTP_NON_PROXY_HOSTS);
  552. printProperty(out, ProxySetup.SOCKS_PROXY_HOST);
  553. printProperty(out, ProxySetup.SOCKS_PROXY_PORT);
  554. printProperty(out, ProxySetup.SOCKS_PROXY_USERNAME);
  555. printProperty(out, ProxySetup.SOCKS_PROXY_PASSWORD);
  556. if (JavaEnvUtils.getJavaVersionNumber() < 15) {
  557. return;
  558. }
  559. printProperty(out, ProxySetup.USE_SYSTEM_PROXIES);
  560. final String proxyDiagClassname = "org.apache.tools.ant.util.java15.ProxyDiagnostics";
  561. try {
  562. Class proxyDiagClass = Class.forName(proxyDiagClassname);
  563. Object instance = proxyDiagClass.newInstance();
  564. out.println("Java1.5+ proxy settings:");
  565. out.println(instance.toString());
  566. } catch (ClassNotFoundException e) {
  567. //not included, do nothing
  568. } catch (IllegalAccessException e) {
  569. //not included, do nothing
  570. } catch (InstantiationException e) {
  571. //not included, do nothing
  572. } catch (NoClassDefFoundError e) {
  573. // not included, to nothing
  574. }
  575. }
  576. }