Friday, October 10, 2008

JAXP + Java Endorsed Packages

In this post I summarized XML related stuff. After all JAXP was constructed with the hope to unify interface.
Here is a very good FAQ about JAXP.

Pluggability
Pluggability is necessary so that programmers can choose the desired implementations of JAXP.
From the JAXP specification, I found the lookup procedure. For XSLT, the procedure is:

• Use the javax.xml.transform.TransformerFactory system property
• Use the properties file "lib/jaxp.properties" in the JRE directory. This configuration file is in standard java.util.Properties format and contains the fully qualified name of the implementation class with the key being the system property defined above. The jaxp.properties file is read only once by the JSR-000206 Java™API for XML Processing (“Specification”) implementation and its values are then cached for future use. If the file does not exist when the first attempt is made to read from it, no further attempts are made to check for its existence. It is not possible to change the value of any property in jaxp.properties after it has been read for the first time.
• Use the Services API (as detailed in the JAR specification), if available, to determine the classname.
The Services API will look for the classname in the file META-INF/services/javax.xml.transform.TransformerFactory
in jars available to the runtime.
• Platform default TransformerFactory instance.

It seems that the #3 option is used mostly. If you download an implementation jar (xalan.jar or xerces-api.jar...), you should be able to find the corresponding file META-INF/services/javax.xml.xxx.xxx.

Problem with Java SE 1.4
However, there is a problem for Java 1.4. It bundled in an implementation of JAXP 1.1 from Apache. Unfortunately, the developers did not change the package names. Even if you downloads and uses a newer version of package from Apache, none of the plug-in options described above works because the class loader always uses the built-in implementation.

Solution
Then two solutions are provided:
(1) Change the package names to other internal package names (e.g. com.sun.org.apache.*)
This is what Sun does in later Java SE releases.
(2) For old Java SE, Endorsed override mechanism can be used.
Java 5 Endorsed Standard: http://java.sun.com/j2se/1.5.0/docs/guide/standards/index.html.
Users can specify the endorsed package path by setting system property - java.endorsed.dirs.
The default path is: <jre-home>/lib/endorsed
On my machine, the path is /usr/java/jdk1.5.0_09/jre/lib/endorsed.
Information about system properties can be accessed here http://java.sun.com/docs/books/tutorial/essential/environment/sysprop.html.
Also I found a very simple program on the web to list all system properties:

public class DisplaySystemProps {
    public static void main(String[] args) {
         System.getProperties().list(System.out);
    }
}
Then you can check the properties you are interested in, such as user home directory, java home, vm version, java class version, path separator, file separator...

Tomcat
For old tomcat releases which rely on old versions of Java, users can put XML parser  into CATALINA_HOME/common/lib.
But for latest versions, it does not work. Read http://tomcat.apache.org/tomcat-6.0-doc/class-loader-howto.html for more information.

"Classes which are part of the JRE base classes cannot be overriden. For some classes (such as the XML parser components in J2SE 1.4+), the J2SE 1.4 endorsed feature can be used.
In previous versions of Tomcat, you could simply replace the XML parser in the $CATALINA_HOME/common/lib directory to change the parser used by all web applications. However, this technique will not be effective when you are running on JSE 5, because the usual class loader delegation process will always choose the implementation inside the JDK in preference to this one.
Tomcat utilizes this mechanism by including the system property setting -Djava.endorsed.dirs=$JAVA_ENDORSED_DIRS in the command line that starts the container."
In other words, users MUST use Endorsed override mechanism to use another XML parser/XSLT in Tomcat. See this post for more information.