JDK-5047031 : Tiger's XSLTC uses DocumentBuilderFactory lookup for each NodeList result
  • Type: Bug
  • Component: xml
  • Sub-Component: javax.xml.transform
  • Affected Version: 1.2.3
  • Priority: P4
  • Status: Resolved
  • Resolution: Fixed
  • OS: windows_xp
  • CPU: x86
  • Submitted: 2004-05-13
  • Updated: 2012-04-25
  • Resolved: 2004-06-06
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
Other
1.3.0 1.3Fixed
Description
Name: gm110360			Date: 05/13/2004


FULL PRODUCT VERSION :
1.5.0-beta-b32c

ADDITIONAL OS VERSION INFORMATION :
Windows XP (5.1, Build 2600.xpsp2.030...)

A DESCRIPTION OF THE PROBLEM :
[Note: I posted this against JAXP 1.2.3 as there is no selection for Tiger]

I'm using Tiger's XSLTC with extension functions. One of my functions returns a org.w3c.dom.NodeList which XSLTC translates into a an internal DOM iterator (see com.sun.org.apache.xalan.internal.xsltc.runtime.BasisLibrary#nodeList2Iterator).

This method is called after each invocation of the extension function.  Each time it will locate a Dom implementation through the JAXP factory interface. This is a very expensive operation as it searches through the whole classpath. It actually dominates processing time, as I can see when doing threaddumps.

After replacing that code to create a new org.apache.xerces.dom.DocumentImpl, I got a factor of 5 higher transformation throughput. In a setting with more complicated classloaders as in a J2EE container, the impact is likely to be even higher.



STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
  From a stylesheet, call an extension function that returns a NodeList:
<xsl:template match="*">
  <xsl:copy-of select="java:my.Class.function()" />
</xsl:template>

with

Class {
  static final NodeList result = DocumentBuilder.newInstance().newDocument().createDocumentFragment().getChildNodes();
  public static NodeList function() {
    return result;
  }
}

Call this transformation in a loop. Do threaddumps.



EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Speedy transformations. No anomalies in the stack traces.
ACTUAL -
Transformation was rather slow (1.6ms). After the proposed change it was down to 0.4ms

The following fragment was dominating the processing time:

"main" prio=5 tid=0x0003e210 nid=0x874 runnable [0x0007e000..0x0007fc3c]
	at java.io.BufferedReader.<init>(BufferedReader.java:91)
	at org.apache.xerces.util.ObjectFactory.findJarServiceProvider(Unknown Source)
	at org.apache.xerces.util.ObjectFactory.createObject(Unknown Source)
	at org.apache.xerces.util.ObjectFactory.createObject(Unknown Source)
	at org.apache.xerces.parsers.DOMParser.<init>(Unknown Source)
	at org.apache.xerces.parsers.DOMParser.<init>(Unknown Source)
	at org.apache.xerces.jaxp.DocumentBuilderImpl.<init>(Unknown Source)
	at org.apache.xerces.jaxp.DocumentBuilderFactoryImpl.newDocumentBuilder(Unknown Source)
	at com.sun.org.apache.xalan.internal.xsltc.runtime.BasisLibrary.nodeList2Iterator(BasisLibrary.java:1172)
	at GregorSamsa.template$dot$0()




REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
/*
 * Copyright (c) 2004 CoreMedia AG, Hamburg. All rights reserved.
 */
package test;

import org.w3c.dom.NodeList;

import javax.xml.transform.Templates;
import javax.xml.transform.TransformerException;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import java.io.ByteArrayOutputStream;
import java.io.StringReader;


public class XsltPerformance {
  public static void main(String[] args) throws TransformerException {
    String xml = "<root/>";
    String xsl =
	    "<xsl:transform version=\"1.0\"\n" +
	    "  xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\"\n" +
	    "  xmlns:java=\"http://xml.apache.org/xalan/java\"\n" +
	    "  exclude-result-prefixes=\"java\"\n" +
	    "  >" +
	    " <xsl:template match=\"/\">" +
	    "   <xsl:copy-of select=\"java:test.XsltPerformance.empty()\"/> "+
	    " </xsl:template>"+
	    "</xsl:transform>";

    Templates templates = new com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl().newTemplates(new StreamSource(new StringReader(xsl)));

    while(true) {
      StreamResult devNull = new StreamResult(new ByteArrayOutputStream());

      long start = System.currentTimeMillis();
      for(int i=0; i<1000; i++) {
        templates.newTransformer().transform(new StreamSource(new StringReader(xml)), devNull);
      }
      System.out.println(System.currentTimeMillis()-start);
    }
  }

  static final NodeList EMPTY = new com.sun.org.apache.xerces.internal.dom.DocumentImpl().createDocumentFragment().getChildNodes();
  public static NodeList empty() {
    return EMPTY;
  }
}

---------- END SOURCE ----------
(Incident Review ID: 265357) 
======================================================================

Comments
CONVERTED DATA BugTraq+ Release Management Values COMMIT TO FIX: 1.3 tiger-rc FIXED IN: 1.3 tiger-rc INTEGRATED IN: 1.3 tiger-b55 tiger-rc
2004-07-08

EVALUATION A DOMImplementation is now cached for even better performance. Translet now stores a reference to the DocumentBuilderFactory which is used by NodeList2Iterator() in the BasisLibrary. Bug has been fixed in Apache and main-trunk of xalan internal workspace. ###@###.### 2004-05-27
2004-05-27