FileDocCategorySizeDatePackage
EnvironmentCheck.javaAPI DocJava SE 5 API44633Fri Aug 26 14:55:32 BST 2005com.sun.org.apache.xalan.internal.xslt

EnvironmentCheck

public class EnvironmentCheck extends Object
Utility class to report simple information about the environment. Simplistic reporting about certain classes found in your JVM may help answer some FAQs for simple problems.

Usage-command line: java com.sun.org.apache.xalan.internal.xslt.EnvironmentCheck [-out outFile]

Usage-from program: boolean environmentOK = (new EnvironmentCheck()).checkEnvironment(yourPrintWriter);

Usage-from stylesheet:

<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
xmlns:xalan="http://xml.apache.org/xalan"
exclude-result-prefixes="xalan">
<xsl:output indent="yes"/>
<xsl:template match="/">
<xsl:copy-of select="xalan:checkEnvironment()"/>
</xsl:template>
</xsl:stylesheet>

Xalan users reporting problems are encouraged to use this class to see if there are potential problems with their actual Java environment before reporting a bug. Note that you should both check from the JVM/JRE's command line as well as temporarily calling checkEnvironment() directly from your code, since the classpath may differ (especially for servlets, etc).

Also see http://xml.apache.org/xalan-j/faq.html

Note: This class is pretty simplistic: results are not necessarily definitive nor will it find all problems related to environment setup. Also, you should avoid calling this in deployed production code, both because it is quite slow and because it forces classes to get loaded.

Note: This class explicitly has very limited compile-time dependencies to enable easy compilation and usage even when Xalan, DOM/SAX/JAXP, etc. are not present.

Note: for an improved version of this utility, please see the xml-commons' project Which utility which does the same kind of thing but in a much simpler manner.

author
Shane_Curcuru@us.ibm.com
version
$Id: EnvironmentCheck.java,v 1.26 2004/02/26 04:00:47 zongaro Exp $

Fields Summary
public static final String
ERROR
Prefixed to hash keys that signify serious problems.
public static final String
WARNING
Added to descriptions that signify potential problems.
public static final String
ERROR_FOUND
Value for any error found.
public static final String
VERSION
Prefixed to hash keys that signify version numbers.
public static final String
FOUNDCLASSES
Prefixed to hash keys that signify .jars found in classpath.
public static final String
CLASS_PRESENT
Marker that a class or .jar was found.
public static final String
CLASS_NOTPRESENT
Marker that a class or .jar was not found.
public String[]
jarNames
Listing of common .jar files that include Xalan-related classes.
protected static Hashtable
jarVersions
Manual table of known .jar sizes. Only includes shipped versions of certain projects. key=jarsize, value=jarname ' from ' distro name Note assumption: two jars cannot have the same size!
protected PrintWriter
outWriter
Simple PrintWriter we send output to; defaults to System.out.
Constructors Summary
Methods Summary
public static void_main(java.lang.String[] args)
Command line runnability: checks for [-out outFilename] arg.

