Wednesday 5 August 2009

How to fix the Glassfish Admin App

Recently we've been having intermittant issues with the GlassFish 2.1 (b.60e) Web Administration Console. The behaviour is that after successfully login you get a HTTP 500 error instead of the web app As follows (minus colours)

HTTP Status 500 - type Exception report

message
descriptionThe server encountered an internal error () that prevented it from fulfilling this request.

exception
javax.servlet.ServletException: java.lang.reflect.InvocationTargetException while attempting to process a 'beforeCreate' event for 'sun_frameSet4'.

root cause
java.lang.RuntimeException: java.lang.reflect.InvocationTargetException while attempting to process a 'beforeCreate' event for 'sun_frameSet4'.

root cause
java.lang.reflect.InvocationTargetException

root cause
javax.xml.transform.TransformerFactoryConfigurationError: Provider org.apache.xalan.processor.TransformerFactoryImpl not found

note The full stack traces of the exception and its root causes are available in the Sun GlassFish Enterprise Server v2.1 logs.
Sun GlassFish Enterprise Server v2.1

At first we were told it was a jar class but I was skeptical as the appserver should keep those isolated from one application to another, however there is something I overlooked that creeps across applications which is the System Properties which are across the JVM.

In the end the issue is down to how the TransformerFactory creates a new instance which uses system properties, more details follow:

Issue:
The Admin app breaks displaying the http 500 error after a successful logon when the javax.xml.transform.TransformerFactory system property is set to a class that is not in its classpath.

Rationale:
This is due to the way that the TransformerFactory is implemented which the Admin app calls to get an XML parser.

To get an XML parser javax.xml.transform.TransformerFactory.newInstance()is called and this uses the following ordered lookup procedure to determine the TransformerFactory implementation class to load:

  • 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 JAXP implementation and it's 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 a classname in the file META-INF/services/javax.xml.transform.TransformerFactory in jars available to the runtime.
  • Platform default TransformerFactory instance.

see http://java.sun.com/j2se/1.5.0/docs/api/javax/xml/transform/TransformerFactory.html#newInstance()

System Setting are across the JVM and by default the javax.xml.transform.TransformerFactory system property is not set.

Fix:
Remove the javax.xml.transform.TransformerFactory system property and use one of the other methods to determine the TransformerFactory implementation class