1. /*
  2. * Copyright 2002-2004 The Apache Software Foundation
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. *
  16. */
  17. package org.apache.tools.ant;
  18. import org.apache.tools.ant.util.LoaderUtils;
  19. import javax.xml.parsers.SAXParserFactory;
  20. import javax.xml.parsers.SAXParser;
  21. import java.io.File;
  22. import java.io.FilenameFilter;
  23. import java.io.PrintStream;
  24. import java.io.InputStream;
  25. import java.io.IOException;
  26. import java.util.Enumeration;
  27. import java.util.Properties;
  28. import java.lang.reflect.Method;
  29. import java.lang.reflect.InvocationTargetException;
  30. /**
  31. * A little diagnostic helper that output some information that may help
  32. * in support. It should quickly give correct information about the
  33. * jar existing in ant.home/lib and the jar versions...
  34. *
  35. * @since Ant 1.5
  36. */
  37. public final class Diagnostics {
  38. private static final String TEST_CLASS
  39. = "org.apache.tools.ant.taskdefs.optional.Test";
  40. /** utility class */
  41. private Diagnostics() {
  42. }
  43. /**
  44. * Check if optional tasks are available. Not that it does not check
  45. * for implementation version. Use <tt>validateVersion()</tt> for this.
  46. * @return <tt>true</tt> if optional tasks are available.
  47. */
  48. public static boolean isOptionalAvailable() {
  49. try {
  50. Class.forName(TEST_CLASS);
  51. } catch (ClassNotFoundException e) {
  52. return false;
  53. }
  54. return true;
  55. }
  56. /**
  57. * Check if core and optional implementation version do match.
  58. * @throws BuildException if the implementation version of optional tasks
  59. * does not match the core implementation version.
  60. */
  61. public static void validateVersion() throws BuildException {
  62. try {
  63. Class optional
  64. = Class.forName("org.apache.tools.ant.taskdefs.optional.Test");
  65. String coreVersion = getImplementationVersion(Main.class);
  66. String optionalVersion = getImplementationVersion(optional);
  67. if (coreVersion != null && !coreVersion.equals(optionalVersion)) {
  68. throw new BuildException("Invalid implementation version "
  69. + "between Ant core and Ant optional tasks.\n"
  70. + " core : " + coreVersion + "\n"
  71. + " optional: " + optionalVersion);
  72. }
  73. } catch (ClassNotFoundException e) {
  74. // ignore
  75. }
  76. }
  77. /**
  78. * return the list of jar files existing in ANT_HOME/lib
  79. * and that must have been picked up by Ant script.
  80. * @return the list of jar files existing in ant.home/lib or
  81. * <tt>null</tt> if an error occurs.
  82. */
  83. public static File[] listLibraries() {
  84. String home = System.getProperty("ant.home");
  85. if (home == null) {
  86. return null;
  87. }
  88. File libDir = new File(home, "lib");
  89. FilenameFilter filter = new FilenameFilter() {
  90. public boolean accept(File dir, String name) {
  91. return name.endsWith(".jar");
  92. }
  93. };
  94. // listFiles is JDK 1.2+ method...
  95. String[] filenames = libDir.list(filter);
  96. if (filenames == null) {
  97. return null;
  98. }
  99. File[] files = new File[filenames.length];
  100. for (int i = 0; i < filenames.length; i++) {
  101. files[i] = new File(libDir, filenames[i]);
  102. }
  103. return files;
  104. }
  105. /**
  106. * main entry point for command line
  107. * @param args command line arguments.
  108. */
  109. public static void main(String[] args) {
  110. doReport(System.out);
  111. }
  112. /**
  113. * Helper method to get the implementation version.
  114. * @param clazz the class to get the information from.
  115. * @return null if there is no package or implementation version.
  116. * '?.?' for JDK 1.0 or 1.1.
  117. */
  118. private static String getImplementationVersion(Class clazz) {
  119. try {
  120. // Package pkg = clazz.getPackage();
  121. Method method = Class.class.getMethod("getPackage", new Class[0]);
  122. Object pkg = method.invoke(clazz, null);
  123. if (pkg != null) {
  124. // pkg.getImplementationVersion();
  125. method = pkg.getClass().getMethod("getImplementationVersion", new Class[0]);
  126. Object version = method.invoke(pkg, null);
  127. return (String) version;
  128. }
  129. } catch (Exception e) {
  130. // JDK < 1.2 should land here because the methods above don't exist.
  131. return "?.?";
  132. }
  133. return null;
  134. }
  135. /**
  136. * what parser are we using.
  137. * @return the classname of the parser
  138. */
  139. private static String getXmlParserName() {
  140. SAXParser saxParser = getSAXParser();
  141. if (saxParser == null) {
  142. return "Could not create an XML Parser";
  143. }
  144. // check to what is in the classname
  145. String saxParserName = saxParser.getClass().getName();
  146. return saxParserName;
  147. }
  148. /**
  149. * Create a JAXP SAXParser
  150. * @return parser or null for trouble
  151. */
  152. private static SAXParser getSAXParser() {
  153. SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();
  154. if (saxParserFactory == null) {
  155. return null;
  156. }
  157. SAXParser saxParser = null;
  158. try {
  159. saxParser = saxParserFactory.newSAXParser();
  160. } catch (Exception e) {
  161. // ignore
  162. }
  163. return saxParser;
  164. }
  165. /**
  166. * get the location of the parser
  167. * @return path or null for trouble in tracking it down
  168. */
  169. private static String getXMLParserLocation() {
  170. SAXParser saxParser = getSAXParser();
  171. if (saxParser == null) {
  172. return null;
  173. }
  174. String location = getClassLocation(saxParser.getClass());
  175. return location;
  176. }
  177. /**
  178. * get the location of a class. Stolen from axis/webapps/happyaxis.jsp
  179. * @param clazz
  180. * @return the jar file or path where a class was found, or null
  181. */
  182. private static String getClassLocation(Class clazz) {
  183. File f = LoaderUtils.getClassSource(clazz);
  184. return f == null ? null : f.getAbsolutePath();
  185. }
  186. /**
  187. * Print a report to the given stream.
  188. * @param out the stream to print the report to.
  189. */
  190. public static void doReport(PrintStream out) {
  191. out.println("------- Ant diagnostics report -------");
  192. out.println(Main.getAntVersion());
  193. out.println();
  194. out.println("-------------------------------------------");
  195. out.println(" Implementation Version (JDK1.2+ only)");
  196. out.println("-------------------------------------------");
  197. out.println("core tasks : " + getImplementationVersion(Main.class));
  198. Class optional = null;
  199. try {
  200. optional = Class.forName(
  201. "org.apache.tools.ant.taskdefs.optional.Test");
  202. out.println("optional tasks : "
  203. + getImplementationVersion(optional));
  204. } catch (ClassNotFoundException e) {
  205. out.println("optional tasks : not available");
  206. }
  207. out.println();
  208. out.println("-------------------------------------------");
  209. out.println(" ANT_HOME/lib jar listing");
  210. out.println("-------------------------------------------");
  211. doReportLibraries(out);
  212. out.println();
  213. out.println("-------------------------------------------");
  214. out.println(" Tasks availability");
  215. out.println("-------------------------------------------");
  216. doReportTasksAvailability(out);
  217. out.println();
  218. out.println("-------------------------------------------");
  219. out.println(" org.apache.env.Which diagnostics");
  220. out.println("-------------------------------------------");
  221. doReportWhich(out);
  222. out.println();
  223. out.println("-------------------------------------------");
  224. out.println(" XML Parser information");
  225. out.println("-------------------------------------------");
  226. doReportParserInfo(out);
  227. out.println();
  228. out.println("-------------------------------------------");
  229. out.println(" System properties");
  230. out.println("-------------------------------------------");
  231. doReportSystemProperties(out);
  232. out.println();
  233. }
  234. /**
  235. * Report a listing of system properties existing in the current vm.
  236. * @param out the stream to print the properties to.
  237. */
  238. private static void doReportSystemProperties(PrintStream out) {
  239. for (Enumeration keys = System.getProperties().keys();
  240. keys.hasMoreElements();) {
  241. String key = (String) keys.nextElement();
  242. out.println(key + " : " + System.getProperty(key));
  243. }
  244. }
  245. /**
  246. * Report the content of ANT_HOME/lib directory
  247. * @param out the stream to print the content to
  248. */
  249. private static void doReportLibraries(PrintStream out) {
  250. out.println("ant.home: " + System.getProperty("ant.home"));
  251. File[] libs = listLibraries();
  252. if (libs == null) {
  253. out.println("Unable to list libraries.");
  254. return;
  255. }
  256. for (int i = 0; i < libs.length; i++) {
  257. out.println(libs[i].getName()
  258. + " (" + libs[i].length() + " bytes)");
  259. }
  260. }
  261. /**
  262. * Call org.apache.env.Which if available
  263. * @param out the stream to print the content to.
  264. */
  265. private static void doReportWhich(PrintStream out) {
  266. Throwable error = null;
  267. try {
  268. Class which = Class.forName("org.apache.env.Which");
  269. Method method
  270. = which.getMethod("main", new Class[]{String[].class});
  271. method.invoke(null, new Object[]{new String[]{}});
  272. } catch (ClassNotFoundException e) {
  273. out.println("Not available.");
  274. out.println("Download it at http://xml.apache.org/commons/");
  275. } catch (InvocationTargetException e) {
  276. error = e.getTargetException() == null ? e : e.getTargetException();
  277. } catch (Throwable e) {
  278. error = e;
  279. }
  280. // report error if something weird happens...this is diagnostic.
  281. if (error != null) {
  282. out.println("Error while running org.apache.env.Which");
  283. error.printStackTrace();
  284. }
  285. }
  286. /**
  287. * Create a report about non-available tasks that are defined in the
  288. * mapping but could not be found via lookup. It might generally happen
  289. * because Ant requires multiple libraries to compile and one of them
  290. * was missing when compiling Ant.
  291. * @param out the stream to print the tasks report to
  292. * <tt>null</tt> for a missing stream (ie mapping).
  293. */
  294. private static void doReportTasksAvailability(PrintStream out) {
  295. InputStream is = Main.class.getResourceAsStream(
  296. "/org/apache/tools/ant/taskdefs/defaults.properties");
  297. if (is == null) {
  298. out.println("None available");
  299. } else {
  300. Properties props = new Properties();
  301. try {
  302. props.load(is);
  303. for (Enumeration keys = props.keys(); keys.hasMoreElements();) {
  304. String key = (String) keys.nextElement();
  305. String classname = props.getProperty(key);
  306. try {
  307. Class.forName(classname);
  308. props.remove(key);
  309. } catch (ClassNotFoundException e) {
  310. out.println(key + " : Not Available");
  311. } catch (NoClassDefFoundError e) {
  312. String pkg = e.getMessage().replace('/', '.');
  313. out.println(key + " : Missing dependency " + pkg);
  314. } catch (Error e) {
  315. out.println(key + " : Initialization error");
  316. }
  317. }
  318. if (props.size() == 0) {
  319. out.println("All defined tasks are available");
  320. }
  321. } catch (IOException e) {
  322. out.println(e.getMessage());
  323. }
  324. }
  325. }
  326. /**
  327. * tell the user about the XML parser
  328. * @param out
  329. */
  330. private static void doReportParserInfo(PrintStream out) {
  331. String parserName = getXmlParserName();
  332. String parserLocation = getXMLParserLocation();
  333. if (parserName == null) {
  334. parserName = "unknown";
  335. }
  336. if (parserLocation == null) {
  337. parserLocation = "unknown";
  338. }
  339. out.println("XML Parser : " + parserName);
  340. out.println("XML Parser Location: " + parserLocation);
  341. }
  342. }