Command line entrypoint; Sets output and calls {@link #checkEnvironment(PrintWriter)}.

param
args command line args

    // Default to System.out, autoflushing
    PrintWriter sendOutputTo = new PrintWriter(System.out, true);

    // Read our simplistic input args, if supplied
    for (int i = 0; i < args.length; i++)
    {
      if ("-out".equalsIgnoreCase(args[i]))
      {
        i++;

        if (i < args.length)
        {
          try
          {
            sendOutputTo = new PrintWriter(new FileWriter(args[i], true));
          }
          catch (Exception e)
          {
            System.err.println("# WARNING: -out " + args[i] + " threw "
                               + e.toString());
          }
        }
        else
        {
          System.err.println(
            "# WARNING: -out argument should have a filename, output sent to console");
        }
      }
    }

    EnvironmentCheck app = new EnvironmentCheck();
    app.checkEnvironment(sendOutputTo);
  
public voidappendEnvironmentReport(org.w3c.dom.Node container, org.w3c.dom.Document factory, java.util.Hashtable h)
Stylesheet extension entrypoint: Dump a basic Xalan environment report from getEnvironmentHash() to a Node.

Copy of writeEnvironmentReport that creates a Node suitable for other processing instead of a properties-like text output.

param
container Node to append our report to
param
factory Document providing createElement, etc. services
param
h Hash presumably from {@link #getEnvironmentHash()}
see
#writeEnvironmentReport(Hashtable) for an equivalent that writes to a PrintWriter instead

    if ((null == container) || (null == factory))
    {
      return;
    }
  
    try
    {
      Element envCheckNode = factory.createElement("EnvironmentCheck");
      envCheckNode.setAttribute("version", "$Revision: 1.26 $");
      container.appendChild(envCheckNode);

      if (null == h)
      {
        Element statusNode = factory.createElement("status");
        statusNode.setAttribute("result", "ERROR");
        statusNode.appendChild(factory.createTextNode("appendEnvironmentReport called with null Hashtable!"));
        envCheckNode.appendChild(statusNode);
        return;
      }

      boolean errors = false;

      Element hashNode = factory.createElement("environment");
      envCheckNode.appendChild(hashNode);
      
      for (Enumeration keys = h.keys(); 
           keys.hasMoreElements();
          /* no increment portion */
          )
      {
        Object key = keys.nextElement();
        String keyStr = (String) key;
        try
        {
          // Special processing for classes found..
          if (keyStr.startsWith(FOUNDCLASSES))
          {
            Vector v = (Vector) h.get(keyStr);
            // errors |= logFoundJars(v, keyStr);
            errors |= appendFoundJars(hashNode, factory, v, keyStr);
          }
          // ..normal processing for all other entries
          else 
          {
            // Note: we could just check for the ERROR key by itself, 
            //    since we now set that, but since we have to go 
            //    through the whole hash anyway, do it this way,
            //    which is safer for maintenance
            if (keyStr.startsWith(ERROR))
            {
              errors = true;
            }
            Element node = factory.createElement("item");
            node.setAttribute("key", keyStr);
            node.appendChild(factory.createTextNode((String)h.get(keyStr)));
            hashNode.appendChild(node);
          }
        }
        catch (Exception e)
        {
          errors = true;
          Element node = factory.createElement("item");
          node.setAttribute("key", keyStr);
          node.appendChild(factory.createTextNode(ERROR + " Reading " + key + " threw: " + e.toString()));
          hashNode.appendChild(node);
        }
      } // end of for...

      Element statusNode = factory.createElement("status");
      statusNode.setAttribute("result", (errors ? "ERROR" : "OK" ));
      envCheckNode.appendChild(statusNode);
    }
    catch (Exception e2)
    {
      System.err.println("appendEnvironmentReport threw: " + e2.toString());
      e2.printStackTrace();
    }
  
protected booleanappendFoundJars(org.w3c.dom.Node container, org.w3c.dom.Document factory, java.util.Vector v, java.lang.String desc)
Print out report of .jars found in a classpath. Takes the information encoded from a checkPathForJars() call and dumps it out to our PrintWriter.

param
container Node to append our report to
param
factory Document providing createElement, etc. services
param
v Vector of Hashtables of .jar file info
param
desc description to print out in header
return
false if OK, true if any .jars were reported as having errors
see
#checkPathForJars(String, String[])


    if ((null == v) || (v.size() < 1))
      return false;

    boolean errors = false;

    for (int i = 0; i < v.size(); i++)
    {
      Hashtable subhash = (Hashtable) v.elementAt(i);

      for (Enumeration keys = subhash.keys(); 
           keys.hasMoreElements();
           /* no increment portion */
          )
      {
        Object key = keys.nextElement();
        try
        {
          String keyStr = (String) key;
          if (keyStr.startsWith(ERROR))
          {
            errors = true;
          }
          Element node = factory.createElement("foundJar");
          node.setAttribute("name", keyStr.substring(0, keyStr.indexOf("-")));
          node.setAttribute("desc", keyStr.substring(keyStr.indexOf("-") + 1));
          node.appendChild(factory.createTextNode((String)subhash.get(keyStr)));
          container.appendChild(node);
        }
        catch (Exception e)
        {
          errors = true;
          Element node = factory.createElement("foundJar");
          node.appendChild(factory.createTextNode(ERROR + " Reading " + key + " threw: " + e.toString()));
          container.appendChild(node);
        }
      }
    }
    return errors;
  
protected voidcheckAntVersion(java.util.Hashtable h)
Report product version information from Ant.

param
h Hashtable to put information in


    if (null == h)
      h = new Hashtable();

    try
    {
      final String ANT_VERSION_CLASS = "org.apache.tools.ant.Main";
      final String ANT_VERSION_METHOD = "getAntVersion"; // noArgs
      final Class noArgs[] = new Class[0];

      Class clazz = ObjectFactory.findProviderClass(
        ANT_VERSION_CLASS, ObjectFactory.findClassLoader(), true);

      Method method = clazz.getMethod(ANT_VERSION_METHOD, noArgs);
      Object returnValue = method.invoke(null, new Object[0]);

      h.put(VERSION + "ant", (String)returnValue);
    }
    catch (Exception e)
    {
      h.put(VERSION + "ant", CLASS_NOTPRESENT);
    }
  
protected voidcheckDOMVersion(java.util.Hashtable h)
Report version info from DOM interfaces. Currently distinguishes between pre-DOM level 2, the DOM level 2 working draft, the DOM level 2 final draft, and not found.

param
h Hashtable to put information in


    if (null == h)
      h = new Hashtable();

    final String DOM_LEVEL2_CLASS = "org.w3c.dom.Document";
    final String DOM_LEVEL2_METHOD = "createElementNS";  // String, String
    final String DOM_LEVEL2WD_CLASS = "org.w3c.dom.Node";
    final String DOM_LEVEL2WD_METHOD = "supported";  // String, String
    final String DOM_LEVEL2FD_CLASS = "org.w3c.dom.Node";
    final String DOM_LEVEL2FD_METHOD = "isSupported";  // String, String
    final Class twoStringArgs[] = { java.lang.String.class,
                                    java.lang.String.class };

    try
    {
      Class clazz = ObjectFactory.findProviderClass(
        DOM_LEVEL2_CLASS, ObjectFactory.findClassLoader(), true);

      Method method = clazz.getMethod(DOM_LEVEL2_METHOD, twoStringArgs);

      // If we succeeded, we have loaded interfaces from a 
      //  level 2 DOM somewhere
      h.put(VERSION + "DOM", "2.0");

      try
      {
        // Check for the working draft version, which is 
        //  commonly found, but won't work anymore
        clazz = ObjectFactory.findProviderClass(
          DOM_LEVEL2WD_CLASS, ObjectFactory.findClassLoader(), true);

        method = clazz.getMethod(DOM_LEVEL2WD_METHOD, twoStringArgs);

        h.put(ERROR + VERSION + "DOM.draftlevel", "2.0wd");
        h.put(ERROR, ERROR_FOUND);
      }
      catch (Exception e2)
      {
        try
        {
          // Check for the final draft version as well
          clazz = ObjectFactory.findProviderClass(
            DOM_LEVEL2FD_CLASS, ObjectFactory.findClassLoader(), true);

          method = clazz.getMethod(DOM_LEVEL2FD_METHOD, twoStringArgs);

          h.put(VERSION + "DOM.draftlevel", "2.0fd");
        }
        catch (Exception e3)
        {
          h.put(ERROR + VERSION + "DOM.draftlevel", "2.0unknown");
          h.put(ERROR, ERROR_FOUND);
        }
      }
    }
    catch (Exception e)
    {
      h.put(ERROR + VERSION + "DOM",
            "ERROR attempting to load DOM level 2 class: " + e.toString());
      h.put(ERROR, ERROR_FOUND);
    }

    //@todo load an actual DOM implmementation and query it as well
    //@todo load an actual DOM implmementation and check if 
    //  isNamespaceAware() == true, which is needed to parse 
    //  xsl stylesheet files into a DOM
  
public booleancheckEnvironment(java.io.PrintWriter pw)
Programmatic entrypoint: Report on basic Java environment and CLASSPATH settings that affect Xalan.

Note that this class is not advanced enough to tell you everything about the environment that affects Xalan, and sometimes reports errors that will not actually affect Xalan's behavior. Currently, it very simplistically checks the JVM's environment for some basic properties and logs them out; it will report a problem if it finds a setting or .jar file that is likely to cause problems.

Advanced users can peruse the code herein to help them investigate potential environment problems found; other users may simply send the output from this tool along with any bugs they submit to help us in the debugging process.

param
pw PrintWriter to send output to; can be sent to a file that will look similar to a Properties file; defaults to System.out if null
return
true if your environment appears to have no major problems; false if potential environment problems found
see
#getEnvironmentHash()


    // Use user-specified output writer if non-null
    if (null != pw)
      outWriter = pw;

    // Setup a hash to store various environment information in
    Hashtable hash = getEnvironmentHash();

    // Check for ERROR keys in the hashtable, and print report
    boolean environmentHasErrors = writeEnvironmentReport(hash);

    if (environmentHasErrors)
    {
      // Note: many logMsg calls have # at the start to 
      //  fake a property-file like output
      logMsg("# WARNING: Potential problems found in your environment!");
      logMsg("#    Check any 'ERROR' items above against the Xalan FAQs");
      logMsg("#    to correct potential problems with your classes/jars");
      logMsg("#    http://xml.apache.org/xalan-j/faq.html");
      if (null != outWriter)
        outWriter.flush();
      return false;
    }
    else
    {
      logMsg("# YAHOO! Your environment seems to be OK.");
      if (null != outWriter)
        outWriter.flush();
      return true;
    }
  
protected voidcheckJAXPVersion(java.util.Hashtable h)
Report version information about JAXP interfaces. Currently distinguishes between JAXP 1.0.1 and JAXP 1.1, and not found; only tests the interfaces, and does not check for reference implementation versions.

param
h Hashtable to put information in


    if (null == h)
      h = new Hashtable();

    final Class noArgs[] = new Class[0];
    Class clazz = null;

    try
    {
      final String JAXP1_CLASS = "javax.xml.parsers.DocumentBuilder";
      final String JAXP11_METHOD = "getDOMImplementation";

      clazz = ObjectFactory.findProviderClass(
        JAXP1_CLASS, ObjectFactory.findClassLoader(), true);

      Method method = clazz.getMethod(JAXP11_METHOD, noArgs);

      // If we succeeded, we at least have JAXP 1.1 available
      h.put(VERSION + "JAXP", "1.1 or higher");
    }
    catch (Exception e)
    {
      if (null != clazz)
      {

        // We must have found the class itself, just not the 
        //  method, so we (probably) have JAXP 1.0.1
        h.put(ERROR + VERSION + "JAXP", "1.0.1");
        h.put(ERROR, ERROR_FOUND);
      }
      else
      {
        // We couldn't even find the class, and don't have 
        //  any JAXP support at all, or only have the 
        //  transform half of it
        h.put(ERROR + VERSION + "JAXP", CLASS_NOTPRESENT);
        h.put(ERROR, ERROR_FOUND);
      }
    }
  
protected voidcheckParserVersion(java.util.Hashtable h)
Report product version information from common parsers. Looks for version info in xerces.jar/xercesImpl.jar/crimson.jar. //@todo actually look up version info in crimson manifest

param
h Hashtable to put information in


    if (null == h)
      h = new Hashtable();

    try
    {
      final String XERCES1_VERSION_CLASS = "com.sun.org.apache.xerces.internal.framework.Version";

      Class clazz = ObjectFactory.findProviderClass(
        XERCES1_VERSION_CLASS, ObjectFactory.findClassLoader(), true);

      // Found Xerces-J 1.x, grab it's version fields
      Field f = clazz.getField("fVersion");
      String parserVersion = (String) f.get(null);

      h.put(VERSION + "xerces1", parserVersion);
    }
    catch (Exception e)
    {
      h.put(VERSION + "xerces1", CLASS_NOTPRESENT);
    }

    // Look for xerces1 and xerces2 parsers separately
    try
    {
      final String XERCES2_VERSION_CLASS = "com.sun.org.apache.xerces.internal.impl.Version";

      Class clazz = ObjectFactory.findProviderClass(
        XERCES2_VERSION_CLASS, ObjectFactory.findClassLoader(), true);

      // Found Xerces-J 2.x, grab it's version fields
      Field f = clazz.getField("fVersion");
      String parserVersion = (String) f.get(null);

      h.put(VERSION + "xerces2", parserVersion);
    }
    catch (Exception e)
    {
      h.put(VERSION + "xerces2", CLASS_NOTPRESENT);
    }

    try
    {
      final String CRIMSON_CLASS = "org.apache.crimson.parser.Parser2";

      Class clazz = ObjectFactory.findProviderClass(
        CRIMSON_CLASS, ObjectFactory.findClassLoader(), true);

      //@todo determine specific crimson version
      h.put(VERSION + "crimson", CLASS_PRESENT);
    }
    catch (Exception e)
    {
      h.put(VERSION + "crimson", CLASS_NOTPRESENT);
    }
  
protected java.util.VectorcheckPathForJars(java.lang.String cp, java.lang.String[] jars)
Cheap-o listing of specified .jars found in the classpath. cp should be separated by the usual File.pathSeparator. We then do a simplistic search of the path for any requested .jar filenames, and return a listing of their names and where (apparently) they came from.

param
cp classpath to search
param
jars array of .jar base filenames to look for
return
Vector of Hashtables filled with info about found .jars
see
#jarNames
see
#logFoundJars(Vector, String)
see
#appendFoundJars(Node, Document, Vector, String )
see
#getApparentVersion(String, long)


    if ((null == cp) || (null == jars) || (0 == cp.length())
            || (0 == jars.length))
      return null;

    Vector v = new Vector();
    StringTokenizer st = new StringTokenizer(cp, File.pathSeparator);

    while (st.hasMoreTokens())
    {

      // Look at each classpath entry for each of our requested jarNames
      String filename = st.nextToken();

      for (int i = 0; i < jars.length; i++)
      {
        if (filename.indexOf(jars[i]) > -1)
        {
          File f = new File(filename);

          if (f.exists())
          {

            // If any requested jarName exists, report on 
            //  the details of that .jar file
            try
            {
              Hashtable h = new Hashtable(2);
              // Note "-" char is looked for in appendFoundJars
              h.put(jars[i] + "-path", f.getAbsolutePath());
             
              // We won't bother reporting on the xalan.jar apparent version
              // since this requires knowing the jar size of the xalan.jar
              // before we build it. 
              // For other jars, eg. xml-apis.jar and xercesImpl.jar, we 
              // report the apparent version of the file we've found
              if (!("xalan.jar".equalsIgnoreCase(jars[i]))) {              
                h.put(jars[i] + "-apparent.version",
                    getApparentVersion(jars[i], f.length()));
              }
              v.addElement(h);
            }
            catch (Exception e)
            {

              /* no-op, don't add it  */
            }
          }
          else
          {
            Hashtable h = new Hashtable(2);
            // Note "-" char is looked for in appendFoundJars
            h.put(jars[i] + "-path", WARNING + " Classpath entry: " 
                  + filename + " does not exist");
            h.put(jars[i] + "-apparent.version", CLASS_NOTPRESENT);
            v.addElement(h);
          }
        }
      }
    }

    return v;
  
protected voidcheckProcessorVersion(java.util.Hashtable h)
Report product version information from Xalan-J. Looks for version info in xalan.jar from Xalan-J products.

param
h Hashtable to put information in


    if (null == h)
      h = new Hashtable();

    try
    {
      final String XALAN1_VERSION_CLASS =
        "com.sun.org.apache.xalan.internal.xslt.XSLProcessorVersion";

      Class clazz = ObjectFactory.findProviderClass(
        XALAN1_VERSION_CLASS, ObjectFactory.findClassLoader(), true);

      // Found Xalan-J 1.x, grab it's version fields
      StringBuffer buf = new StringBuffer();
      Field f = clazz.getField("PRODUCT");

      buf.append(f.get(null));
      buf.append(';");

      f = clazz.getField("LANGUAGE");

      buf.append(f.get(null));
      buf.append(';");

      f = clazz.getField("S_VERSION");

      buf.append(f.get(null));
      buf.append(';");
      h.put(VERSION + "xalan1", buf.toString());
    }
    catch (Exception e1)
    {
      h.put(VERSION + "xalan1", CLASS_NOTPRESENT);
    }

    try
    {
      // NOTE: This is the old Xalan 2.0, 2.1, 2.2 version class, 
      //    is being replaced by class below
      final String XALAN2_VERSION_CLASS =
        "com.sun.org.apache.xalan.internal.processor.XSLProcessorVersion";

      Class clazz = ObjectFactory.findProviderClass(
        XALAN2_VERSION_CLASS, ObjectFactory.findClassLoader(), true);

      // Found Xalan-J 2.x, grab it's version fields
      StringBuffer buf = new StringBuffer();
      Field f = clazz.getField("S_VERSION");
      buf.append(f.get(null));

      h.put(VERSION + "xalan2x", buf.toString());
    }
    catch (Exception e2)
    {
      h.put(VERSION + "xalan2x", CLASS_NOTPRESENT);
    }
    try
    {
      // NOTE: This is the new Xalan 2.2+ version class
      final String XALAN2_2_VERSION_CLASS =
        "com.sun.org.apache.xalan.internal.Version";
      final String XALAN2_2_VERSION_METHOD = "getVersion";
      final Class noArgs[] = new Class[0];

      Class clazz = ObjectFactory.findProviderClass(
        XALAN2_2_VERSION_CLASS, ObjectFactory.findClassLoader(), true);

      Method method = clazz.getMethod(XALAN2_2_VERSION_METHOD, noArgs);
      Object returnValue = method.invoke(null, new Object[0]);

      h.put(VERSION + "xalan2_2", (String)returnValue);
    }
    catch (Exception e2)
    {
      h.put(VERSION + "xalan2_2", CLASS_NOTPRESENT);
    }
  
protected voidcheckSAXVersion(java.util.Hashtable h)
Report version info from SAX interfaces. Currently distinguishes between SAX 2, SAX 2.0beta2, SAX1, and not found.

param
h Hashtable to put information in


    if (null == h)
      h = new Hashtable();

    final String SAX_VERSION1_CLASS = "org.xml.sax.Parser";
    final String SAX_VERSION1_METHOD = "parse";  // String
    final String SAX_VERSION2_CLASS = "org.xml.sax.XMLReader";
    final String SAX_VERSION2_METHOD = "parse";  // String
    final String SAX_VERSION2BETA_CLASSNF = "org.xml.sax.helpers.AttributesImpl";
    final String SAX_VERSION2BETA_METHODNF = "setAttributes";  // Attributes
    final Class oneStringArg[] = { java.lang.String.class };
    // Note this introduces a minor compile dependency on SAX...
    final Class attributesArg[] = { org.xml.sax.Attributes.class };

    try
    {
      // This method was only added in the final SAX 2.0 release; 
      //  see changes.html "Changes from SAX 2.0beta2 to SAX 2.0prerelease"
      Class clazz = ObjectFactory.findProviderClass(
        SAX_VERSION2BETA_CLASSNF, ObjectFactory.findClassLoader(), true);

      Method method = clazz.getMethod(SAX_VERSION2BETA_METHODNF, attributesArg);

      // If we succeeded, we have loaded interfaces from a 
      //  real, final SAX version 2.0 somewhere
      h.put(VERSION + "SAX", "2.0");
    }
    catch (Exception e)
    {
      // If we didn't find the SAX 2.0 class, look for a 2.0beta2
      h.put(ERROR + VERSION + "SAX",
            "ERROR attempting to load SAX version 2 class: " + e.toString());
      h.put(ERROR, ERROR_FOUND);
            
      try
      {
        Class clazz = ObjectFactory.findProviderClass(
          SAX_VERSION2_CLASS, ObjectFactory.findClassLoader(), true);

        Method method = clazz.getMethod(SAX_VERSION2_METHOD, oneStringArg);

        // If we succeeded, we have loaded interfaces from a 
        //  SAX version 2.0beta2 or earlier; these might work but 
        //  you should really have the final SAX 2.0 
        h.put(VERSION + "SAX-backlevel", "2.0beta2-or-earlier");
      }
      catch (Exception e2)
      {
        // If we didn't find the SAX 2.0beta2 class, look for a 1.0 one
        h.put(ERROR + VERSION + "SAX",
              "ERROR attempting to load SAX version 2 class: " + e.toString());
        h.put(ERROR, ERROR_FOUND);
          
        try
        {
          Class clazz = ObjectFactory.findProviderClass(
            SAX_VERSION1_CLASS, ObjectFactory.findClassLoader(), true);

          Method method = clazz.getMethod(SAX_VERSION1_METHOD, oneStringArg);

          // If we succeeded, we have loaded interfaces from a 
          //  SAX version 1.0 somewhere; which won't work very 
          //  well for JAXP 1.1 or beyond!
          h.put(VERSION + "SAX-backlevel", "1.0");
        }
        catch (Exception e3)
        {
          // If we didn't find the SAX 2.0 class, look for a 1.0 one
          // Note that either 1.0 or no SAX are both errors
          h.put(ERROR + VERSION + "SAX-backlevel",
                "ERROR attempting to load SAX version 1 class: " + e3.toString());
            
        }
      }
    }
  
protected voidcheckSystemProperties(java.util.Hashtable h)
Fillin hash with info about SystemProperties. Logs java.class.path and other likely paths; then attempts to search those paths for .jar files with Xalan-related classes. //@todo NOTE: We don't actually search java.ext.dirs for // *.jar files therein! This should be updated

param
h Hashtable to put information in
see
#jarNames
see
#checkPathForJars(String, String[])


    if (null == h)
      h = new Hashtable();

    // Grab java version for later use
    try
    {
      String javaVersion = System.getProperty("java.version");

      h.put("java.version", javaVersion);
    }
    catch (SecurityException se)
    {

      // For applet context, etc.
      h.put(
        "java.version",
        "WARNING: SecurityException thrown accessing system version properties");
    }

    // Printout jar files on classpath(s) that may affect operation
    //  Do this in order
    try
    {

      // This is present in all JVM's
      String cp = System.getProperty("java.class.path");

      h.put("java.class.path", cp);

      Vector classpathJars = checkPathForJars(cp, jarNames);

      if (null != classpathJars)
        h.put(FOUNDCLASSES + "java.class.path", classpathJars);

      // Also check for JDK 1.2+ type classpaths
      String othercp = System.getProperty("sun.boot.class.path");

      if (null != othercp)
      {
        h.put("sun.boot.class.path", othercp);

        classpathJars = checkPathForJars(othercp, jarNames);

        if (null != classpathJars)
          h.put(FOUNDCLASSES + "sun.boot.class.path", classpathJars);
      }

      //@todo NOTE: We don't actually search java.ext.dirs for 
      //  *.jar files therein! This should be updated
      othercp = System.getProperty("java.ext.dirs");

      if (null != othercp)
      {
        h.put("java.ext.dirs", othercp);

        classpathJars = checkPathForJars(othercp, jarNames);

        if (null != classpathJars)
          h.put(FOUNDCLASSES + "java.ext.dirs", classpathJars);
      }

      //@todo also check other System properties' paths?
      //  v2 = checkPathForJars(System.getProperty("sun.boot.library.path"), jarNames);   // ?? may not be needed
      //  v3 = checkPathForJars(System.getProperty("java.library.path"), jarNames);   // ?? may not be needed
    }
    catch (SecurityException se2)
    {
      // For applet context, etc.
      h.put(
        "java.class.path",
        "WARNING: SecurityException thrown accessing system classpath properties");
    }
  
protected java.lang.StringgetApparentVersion(java.lang.String jarName, long jarSize)
Cheap-o method to determine the product version of a .jar. Currently does a lookup into a local table of some recent shipped Xalan builds to determine where the .jar probably came from. Note that if you recompile Xalan or Xerces yourself this will likely report a potential error, since we can't certify builds other than the ones we ship. Only reports against selected posted Xalan-J builds. //@todo actually look up version info in manifests

param
jarName base filename of the .jarfile
param
jarSize size of the .jarfile
return
String describing where the .jar file probably came from

    // If we found a matching size and it's for our 
    //  jar, then return it's description
    // Lookup in static jarVersions Hashtable
    String foundSize = (String) jarVersions.get(new Long(jarSize));

    if ((null != foundSize) && (foundSize.startsWith(jarName)))
    {
      return foundSize;
    }
    else
    {
      if ("xerces.jar".equalsIgnoreCase(jarName)
              || "xercesImpl.jar".equalsIgnoreCase(jarName))
//              || "xalan.jar".equalsIgnoreCase(jarName))
      {

        // For xalan.jar and xerces.jar/xercesImpl.jar, which we ship together:
        // The jar is not from a shipped copy of xalan-j, so 
        //  it's up to the user to ensure that it's compatible
        return jarName + " " + WARNING + CLASS_PRESENT;
      }
      else
      {

        // Otherwise, it's just a jar we don't have the version info calculated for
        return jarName + " " + CLASS_PRESENT;
      }
    }
  
public java.util.HashtablegetEnvironmentHash()
Fill a hash with basic environment settings that affect Xalan.

Worker method called from various places.

Various system and CLASSPATH, etc. properties are put into the hash as keys with a brief description of the current state of that item as the value. Any serious problems will be put in with a key that is prefixed with {@link #ERROR 'ERROR.'} so it stands out in any resulting report; also a key with just that constant will be set as well for any error.

Note that some legitimate cases are flaged as potential errors - namely when a developer recompiles xalan.jar on their own - and even a non-error state doesn't guaruntee that everything in the environment is correct. But this will help point out the most common classpath and system property problems that we've seen.

return
Hashtable full of useful environment info about Xalan and related system properties, etc.

    // Setup a hash to store various environment information in
    Hashtable hash = new Hashtable();

    // Call various worker methods to fill in the hash
    //  These are explicitly separate for maintenance and so 
    //  advanced users could call them standalone
    checkJAXPVersion(hash);
    checkProcessorVersion(hash);
    checkParserVersion(hash);
    checkAntVersion(hash);
    checkDOMVersion(hash);
    checkSAXVersion(hash);
    checkSystemProperties(hash);

    return hash;
  
protected booleanlogFoundJars(java.util.Vector v, java.lang.String desc)
Print out report of .jars found in a classpath. Takes the information encoded from a checkPathForJars() call and dumps it out to our PrintWriter.

param
v Vector of Hashtables of .jar file info
param
desc description to print out in header
return
false if OK, true if any .jars were reported as having errors
see
#checkPathForJars(String, String[])


                                                                 
       
  

    if ((null == v) || (v.size() < 1))
      return false;

    boolean errors = false;

    logMsg("#---- BEGIN Listing XML-related jars in: " + desc + " ----");

    for (int i = 0; i < v.size(); i++)
    {
      Hashtable subhash = (Hashtable) v.elementAt(i);

      for (Enumeration keys = subhash.keys(); 
           keys.hasMoreElements();
           /* no increment portion */
          )
      {
        Object key = keys.nextElement();
        String keyStr = (String) key;
        try
        {
          if (keyStr.startsWith(ERROR))
          {
            errors = true;
          }
          logMsg(keyStr + "=" + subhash.get(keyStr));

        }
        catch (Exception e)
        {
          errors = true;
          logMsg("Reading-" + key + "= threw: " + e.toString());
        }
      }
    }

    logMsg("#----- END Listing XML-related jars in: " + desc + " -----");

    return errors;
  
protected voidlogMsg(java.lang.String s)
Bottleneck output: calls outWriter.println(s).

param
s String to print


                
     
  
    outWriter.println(s);
  
protected booleanwriteEnvironmentReport(java.util.Hashtable h)
Dump a basic Xalan environment report to outWriter.

This dumps a simple header and then each of the entries in the Hashtable to our PrintWriter; it does special processing for entries that are .jars found in the classpath.

param
h Hashtable of items to report on; presumably filled in by our various check*() methods
return
true if your environment appears to have no major problems; false if potential environment problems found
see
#appendEnvironmentReport(Node, Document, Hashtable) for an equivalent that appends to a Node instead


    if (null == h)
    {
      logMsg("# ERROR: writeEnvironmentReport called with null Hashtable");
      return false;
    }

    boolean errors = false;

    logMsg(
      "#---- BEGIN writeEnvironmentReport($Revision: 1.26 $): Useful stuff found: ----");

    // Fake the Properties-like output
    for (Enumeration keys = h.keys(); 
         keys.hasMoreElements();
        /* no increment portion */
        )
    {
      Object key = keys.nextElement();
      String keyStr = (String) key;
      try
      {
        // Special processing for classes found..
        if (keyStr.startsWith(FOUNDCLASSES))
        {
          Vector v = (Vector) h.get(keyStr);
          errors |= logFoundJars(v, keyStr);
        }
        // ..normal processing for all other entries
        else
        {
          // Note: we could just check for the ERROR key by itself, 
          //    since we now set that, but since we have to go 
          //    through the whole hash anyway, do it this way,
          //    which is safer for maintenance
          if (keyStr.startsWith(ERROR))
          {
            errors = true;
          }
          logMsg(keyStr + "=" + h.get(keyStr));
        }
      }
      catch (Exception e)
      {
        logMsg("Reading-" + key + "= threw: " + e.toString());
      }
    }

    logMsg(
      "#----- END writeEnvironmentReport: Useful properties found: -----");

    return errors;