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 23 kB

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