1. /*
  2. * The Apache Software License, Version 1.1
  3. *
  4. *
  5. * Copyright (c) 2001-2002 The Apache Software Foundation. All rights
  6. * reserved.
  7. *
  8. * Redistribution and use in source and binary forms, with or without
  9. * modification, are permitted provided that the following conditions
  10. * are met:
  11. *
  12. * 1. Redistributions of source code must retain the above copyright
  13. * notice, this list of conditions and the following disclaimer.
  14. *
  15. * 2. Redistributions in binary form must reproduce the above copyright
  16. * notice, this list of conditions and the following disclaimer in
  17. * the documentation and/or other materials provided with the
  18. * distribution.
  19. *
  20. * 3. The end-user documentation included with the redistribution,
  21. * if any, must include the following acknowledgment:
  22. * "This product includes software developed by the
  23. * Apache Software Foundation (http://www.apache.org/)."
  24. * Alternately, this acknowledgment may appear in the software itself,
  25. * if and wherever such third-party acknowledgments normally appear.
  26. *
  27. * 4. The names "Xalan" and "Apache Software Foundation" must
  28. * not be used to endorse or promote products derived from this
  29. * software without prior written permission. For written
  30. * permission, please contact apache@apache.org.
  31. *
  32. * 5. Products derived from this software may not be called "Apache",
  33. * nor may "Apache" appear in their name, without prior written
  34. * permission of the Apache Software Foundation.
  35. *
  36. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
  37. * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  38. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  39. * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
  40. * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  41. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  42. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  43. * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  44. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  45. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  46. * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  47. * SUCH DAMAGE.
  48. * ====================================================================
  49. *
  50. * This software consists of voluntary contributions made by many
  51. * individuals on behalf of the Apache Software Foundation and was
  52. * originally based on software copyright (c) 1999, Lotus
  53. * Development Corporation., http://www.lotus.com. For more
  54. * information on the Apache Software Foundation, please see
  55. * <http://www.apache.org/>.
  56. */
  57. package org.apache.xalan.xslt;
  58. import java.io.File;
  59. import java.io.FileWriter;
  60. import java.io.PrintWriter;
  61. import java.lang.reflect.Method;
  62. import java.lang.reflect.Field;
  63. import java.util.Enumeration;
  64. import java.util.Hashtable;
  65. import java.util.Properties;
  66. import java.util.StringTokenizer;
  67. import java.util.Vector;
  68. // Used in append* methods only
  69. import org.w3c.dom.Document;
  70. import org.w3c.dom.Element;
  71. import org.w3c.dom.Node;
  72. /**
  73. * Utility class to report simple information about the environment.
  74. * Simplistic reporting about certain classes found in your JVM may
  75. * help answer some FAQs for simple problems.
  76. *
  77. * <p>Usage-command line:
  78. * <code>
  79. * java org.apache.xalan.xslt.EnvironmentCheck [-out outFile]
  80. * </code></p>
  81. *
  82. * <p>Usage-from program:
  83. * <code>
  84. * boolean environmentOK =
  85. * (new EnvironmentCheck()).checkEnvironment(yourPrintWriter);
  86. * </code></p>
  87. *
  88. * <p>Usage-from stylesheet:
  89. * <code><pre>
  90. * <?xml version="1.0"?>
  91. * <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
  92. * xmlns:xalan="http://xml.apache.org/xalan"
  93. * exclude-result-prefixes="xalan">
  94. * <xsl:output indent="yes"/>
  95. * <xsl:template match="/">
  96. * <xsl:copy-of select="xalan:checkEnvironment()"/>
  97. * </xsl:template>
  98. * </xsl:stylesheet>
  99. * </pre></code></p>
  100. *
  101. * <p>Xalan users reporting problems are encouraged to use this class
  102. * to see if there are potential problems with their actual
  103. * Java environment <b>before</b> reporting a bug. Note that you
  104. * should both check from the JVM/JRE's command line as well as
  105. * temporarily calling checkEnvironment() directly from your code,
  106. * since the classpath may differ (especially for servlets, etc).</p>
  107. *
  108. * <p>Also see http://xml.apache.org/xalan-j/faq.html</p>
  109. *
  110. * <p>Note: This class is pretty simplistic: it does a fairly simple
  111. * unordered search of the classpath; it only uses Class.forName()
  112. * to load things, not actually querying the classloader; so the
  113. * results are not necessarily definitive nor will it find all
  114. * problems related to environment setup. Also, you should avoid
  115. * calling this in deployed production code, both because it is
  116. * quite slow and because it forces classes to get loaded.</p>
  117. *
  118. * <p>Note: This class explicitly has very limited compile-time
  119. * dependencies to enable easy compilation and usage even when
  120. * Xalan, DOM/SAX/JAXP, etc. are not present.</p>
  121. *
  122. * <p>Note: for an improved version of this utility, please see
  123. * the xml-commons' project Which utility which does the same kind
  124. * of thing but in a much simpler manner.</p>
  125. *
  126. * @author Shane_Curcuru@us.ibm.com
  127. * @version $Id: EnvironmentCheck.java,v 1.14 2002/10/31 15:06:43 ilene Exp $
  128. */
  129. public class EnvironmentCheck
  130. {
  131. /**
  132. * Command line runnability: checks for [-out outFilename] arg.
  133. * <p>Command line entrypoint; Sets output and calls
  134. * {@link #checkEnvironment(PrintWriter)}.</p>
  135. * @param args command line args
  136. */
  137. public static void main(String[] args)
  138. {
  139. // Default to System.out, autoflushing
  140. PrintWriter sendOutputTo = new PrintWriter(System.out, true);
  141. // Read our simplistic input args, if supplied
  142. for (int i = 0; i < args.length; i++)
  143. {
  144. if ("-out".equalsIgnoreCase(args[i]))
  145. {
  146. i++;
  147. if (i < args.length)
  148. {
  149. try
  150. {
  151. sendOutputTo = new PrintWriter(new FileWriter(args[i], true));
  152. }
  153. catch (Exception e)
  154. {
  155. System.err.println("# WARNING: -out " + args[i] + " threw "
  156. + e.toString());
  157. }
  158. }
  159. else
  160. {
  161. System.err.println(
  162. "# WARNING: -out argument should have a filename, output sent to console");
  163. }
  164. }
  165. }
  166. EnvironmentCheck app = new EnvironmentCheck();
  167. app.checkEnvironment(sendOutputTo);
  168. }
  169. /**
  170. * Programmatic entrypoint: Report on basic Java environment
  171. * and CLASSPATH settings that affect Xalan.
  172. *
  173. * <p>Note that this class is not advanced enough to tell you
  174. * everything about the environment that affects Xalan, and
  175. * sometimes reports errors that will not actually affect
  176. * Xalan's behavior. Currently, it very simplistically
  177. * checks the JVM's environment for some basic properties and
  178. * logs them out; it will report a problem if it finds a setting
  179. * or .jar file that is <i>likely</i> to cause problems.</p>
  180. *
  181. * <p>Advanced users can peruse the code herein to help them
  182. * investigate potential environment problems found; other users
  183. * may simply send the output from this tool along with any bugs
  184. * they submit to help us in the debugging process.</p>
  185. *
  186. * @param pw PrintWriter to send output to; can be sent to a
  187. * file that will look similar to a Properties file; defaults
  188. * to System.out if null
  189. * @return true if your environment appears to have no major
  190. * problems; false if potential environment problems found
  191. * @see #getEnvironmentHash()
  192. */
  193. public boolean checkEnvironment(PrintWriter pw)
  194. {
  195. // Use user-specified output writer if non-null
  196. if (null != pw)
  197. outWriter = pw;
  198. // Setup a hash to store various environment information in
  199. Hashtable hash = getEnvironmentHash();
  200. // Check for ERROR keys in the hashtable, and print report
  201. boolean environmentHasErrors = writeEnvironmentReport(hash);
  202. if (environmentHasErrors)
  203. {
  204. // Note: many logMsg calls have # at the start to
  205. // fake a property-file like output
  206. logMsg("# WARNING: Potential problems found in your environment!");
  207. logMsg("# Check any 'ERROR' items above against the Xalan FAQs");
  208. logMsg("# to correct potential problems with your classes/jars");
  209. logMsg("# http://xml.apache.org/xalan-j/faq.html");
  210. if (null != outWriter)
  211. outWriter.flush();
  212. return false;
  213. }
  214. else
  215. {
  216. logMsg("# YAHOO! Your environment seems to be OK.");
  217. if (null != outWriter)
  218. outWriter.flush();
  219. return true;
  220. }
  221. }
  222. /**
  223. * Fill a hash with basic environment settings that affect Xalan.
  224. *
  225. * <p>Worker method called from various places.</p>
  226. * <p>Various system and CLASSPATH, etc. properties are put into
  227. * the hash as keys with a brief description of the current state
  228. * of that item as the value. Any serious problems will be put in
  229. * with a key that is prefixed with {@link #ERROR 'ERROR.'} so it
  230. * stands out in any resulting report; also a key with just that
  231. * constant will be set as well for any error.</p>
  232. * <p>Note that some legitimate cases are flaged as potential
  233. * errors - namely when a developer recompiles xalan.jar on their
  234. * own - and even a non-error state doesn't guaruntee that
  235. * everything in the environment is correct. But this will help
  236. * point out the most common classpath and system property
  237. * problems that we've seen.</p>
  238. *
  239. * @return Hashtable full of useful environment info about Xalan
  240. * and related system properties, etc.
  241. */
  242. public Hashtable getEnvironmentHash()
  243. {
  244. // Setup a hash to store various environment information in
  245. Hashtable hash = new Hashtable();
  246. // Call various worker methods to fill in the hash
  247. // These are explicitly separate for maintenance and so
  248. // advanced users could call them standalone
  249. checkJAXPVersion(hash);
  250. checkProcessorVersion(hash);
  251. checkParserVersion(hash);
  252. checkAntVersion(hash);
  253. checkDOMVersion(hash);
  254. checkSAXVersion(hash);
  255. checkSystemProperties(hash);
  256. return hash;
  257. }
  258. /**
  259. * Dump a basic Xalan environment report to outWriter.
  260. *
  261. * <p>This dumps a simple header and then each of the entries in
  262. * the Hashtable to our PrintWriter; it does special processing
  263. * for entries that are .jars found in the classpath.</p>
  264. *
  265. * @param h Hashtable of items to report on; presumably
  266. * filled in by our various check*() methods
  267. * @return true if your environment appears to have no major
  268. * problems; false if potential environment problems found
  269. * @see #appendEnvironmentReport(Node, Document, Hashtable)
  270. * for an equivalent that appends to a Node instead
  271. */
  272. protected boolean writeEnvironmentReport(Hashtable h)
  273. {
  274. if (null == h)
  275. {
  276. logMsg("# ERROR: writeEnvironmentReport called with null Hashtable");
  277. return false;
  278. }
  279. boolean errors = false;
  280. logMsg(
  281. "#---- BEGIN writeEnvironmentReport($Revision: 1.14 $): Useful stuff found: ----");
  282. // Fake the Properties-like output
  283. for (Enumeration enum = h.keys();
  284. enum.hasMoreElements();
  285. /* no increment portion */
  286. )
  287. {
  288. Object key = enum.nextElement();
  289. String keyStr = (String) key;
  290. try
  291. {
  292. // Special processing for classes found..
  293. if (keyStr.startsWith(FOUNDCLASSES))
  294. {
  295. Vector v = (Vector) h.get(keyStr);
  296. errors |= logFoundJars(v, keyStr);
  297. }
  298. // ..normal processing for all other entries
  299. else
  300. {
  301. // Note: we could just check for the ERROR key by itself,
  302. // since we now set that, but since we have to go
  303. // through the whole hash anyway, do it this way,
  304. // which is safer for maintenance
  305. if (keyStr.startsWith(ERROR))
  306. {
  307. errors = true;
  308. }
  309. logMsg(keyStr + "=" + h.get(keyStr));
  310. }
  311. }
  312. catch (Exception e)
  313. {
  314. logMsg("Reading-" + key + "= threw: " + e.toString());
  315. }
  316. }
  317. logMsg(
  318. "#----- END writeEnvironmentReport: Useful properties found: -----");
  319. return errors;
  320. }
  321. /** Prefixed to hash keys that signify serious problems. */
  322. public static final String ERROR = "ERROR.";
  323. /** Added to descriptions that signify potential problems. */
  324. public static final String WARNING = "WARNING.";
  325. /** Value for any error found. */
  326. public static final String ERROR_FOUND = "At least one error was found!";
  327. /** Prefixed to hash keys that signify version numbers. */
  328. public static final String VERSION = "version.";
  329. /** Prefixed to hash keys that signify .jars found in classpath. */
  330. public static final String FOUNDCLASSES = "foundclasses.";
  331. /** Marker that a class or .jar was found. */
  332. public static final String CLASS_PRESENT = "present-unknown-version";
  333. /** Marker that a class or .jar was not found. */
  334. public static final String CLASS_NOTPRESENT = "not-present";
  335. /** Listing of common .jar files that include Xalan-related classes. */
  336. public String[] jarNames =
  337. {
  338. "xalan.jar", "xalansamples.jar", "xalanj1compat.jar", "xalanservlet.jar",
  339. "xerces.jar", // Xerces-J 1.x
  340. "xercesImpl.jar", // Xerces-J 2.x
  341. "testxsl.jar",
  342. "crimson.jar",
  343. "lotusxsl.jar",
  344. "jaxp.jar", "parser.jar", "dom.jar", "sax.jar", "xml.jar",
  345. "xml-apis.jar",
  346. "xsltc.jar"
  347. };
  348. /**
  349. * Print out report of .jars found in a classpath.
  350. *
  351. * Takes the information encoded from a checkPathForJars()
  352. * call and dumps it out to our PrintWriter.
  353. *
  354. * @param v Vector of Hashtables of .jar file info
  355. * @param desc description to print out in header
  356. *
  357. * @return false if OK, true if any .jars were reported
  358. * as having errors
  359. * @see #checkPathForJars(String, String[])
  360. */
  361. protected boolean logFoundJars(Vector v, String desc)
  362. {
  363. if ((null == v) || (v.size() < 1))
  364. return false;
  365. boolean errors = false;
  366. logMsg("#---- BEGIN Listing XML-related jars in: " + desc + " ----");
  367. for (int i = 0; i < v.size(); i++)
  368. {
  369. Hashtable subhash = (Hashtable) v.elementAt(i);
  370. for (Enumeration enum = subhash.keys();
  371. enum.hasMoreElements();
  372. /* no increment portion */
  373. )
  374. {
  375. Object key = enum.nextElement();
  376. String keyStr = (String) key;
  377. try
  378. {
  379. if (keyStr.startsWith(ERROR))
  380. {
  381. errors = true;
  382. }
  383. logMsg(keyStr + "=" + subhash.get(keyStr));
  384. }
  385. catch (Exception e)
  386. {
  387. errors = true;
  388. logMsg("Reading-" + key + "= threw: " + e.toString());
  389. }
  390. }
  391. }
  392. logMsg("#----- END Listing XML-related jars in: " + desc + " -----");
  393. return errors;
  394. }
  395. /**
  396. * Stylesheet extension entrypoint: Dump a basic Xalan
  397. * environment report from getEnvironmentHash() to a Node.
  398. *
  399. * <p>Copy of writeEnvironmentReport that creates a Node suitable
  400. * for other processing instead of a properties-like text output.
  401. * </p>
  402. * @param container Node to append our report to
  403. * @param factory Document providing createElement, etc. services
  404. * @param h Hash presumably from {@link #getEnvironmentHash()}
  405. * @see #writeEnvironmentReport(Hashtable)
  406. * for an equivalent that writes to a PrintWriter instead
  407. */
  408. public void appendEnvironmentReport(Node container, Document factory, Hashtable h)
  409. {
  410. if ((null == container) || (null == factory))
  411. {
  412. return;
  413. }
  414. try
  415. {
  416. Element envCheckNode = factory.createElement("EnvironmentCheck");
  417. envCheckNode.setAttribute("version", "$Revision: 1.14 $");
  418. container.appendChild(envCheckNode);
  419. if (null == h)
  420. {
  421. Element statusNode = factory.createElement("status");
  422. statusNode.setAttribute("result", "ERROR");
  423. statusNode.appendChild(factory.createTextNode("appendEnvironmentReport called with null Hashtable!"));
  424. envCheckNode.appendChild(statusNode);
  425. return;
  426. }
  427. boolean errors = false;
  428. Element hashNode = factory.createElement("environment");
  429. envCheckNode.appendChild(hashNode);
  430. for (Enumeration enum = h.keys();
  431. enum.hasMoreElements();
  432. /* no increment portion */
  433. )
  434. {
  435. Object key = enum.nextElement();
  436. String keyStr = (String) key;
  437. try
  438. {
  439. // Special processing for classes found..
  440. if (keyStr.startsWith(FOUNDCLASSES))
  441. {
  442. Vector v = (Vector) h.get(keyStr);
  443. // errors |= logFoundJars(v, keyStr);
  444. errors |= appendFoundJars(hashNode, factory, v, keyStr);
  445. }
  446. // ..normal processing for all other entries
  447. else
  448. {
  449. // Note: we could just check for the ERROR key by itself,
  450. // since we now set that, but since we have to go
  451. // through the whole hash anyway, do it this way,
  452. // which is safer for maintenance
  453. if (keyStr.startsWith(ERROR))
  454. {
  455. errors = true;
  456. }
  457. Element node = factory.createElement("item");
  458. node.setAttribute("key", keyStr);
  459. node.appendChild(factory.createTextNode((String)h.get(keyStr)));
  460. hashNode.appendChild(node);
  461. }
  462. }
  463. catch (Exception e)
  464. {
  465. errors = true;
  466. Element node = factory.createElement("item");
  467. node.setAttribute("key", keyStr);
  468. node.appendChild(factory.createTextNode(ERROR + " Reading " + key + " threw: " + e.toString()));
  469. hashNode.appendChild(node);
  470. }
  471. } // end of for...
  472. Element statusNode = factory.createElement("status");
  473. statusNode.setAttribute("result", (errors ? "ERROR" : "OK" ));
  474. envCheckNode.appendChild(statusNode);
  475. }
  476. catch (Exception e2)
  477. {
  478. System.err.println("appendEnvironmentReport threw: " + e2.toString());
  479. e2.printStackTrace();
  480. }
  481. }
  482. /**
  483. * Print out report of .jars found in a classpath.
  484. *
  485. * Takes the information encoded from a checkPathForJars()
  486. * call and dumps it out to our PrintWriter.
  487. *
  488. * @param container Node to append our report to
  489. * @param factory Document providing createElement, etc. services
  490. * @param v Vector of Hashtables of .jar file info
  491. * @param desc description to print out in header
  492. *
  493. * @return false if OK, true if any .jars were reported
  494. * as having errors
  495. * @see #checkPathForJars(String, String[])
  496. */
  497. protected boolean appendFoundJars(Node container, Document factory,
  498. Vector v, String desc)
  499. {
  500. if ((null == v) || (v.size() < 1))
  501. return false;
  502. boolean errors = false;
  503. for (int i = 0; i < v.size(); i++)
  504. {
  505. Hashtable subhash = (Hashtable) v.elementAt(i);
  506. for (Enumeration enum = subhash.keys();
  507. enum.hasMoreElements();
  508. /* no increment portion */
  509. )
  510. {
  511. Object key = enum.nextElement();
  512. try
  513. {
  514. String keyStr = (String) key;
  515. if (keyStr.startsWith(ERROR))
  516. {
  517. errors = true;
  518. }
  519. Element node = factory.createElement("foundJar");
  520. node.setAttribute("name", keyStr.substring(0, keyStr.indexOf("-")));
  521. node.setAttribute("desc", keyStr.substring(keyStr.indexOf("-") + 1));
  522. node.appendChild(factory.createTextNode((String)subhash.get(keyStr)));
  523. container.appendChild(node);
  524. }
  525. catch (Exception e)
  526. {
  527. errors = true;
  528. Element node = factory.createElement("foundJar");
  529. node.appendChild(factory.createTextNode(ERROR + " Reading " + key + " threw: " + e.toString()));
  530. container.appendChild(node);
  531. }
  532. }
  533. }
  534. return errors;
  535. }
  536. /**
  537. * Fillin hash with info about SystemProperties.
  538. *
  539. * Logs java.class.path and other likely paths; then attempts
  540. * to search those paths for .jar files with Xalan-related classes.
  541. *
  542. * //@todo NOTE: We don't actually search java.ext.dirs for
  543. * // *.jar files therein! This should be updated
  544. *
  545. * @param h Hashtable to put information in
  546. * @see #jarNames
  547. * @see #checkPathForJars(String, String[])
  548. */
  549. protected void checkSystemProperties(Hashtable h)
  550. {
  551. if (null == h)
  552. h = new Hashtable();
  553. // Grab java version for later use
  554. try
  555. {
  556. String javaVersion = System.getProperty("java.version");
  557. h.put("java.version", javaVersion);
  558. }
  559. catch (SecurityException se)
  560. {
  561. // For applet context, etc.
  562. h.put(
  563. "java.version",
  564. "WARNING: SecurityException thrown accessing system version properties");
  565. }
  566. // Printout jar files on classpath(s) that may affect operation
  567. // Do this in order
  568. try
  569. {
  570. // This is present in all JVM's
  571. String cp = System.getProperty("java.class.path");
  572. h.put("java.class.path", cp);
  573. Vector classpathJars = checkPathForJars(cp, jarNames);
  574. if (null != classpathJars)
  575. h.put(FOUNDCLASSES + "java.class.path", classpathJars);
  576. // Also check for JDK 1.2+ type classpaths
  577. String othercp = System.getProperty("sun.boot.class.path");
  578. if (null != othercp)
  579. {
  580. h.put("sun.boot.class.path", othercp);
  581. classpathJars = checkPathForJars(othercp, jarNames);
  582. if (null != classpathJars)
  583. h.put(FOUNDCLASSES + "sun.boot.class.path", classpathJars);
  584. }
  585. //@todo NOTE: We don't actually search java.ext.dirs for
  586. // *.jar files therein! This should be updated
  587. othercp = System.getProperty("java.ext.dirs");
  588. if (null != othercp)
  589. {
  590. h.put("java.ext.dirs", othercp);
  591. classpathJars = checkPathForJars(othercp, jarNames);
  592. if (null != classpathJars)
  593. h.put(FOUNDCLASSES + "java.ext.dirs", classpathJars);
  594. }
  595. //@todo also check other System properties' paths?
  596. // v2 = checkPathForJars(System.getProperty("sun.boot.library.path"), jarNames); // ?? may not be needed
  597. // v3 = checkPathForJars(System.getProperty("java.library.path"), jarNames); // ?? may not be needed
  598. }
  599. catch (SecurityException se2)
  600. {
  601. // For applet context, etc.
  602. h.put(
  603. "java.class.path",
  604. "WARNING: SecurityException thrown accessing system classpath properties");
  605. }
  606. }
  607. /**
  608. * Cheap-o listing of specified .jars found in the classpath.
  609. *
  610. * cp should be separated by the usual File.pathSeparator. We
  611. * then do a simplistic search of the path for any requested
  612. * .jar filenames, and return a listing of their names and
  613. * where (apparently) they came from.
  614. *
  615. * @param cp classpath to search
  616. * @param jars array of .jar base filenames to look for
  617. *
  618. * @return Vector of Hashtables filled with info about found .jars
  619. * @see #jarNames
  620. * @see #logFoundJars(Vector, String)
  621. * @see #appendFoundJars(Node, Document, Vector, String )
  622. * @see #getApparentVersion(String, long)
  623. */
  624. protected Vector checkPathForJars(String cp, String[] jars)
  625. {
  626. if ((null == cp) || (null == jars) || (0 == cp.length())
  627. || (0 == jars.length))
  628. return null;
  629. Vector v = new Vector();
  630. StringTokenizer st = new StringTokenizer(cp, File.pathSeparator);
  631. while (st.hasMoreTokens())
  632. {
  633. // Look at each classpath entry for each of our requested jarNames
  634. String filename = st.nextToken();
  635. for (int i = 0; i < jars.length; i++)
  636. {
  637. if (filename.indexOf(jars[i]) > -1)
  638. {
  639. File f = new File(filename);
  640. if (f.exists())
  641. {
  642. // If any requested jarName exists, report on
  643. // the details of that .jar file
  644. try
  645. {
  646. Hashtable h = new Hashtable(2);
  647. // Note "-" char is looked for in appendFoundJars
  648. h.put(jars[i] + "-path", f.getAbsolutePath());
  649. h.put(jars[i] + "-apparent.version",
  650. getApparentVersion(jars[i], f.length()));
  651. v.addElement(h);
  652. }
  653. catch (Exception e)
  654. {
  655. /* no-op, don't add it */
  656. }
  657. }
  658. else
  659. {
  660. Hashtable h = new Hashtable(2);
  661. // Note "-" char is looked for in appendFoundJars
  662. h.put(jars[i] + "-path", WARNING + " Classpath entry: "
  663. + filename + " does not exist");
  664. h.put(jars[i] + "-apparent.version", CLASS_NOTPRESENT);
  665. v.addElement(h);
  666. }
  667. }
  668. }
  669. }
  670. return v;
  671. }
  672. /**
  673. * Cheap-o method to determine the product version of a .jar.
  674. *
  675. * Currently does a lookup into a local table of some recent
  676. * shipped Xalan builds to determine where the .jar probably
  677. * came from. Note that if you recompile Xalan or Xerces
  678. * yourself this will likely report a potential error, since
  679. * we can't certify builds other than the ones we ship.
  680. * Only reports against selected posted Xalan-J builds.
  681. *
  682. * //@todo actually look up version info in manifests
  683. *
  684. * @param jarName base filename of the .jarfile
  685. * @param jarSize size of the .jarfile
  686. *
  687. * @return String describing where the .jar file probably
  688. * came from
  689. */
  690. protected String getApparentVersion(String jarName, long jarSize)
  691. {
  692. // If we found a matching size and it's for our
  693. // jar, then return it's description
  694. // Lookup in static jarVersions Hashtable
  695. String foundSize = (String) jarVersions.get(new Long(jarSize));
  696. if ((null != foundSize) && (foundSize.startsWith(jarName)))
  697. {
  698. return foundSize;
  699. }
  700. else
  701. {
  702. if ("xerces.jar".equalsIgnoreCase(jarName)
  703. || "xercesImpl.jar".equalsIgnoreCase(jarName)
  704. || "xalan.jar".equalsIgnoreCase(jarName))
  705. {
  706. // For xalan.jar and xerces.jar/xercesImpl.jar, which we ship together:
  707. // The jar is not from a shipped copy of xalan-j, so
  708. // it's up to the user to ensure that it's compatible
  709. return jarName + " " + WARNING + CLASS_PRESENT;
  710. }
  711. else
  712. {
  713. // Otherwise, it's just a jar we don't have the version info calculated for
  714. return jarName + " " + CLASS_PRESENT;
  715. }
  716. }
  717. }
  718. /**
  719. * Report version information about JAXP interfaces.
  720. *
  721. * Currently distinguishes between JAXP 1.0.1 and JAXP 1.1,
  722. * and not found; only tests the interfaces, and does not
  723. * check for reference implementation versions.
  724. *
  725. * @param h Hashtable to put information in
  726. */
  727. protected void checkJAXPVersion(Hashtable h)
  728. {
  729. if (null == h)
  730. h = new Hashtable();
  731. final Class noArgs[] = new Class[0];
  732. Class clazz = null;
  733. try
  734. {
  735. final String JAXP1_CLASS = "javax.xml.parsers.DocumentBuilder";
  736. final String JAXP11_METHOD = "getDOMImplementation";
  737. clazz = classForName(JAXP1_CLASS);
  738. Method method = clazz.getMethod(JAXP11_METHOD, noArgs);
  739. // If we succeeded, we at least have JAXP 1.1 available
  740. h.put(VERSION + "JAXP", "1.1");
  741. }
  742. catch (Exception e)
  743. {
  744. if (null != clazz)
  745. {
  746. // We must have found the class itself, just not the
  747. // method, so we (probably) have JAXP 1.0.1
  748. h.put(ERROR + VERSION + "JAXP", "1.0.1");
  749. h.put(ERROR, ERROR_FOUND);
  750. }
  751. else
  752. {
  753. // We couldn't even find the class, and don't have
  754. // any JAXP support at all, or only have the
  755. // transform half of it
  756. h.put(ERROR + VERSION + "JAXP", CLASS_NOTPRESENT);
  757. h.put(ERROR, ERROR_FOUND);
  758. }
  759. }
  760. }
  761. /**
  762. * Report product version information from Xalan-J.
  763. *
  764. * Looks for version info in xalan.jar from Xalan-J products.
  765. *
  766. * @param h Hashtable to put information in
  767. */
  768. protected void checkProcessorVersion(Hashtable h)
  769. {
  770. if (null == h)
  771. h = new Hashtable();
  772. try
  773. {
  774. final String XALAN1_VERSION_CLASS =
  775. "org.apache.xalan.xslt.XSLProcessorVersion";
  776. Class clazz = classForName(XALAN1_VERSION_CLASS);
  777. // Found Xalan-J 1.x, grab it's version fields
  778. StringBuffer buf = new StringBuffer();
  779. Field f = clazz.getField("PRODUCT");
  780. buf.append(f.get(null));
  781. buf.append(';');
  782. f = clazz.getField("LANGUAGE");
  783. buf.append(f.get(null));
  784. buf.append(';');
  785. f = clazz.getField("S_VERSION");
  786. buf.append(f.get(null));
  787. buf.append(';');
  788. h.put(VERSION + "xalan1", buf.toString());
  789. }
  790. catch (Exception e1)
  791. {
  792. h.put(VERSION + "xalan1", CLASS_NOTPRESENT);
  793. }
  794. try
  795. {
  796. // NOTE: This is the old Xalan 2.0, 2.1, 2.2 version class,
  797. // is being replaced by class below
  798. final String XALAN2_VERSION_CLASS =
  799. "org.apache.xalan.processor.XSLProcessorVersion";
  800. Class clazz = classForName(XALAN2_VERSION_CLASS);
  801. // Found Xalan-J 2.x, grab it's version fields
  802. StringBuffer buf = new StringBuffer();
  803. Field f = clazz.getField("S_VERSION");
  804. buf.append(f.get(null));
  805. h.put(VERSION + "xalan2x", buf.toString());
  806. }
  807. catch (Exception e2)
  808. {
  809. h.put(VERSION + "xalan2x", CLASS_NOTPRESENT);
  810. }
  811. try
  812. {
  813. // NOTE: This is the new Xalan 2.2+ version class
  814. final String XALAN2_2_VERSION_CLASS =
  815. "org.apache.xalan.Version";
  816. final String XALAN2_2_VERSION_METHOD = "getVersion";
  817. final Class noArgs[] = new Class[0];
  818. Class clazz = classForName(XALAN2_2_VERSION_CLASS);
  819. Method method = clazz.getMethod(XALAN2_2_VERSION_METHOD, noArgs);
  820. Object returnValue = method.invoke(null, new Object[0]);
  821. h.put(VERSION + "xalan2_2", (String)returnValue);
  822. }
  823. catch (Exception e2)
  824. {
  825. h.put(VERSION + "xalan2_2", CLASS_NOTPRESENT);
  826. }
  827. }
  828. /**
  829. * Report product version information from common parsers.
  830. *
  831. * Looks for version info in xerces.jar/xercesImpl.jar/crimson.jar.
  832. *
  833. * //@todo actually look up version info in crimson manifest
  834. *
  835. * @param h Hashtable to put information in
  836. */
  837. protected void checkParserVersion(Hashtable h)
  838. {
  839. if (null == h)
  840. h = new Hashtable();
  841. try
  842. {
  843. final String XERCES1_VERSION_CLASS = "org.apache.xerces.framework.Version";
  844. Class clazz = classForName(XERCES1_VERSION_CLASS);
  845. // Found Xerces-J 1.x, grab it's version fields
  846. Field f = clazz.getField("fVersion");
  847. String parserVersion = (String) f.get(null);
  848. h.put(VERSION + "xerces1", parserVersion);
  849. }
  850. catch (Exception e)
  851. {
  852. h.put(VERSION + "xerces1", CLASS_NOTPRESENT);
  853. }
  854. // Look for xerces1 and xerces2 parsers separately
  855. try
  856. {
  857. final String XERCES2_VERSION_CLASS = "org.apache.xerces.impl.Version";
  858. Class clazz = classForName(XERCES2_VERSION_CLASS);
  859. // Found Xerces-J 2.x, grab it's version fields
  860. Field f = clazz.getField("fVersion");
  861. String parserVersion = (String) f.get(null);
  862. h.put(VERSION + "xerces2", parserVersion);
  863. }
  864. catch (Exception e)
  865. {
  866. h.put(VERSION + "xerces2", CLASS_NOTPRESENT);
  867. }
  868. try
  869. {
  870. final String CRIMSON_CLASS = "org.apache.crimson.parser.Parser2";
  871. Class clazz = classForName(CRIMSON_CLASS);
  872. //@todo determine specific crimson version
  873. h.put(VERSION + "crimson", CLASS_PRESENT);
  874. }
  875. catch (Exception e)
  876. {
  877. h.put(VERSION + "crimson", CLASS_NOTPRESENT);
  878. }
  879. }
  880. /**
  881. * Report product version information from Ant.
  882. *
  883. * @param h Hashtable to put information in
  884. */
  885. protected void checkAntVersion(Hashtable h)
  886. {
  887. if (null == h)
  888. h = new Hashtable();
  889. try
  890. {
  891. final String ANT_VERSION_CLASS = "org.apache.tools.ant.Main";
  892. final String ANT_VERSION_METHOD = "getAntVersion"; // noArgs
  893. final Class noArgs[] = new Class[0];
  894. Class clazz = classForName(ANT_VERSION_CLASS);
  895. Method method = clazz.getMethod(ANT_VERSION_METHOD, noArgs);
  896. Object returnValue = method.invoke(null, new Object[0]);
  897. h.put(VERSION + "ant", (String)returnValue);
  898. }
  899. catch (Exception e)
  900. {
  901. h.put(VERSION + "ant", CLASS_NOTPRESENT);
  902. }
  903. }
  904. /**
  905. * Report version info from DOM interfaces.
  906. *
  907. * Currently distinguishes between pre-DOM level 2, the DOM
  908. * level 2 working draft, the DOM level 2 final draft,
  909. * and not found.
  910. *
  911. * @param h Hashtable to put information in
  912. */
  913. protected void checkDOMVersion(Hashtable h)
  914. {
  915. if (null == h)
  916. h = new Hashtable();
  917. final String DOM_LEVEL2_CLASS = "org.w3c.dom.Document";
  918. final String DOM_LEVEL2_METHOD = "createElementNS"; // String, String
  919. final String DOM_LEVEL2WD_CLASS = "org.w3c.dom.Node";
  920. final String DOM_LEVEL2WD_METHOD = "supported"; // String, String
  921. final String DOM_LEVEL2FD_CLASS = "org.w3c.dom.Node";
  922. final String DOM_LEVEL2FD_METHOD = "isSupported"; // String, String
  923. final Class twoStringArgs[] = { java.lang.String.class,
  924. java.lang.String.class };
  925. try
  926. {
  927. Class clazz = classForName(DOM_LEVEL2_CLASS);
  928. Method method = clazz.getMethod(DOM_LEVEL2_METHOD, twoStringArgs);
  929. // If we succeeded, we have loaded interfaces from a
  930. // level 2 DOM somewhere
  931. h.put(VERSION + "DOM", "2.0");
  932. try
  933. {
  934. // Check for the working draft version, which is
  935. // commonly found, but won't work anymore
  936. clazz = classForName(DOM_LEVEL2WD_CLASS);
  937. method = clazz.getMethod(DOM_LEVEL2WD_METHOD, twoStringArgs);
  938. h.put(ERROR + VERSION + "DOM.draftlevel", "2.0wd");
  939. h.put(ERROR, ERROR_FOUND);
  940. }
  941. catch (Exception e2)
  942. {
  943. try
  944. {
  945. // Check for the final draft version as well
  946. clazz = classForName(DOM_LEVEL2FD_CLASS);
  947. method = clazz.getMethod(DOM_LEVEL2FD_METHOD, twoStringArgs);
  948. h.put(VERSION + "DOM.draftlevel", "2.0fd");
  949. }
  950. catch (Exception e3)
  951. {
  952. h.put(ERROR + VERSION + "DOM.draftlevel", "2.0unknown");
  953. h.put(ERROR, ERROR_FOUND);
  954. }
  955. }
  956. }
  957. catch (Exception e)
  958. {
  959. h.put(ERROR + VERSION + "DOM",
  960. "ERROR attempting to load DOM level 2 class: " + e.toString());
  961. h.put(ERROR, ERROR_FOUND);
  962. }
  963. //@todo load an actual DOM implmementation and query it as well
  964. //@todo load an actual DOM implmementation and check if
  965. // isNamespaceAware() == true, which is needed to parse
  966. // xsl stylesheet files into a DOM
  967. }
  968. /**
  969. * Report version info from SAX interfaces.
  970. *
  971. * Currently distinguishes between SAX 2, SAX 2.0beta2,
  972. * SAX1, and not found.
  973. *
  974. * @param h Hashtable to put information in
  975. */
  976. protected void checkSAXVersion(Hashtable h)
  977. {
  978. if (null == h)
  979. h = new Hashtable();
  980. final String SAX_VERSION1_CLASS = "org.xml.sax.Parser";
  981. final String SAX_VERSION1_METHOD = "parse"; // String
  982. final String SAX_VERSION2_CLASS = "org.xml.sax.XMLReader";
  983. final String SAX_VERSION2_METHOD = "parse"; // String
  984. final String SAX_VERSION2BETA_CLASSNF = "org.xml.sax.helpers.AttributesImpl";
  985. final String SAX_VERSION2BETA_METHODNF = "setAttributes"; // Attributes
  986. final Class oneStringArg[] = { java.lang.String.class };
  987. // Note this introduces a minor compile dependency on SAX...
  988. final Class attributesArg[] = { org.xml.sax.Attributes.class };
  989. try
  990. {
  991. // This method was only added in the final SAX 2.0 release;
  992. // see changes.html "Changes from SAX 2.0beta2 to SAX 2.0prerelease"
  993. Class clazz = classForName(SAX_VERSION2BETA_CLASSNF);
  994. Method method = clazz.getMethod(SAX_VERSION2BETA_METHODNF, attributesArg);
  995. // If we succeeded, we have loaded interfaces from a
  996. // real, final SAX version 2.0 somewhere
  997. h.put(VERSION + "SAX", "2.0");
  998. }
  999. catch (Exception e)
  1000. {
  1001. // If we didn't find the SAX 2.0 class, look for a 2.0beta2
  1002. h.put(ERROR + VERSION + "SAX",
  1003. "ERROR attempting to load SAX version 2 class: " + e.toString());
  1004. h.put(ERROR, ERROR_FOUND);
  1005. try
  1006. {
  1007. Class clazz = classForName(SAX_VERSION2_CLASS);
  1008. Method method = clazz.getMethod(SAX_VERSION2_METHOD, oneStringArg);
  1009. // If we succeeded, we have loaded interfaces from a
  1010. // SAX version 2.0beta2 or earlier; these might work but
  1011. // you should really have the final SAX 2.0
  1012. h.put(VERSION + "SAX-backlevel", "2.0beta2-or-earlier");
  1013. }
  1014. catch (Exception e2)
  1015. {
  1016. // If we didn't find the SAX 2.0beta2 class, look for a 1.0 one
  1017. h.put(ERROR + VERSION + "SAX",
  1018. "ERROR attempting to load SAX version 2 class: " + e.toString());
  1019. h.put(ERROR, ERROR_FOUND);
  1020. try
  1021. {
  1022. Class clazz = classForName(SAX_VERSION1_CLASS);
  1023. Method method = clazz.getMethod(SAX_VERSION1_METHOD, oneStringArg);
  1024. // If we succeeded, we have loaded interfaces from a
  1025. // SAX version 1.0 somewhere; which won't work very
  1026. // well for JAXP 1.1 or beyond!
  1027. h.put(VERSION + "SAX-backlevel", "1.0");
  1028. }
  1029. catch (Exception e3)
  1030. {
  1031. // If we didn't find the SAX 2.0 class, look for a 1.0 one
  1032. // Note that either 1.0 or no SAX are both errors
  1033. h.put(ERROR + VERSION + "SAX-backlevel",
  1034. "ERROR attempting to load SAX version 1 class: " + e3.toString());
  1035. }
  1036. }
  1037. }
  1038. }
  1039. /**
  1040. * Worker method to load a class.
  1041. * Factor out loading classes for future use and JDK differences.
  1042. * Copied from javax.xml.*.FactoryFinder
  1043. * @param className name of class to load from
  1044. * an appropriate classLoader
  1045. * @return the class asked for
  1046. */
  1047. protected static Class classForName(String className)
  1048. throws ClassNotFoundException
  1049. {
  1050. ClassLoader classLoader = findClassLoader();
  1051. if (classLoader == null)
  1052. {
  1053. return Class.forName(className);
  1054. }
  1055. else
  1056. {
  1057. return classLoader.loadClass(className);
  1058. }
  1059. }
  1060. /**
  1061. * Worker method to figure out which ClassLoader to use.
  1062. * For JDK 1.2 and later use the context ClassLoader.
  1063. * Copied from javax.xml.*.FactoryFinder
  1064. * @return the appropriate ClassLoader
  1065. */
  1066. protected static ClassLoader findClassLoader()
  1067. throws ClassNotFoundException
  1068. {
  1069. ClassLoader classLoader = null;
  1070. Method m = null;
  1071. try
  1072. {
  1073. m = Thread.class.getMethod("getContextClassLoader", null);
  1074. }
  1075. catch (NoSuchMethodException e)
  1076. {
  1077. // Assume that we are running JDK 1.1, use the current ClassLoader
  1078. return EnvironmentCheck.class.getClassLoader();
  1079. }
  1080. try
  1081. {
  1082. return (ClassLoader) m.invoke(Thread.currentThread(), null);
  1083. }
  1084. catch (Exception e)
  1085. {
  1086. throw new RuntimeException(e.toString());
  1087. }
  1088. }
  1089. /**
  1090. * Manual table of known .jar sizes.
  1091. * Only includes shipped versions of certain projects.
  1092. * key=jarsize, value=jarname ' from ' distro name
  1093. * Note assumption: two jars cannot have the same size!
  1094. *
  1095. * @see #getApparentVersion(String, long)
  1096. */
  1097. protected static Hashtable jarVersions = new Hashtable();
  1098. /**
  1099. * Static initializer for jarVersions table.
  1100. * Doing this just once saves time and space.
  1101. *
  1102. * @see #getApparentVersion(String, long)
  1103. */
  1104. static
  1105. {
  1106. // Note: hackish Hashtable, this could use improvement
  1107. jarVersions.put(new Long(857192), "xalan.jar from xalan-j_1_1");
  1108. jarVersions.put(new Long(440237), "xalan.jar from xalan-j_1_2");
  1109. jarVersions.put(new Long(436094), "xalan.jar from xalan-j_1_2_1");
  1110. jarVersions.put(new Long(426249), "xalan.jar from xalan-j_1_2_2");
  1111. jarVersions.put(new Long(702536), "xalan.jar from xalan-j_2_0_0");
  1112. jarVersions.put(new Long(720930), "xalan.jar from xalan-j_2_0_1");
  1113. jarVersions.put(new Long(732330), "xalan.jar from xalan-j_2_1_0");
  1114. jarVersions.put(new Long(872241), "xalan.jar from xalan-j_2_2_D10");
  1115. jarVersions.put(new Long(882739), "xalan.jar from xalan-j_2_2_D11");
  1116. jarVersions.put(new Long(923866), "xalan.jar from xalan-j_2_2_0");
  1117. jarVersions.put(new Long(905872), "xalan.jar from xalan-j_2_3_D1");
  1118. jarVersions.put(new Long(906122), "xalan.jar from xalan-j_2_3_0");
  1119. jarVersions.put(new Long(906248), "xalan.jar from xalan-j_2_3_1");
  1120. jarVersions.put(new Long(983377), "xalan.jar from xalan-j_2_4_D1");
  1121. jarVersions.put(new Long(997276), "xalan.jar from xalan-j_2_4_0");
  1122. jarVersions.put(new Long(857171), "xalan.jar from lotusxsl-j_1_0_1");
  1123. jarVersions.put(new Long(802165), "xalan.jar from lotusxsl-j_2_0_0");
  1124. jarVersions.put(new Long(857692), "xalan.jar from lotusxsl-j_2_2");
  1125. jarVersions.put(new Long(906359), "xalan.jar from lotusxsl-j_2_3_1");
  1126. jarVersions.put(new Long(857692), "xalan.jar from lotusxsl-j_2_3_2");
  1127. jarVersions.put(new Long(1201514), "xalan.jar from lotusxsl-j_2_3_3");
  1128. jarVersions.put(new Long(1201599), "xalan.jar from lotusxsl-j_2_3_4");
  1129. jarVersions.put(new Long(1201641), "xalan.jar from lotusxsl-j_2_3_5");
  1130. jarVersions.put(new Long(596540), "xsltc.jar from xalan-j_2_2_0");
  1131. jarVersions.put(new Long(590247), "xsltc.jar from xalan-j_2_3_D1");
  1132. jarVersions.put(new Long(589914), "xsltc.jar from xalan-j_2_3_0");
  1133. jarVersions.put(new Long(589915), "xsltc.jar from xalan-j_2_3_1");
  1134. jarVersions.put(new Long(1306667), "xsltc.jar from xalan-j_2_4_D1");
  1135. jarVersions.put(new Long(1328227), "xsltc.jar from xalan-j_2_4_0");
  1136. jarVersions.put(new Long(1268634), "xsltc.jar-bundled from xalan-j_2_3_0");
  1137. jarVersions.put(new Long(100196), "xml-apis.jar from xalan-j_2_2_0 or xalan-j_2_3_D1");
  1138. jarVersions.put(new Long(108484), "xml-apis.jar from xalan-j_2_3_0, or xalan-j_2_3_1 from xml-commons-1.0.b2");
  1139. jarVersions.put(new Long(109049), "xml-apis.jar from xalan-j_2_4_0 from xml-commons RIVERCOURT1 branch");
  1140. jarVersions.put(new Long(109049), "xml-apis.jar from xalan-j_2_4_0, lotusxsl-j_2_3_2 or lotusxsl-j_2_3_3 from xml-commons RIVERCOURT1");
  1141. jarVersions.put(new Long(113749), "xml-apis.jar from xalan-j_2_4_1, lotusxsl-j_2_3_4 or lotusxsl-j_2_3_5 from factoryfinder-build of xml-commons RIVERCOURT1");
  1142. // If the below were more common I would update it to report
  1143. // errors better; but this is so old hardly anyone has it
  1144. jarVersions.put(new Long(424490), "xalan.jar from Xerces Tools releases - ERROR:DO NOT USE!");
  1145. jarVersions.put(new Long(1591855), "xerces.jar from xalan-j_1_1 from xerces-1...");
  1146. jarVersions.put(new Long(1498679), "xerces.jar from xalan-j_1_2 from xerces-1_2_0.bin");
  1147. jarVersions.put(new Long(1484896), "xerces.jar from xalan-j_1_2_1 from xerces-1_2_1.bin");
  1148. jarVersions.put(new Long(804460), "xerces.jar from xalan-j_1_2_2 from xerces-1_2_2.bin");
  1149. jarVersions.put(new Long(1499244), "xerces.jar from xalan-j_2_0_0 from xerces-1_2_3.bin");
  1150. jarVersions.put(new Long(1605266), "xerces.jar from xalan-j_2_0_1 from xerces-1_3_0.bin");
  1151. jarVersions.put(new Long(904030), "xerces.jar from xalan-j_2_1_0 from xerces-1_4.bin");
  1152. jarVersions.put(new Long(1190776), "xerces.jar from lotusxsl_1_0_1 apparently-from xerces-1_0_3.bin");
  1153. jarVersions.put(new Long(1489400), "xerces.jar from lotusxsl-j_2_0_0 from XML4J-3_1_1");
  1154. jarVersions.put(new Long(1787796), "xerces.jar from lotusxsl-j_2_2 or xerces-1_4_1.bin");
  1155. jarVersions.put(new Long(904030), "xerces.jar from xerces-1_4_0.bin");
  1156. jarVersions.put(new Long(1802885), "xerces.jar from xerces-1_4_2.bin");
  1157. jarVersions.put(new Long(1734594), "xerces.jar from Xerces-J-bin.2.0.0.beta3");
  1158. jarVersions.put(new Long(1808883), "xerces.jar from xalan-j_2_2_D10,D11,D12 or xerces-1_4_3.bin");
  1159. jarVersions.put(new Long(1803877), "xerces.jar from XML4J-3_2_1");
  1160. jarVersions.put(new Long(1812019), "xerces.jar from xalan-j_2_2_0");
  1161. jarVersions.put(new Long(1720292), "xercesImpl.jar from xalan-j_2_3_D1");
  1162. jarVersions.put(new Long(1730053), "xercesImpl.jar from xalan-j_2_3_0 or xalan-j_2_3_1 from xerces-2_0_0");
  1163. jarVersions.put(new Long(1728861), "xercesImpl.jar from xalan-j_2_4_D1 from xerces-2_0_1");
  1164. jarVersions.put(new Long(972027), "xercesImpl.jar from xalan-j_2_4_0 from xerces-2_1");
  1165. jarVersions.put(new Long(831587), "xercesImpl.jar from xalan-j_2_4_1 from xerces-2_2");
  1166. jarVersions.put(new Long(1729063), "xercesImpl.jar from lotusxsl-j_2_3_1 from XML4J-4_0_0");
  1167. jarVersions.put(new Long(1738551), "xercesImpl.jar from lotusxsl-j_2_3_2 from XML4J-4_0_2");
  1168. jarVersions.put(new Long(3243826), "xercesImpl.jar from lotusxsl-j_2_3_3 from XML4J-4_0_5");
  1169. jarVersions.put(new Long(1171789), "xercesImpl.jar from lotusxsl-j_2_3_4 from XML4J-4_0_6");
  1170. jarVersions.put(new Long(1174955), "xercesImpl.jar from lotusxsl-j_2_3_5 from XML4J-4_0_8");
  1171. jarVersions.put(new Long(1173922), "xercesImpl.jar from lotusxsl-j_2_3_6 from XML4J-4_0_9");
  1172. jarVersions.put(new Long(831828), "xercesImpl.jar from lotusxsl-j_2_4_0 from XML4J-4_1_1");
  1173. jarVersions.put(new Long(37485), "xalanj1compat.jar from xalan-j_2_0_0");
  1174. jarVersions.put(new Long(38100), "xalanj1compat.jar from xalan-j_2_0_1");
  1175. jarVersions.put(new Long(18779), "xalanservlet.jar from xalan-j_2_0_0");
  1176. jarVersions.put(new Long(21453), "xalanservlet.jar from xalan-j_2_0_1");
  1177. jarVersions.put(new Long(24826), "xalanservlet.jar from xalan-j_2_3_1 or xalan-j_2_4_1 or lotusxsl-j_2_3_1 to lotusxsl-j-2_3_5");
  1178. jarVersions.put(new Long(24831), "xalanservlet.jar from xalan-j_2_4_1");
  1179. // For those who've downloaded JAXP from sun
  1180. jarVersions.put(new Long(5618), "jaxp.jar from jaxp1.0.1");
  1181. jarVersions.put(new Long(136133), "parser.jar from jaxp1.0.1");
  1182. jarVersions.put(new Long(28404), "jaxp.jar from jaxp-1.1");
  1183. jarVersions.put(new Long(187162), "crimson.jar from jaxp-1.1");
  1184. jarVersions.put(new Long(801714), "xalan.jar from jaxp-1.1");
  1185. jarVersions.put(new Long(196399), "crimson.jar from crimson-1.1.1");
  1186. jarVersions.put(new Long(33323), "jaxp.jar from crimson-1.1.1 or jakarta-ant-1.4.1b1");
  1187. jarVersions.put(new Long(152717), "crimson.jar from crimson-1.1.2beta2");
  1188. jarVersions.put(new Long(88143), "xml-apis.jar from crimson-1.1.2beta2");
  1189. jarVersions.put(new Long(206384), "crimson.jar from crimson-1.1.3 or jakarta-ant-1.4.1b1");
  1190. // jakarta-ant: since many people use ant these days
  1191. jarVersions.put(new Long(136198), "parser.jar from jakarta-ant-1.3 or 1.2");
  1192. jarVersions.put(new Long(5537), "jaxp.jar from jakarta-ant-1.3 or 1.2");
  1193. // Various LotusXSL versions, which are based on Xalan code
  1194. // (LotusXSL was donated by Lotus to Apache to become Xalan)
  1195. jarVersions.put(new Long(120274), "lotusxsl.jar from lotusxsl-0_16_4");
  1196. jarVersions.put(new Long(120293), "lotusxsl.jar from lotusxsl-0_16_5");
  1197. jarVersions.put(new Long(283777), "lotusxsl.jar from lotusxsl-0_17_2");
  1198. jarVersions.put(new Long(305577), "lotusxsl.jar from lotusxsl-0_17_3");
  1199. jarVersions.put(new Long(304500), "lotusxsl.jar from lotusxsl-0_17_4");
  1200. jarVersions.put(new Long(714959), "lotusxsl.jar from lotusxsl-0_18_1");
  1201. jarVersions.put(new Long(717674), "lotusxsl.jar from lotusxsl-0_18_2");
  1202. jarVersions.put(new Long(752343), "lotusxsl.jar from lotusxsl-0_18_3");
  1203. jarVersions.put(new Long(907101), "lotusxsl.jar from lotusxsl-0_18_4");
  1204. }
  1205. /** Simple PrintWriter we send output to; defaults to System.out. */
  1206. protected PrintWriter outWriter = new PrintWriter(System.out, true);
  1207. /**
  1208. * Bottleneck output: calls outWriter.println(s).
  1209. * @param s String to print
  1210. */
  1211. protected void logMsg(String s)
  1212. {
  1213. outWriter.println(s);
  1214. }
  1215. }