Details

    • Type: Improvement Improvement
    • Status: Open
    • Priority: Major Major
    • Resolution: Unresolved
    • Affects Version/s: 2.1.0
    • Fix Version/s: None
    • Security Level: No security risk; visible to anyone (Ordinary problems in Xalan projects. Anybody can view the issue.)
    • Labels:
      None
    • Environment:
      Operating System: All
      Platform: PC

      Description

      import java.io.FileInputStream;
      import javax.xml.transform.Templates;
      import javax.xml.transform.sax.SAXTransformerFactory;
      import javax.xml.transform.sax.TransformerHandler;
      import javax.xml.transform.stream.StreamSource;
      import javax.xml.transform.stream.StreamResult;
      import org.xml.sax.helpers.AttributesImpl;

      public class Test {

      public static void main(String[] args) {
      try

      { SAXTransformerFactory f = (SAXTransformerFactory) SAXTransformerFactory.newInstance(); Templates t = f.newTemplates(new StreamSource(new FileInputStream("in.xsl"))); TransformerHandler th = f.newTransformerHandler(t); th.setResult(new StreamResult(System.out)); th.startDocument(); th.startElement("","foo","foo",new AttributesImpl()); th.endElement("","foo","foo"); th.endDocument(); th.startDocument(); th.startElement("","foo","foo",new AttributesImpl()); th.endElement("","foo","foo"); th.endDocument(); }

      catch(Exception e)

      { e.printStackTrace(); }

      }
      }

      If you run this code with any valid in.xsl file, the template is instantiated
      only once.
      It's true, that in JAXP-1.1 specification it is not explicitly stated that
      TransformerHandlers should be reusable, but it is stated that Transformers
      should be reusable, and my opinion is that it would be reasonable and natural
      to be able to reuse TransformerHandlers as well.

        Activity

        Hide
        Gary L Peskin added a comment -

        I'm not sure when you'd decide that you were done with the TransformerHandler.
        I might think endDocument() but couldn't you have a nested startDocument()
        somehow?

        In any event, I can suggest a possible workaround. Please post to bugzilla if
        it works (or doesn't).

        After your endDocument(), add:

        Transformer tr = th.getTransformer();
        if (tr instanceof TransformerImpl)
        tr.reset();

        Show
        Gary L Peskin added a comment - I'm not sure when you'd decide that you were done with the TransformerHandler. I might think endDocument() but couldn't you have a nested startDocument() somehow? In any event, I can suggest a possible workaround. Please post to bugzilla if it works (or doesn't). After your endDocument(), add: Transformer tr = th.getTransformer(); if (tr instanceof TransformerImpl) tr.reset();
        Hide
        slobo added a comment -

        I'm not sure when you'd decide that you were done with the TransformerHandler.
        I might think endDocument() but couldn't you have a nested startDocument()
        somehow?

        I think you have to know that you were done anyway, because that's the moment
        when you finish building the input-xml, start processing it, and emit the
        result xml.
        A nested startDocument() should be an (illegal state) error, just as with any
        ContentHandler.

        Show
        slobo added a comment - I'm not sure when you'd decide that you were done with the TransformerHandler. I might think endDocument() but couldn't you have a nested startDocument() somehow? I think you have to know that you were done anyway, because that's the moment when you finish building the input-xml, start processing it, and emit the result xml. A nested startDocument() should be an (illegal state) error, just as with any ContentHandler.
        Hide
        slobo added a comment -

        After your endDocument(), add:

        Transformer tr = th.getTransformer();
        if (tr instanceof TransformerImpl)
        tr.reset();

        I tested this workaround, and it produces the same result as without it (ie the
        template is instantiated only once).

        • o -

        If you think that TransformerHandlers should not be reused, it should at least
        throw an exception at the second startDocument(), explaining that it can not be
        reused. Now it silently ignores the second startDocument(), and everything
        after that, which is quite confusing.

        Show
        slobo added a comment - After your endDocument(), add: Transformer tr = th.getTransformer(); if (tr instanceof TransformerImpl) tr.reset(); I tested this workaround, and it produces the same result as without it (ie the template is instantiated only once). o - If you think that TransformerHandlers should not be reused, it should at least throw an exception at the second startDocument(), explaining that it can not be reused. Now it silently ignores the second startDocument(), and everything after that, which is quite confusing.
        Hide
        Shane Curcuru added a comment -
            • Bug 1156 has been marked as a duplicate of this bug. ***
        Show
        Shane Curcuru added a comment - Bug 1156 has been marked as a duplicate of this bug. ***
        Hide
        Shane Curcuru added a comment -

        Although I can see the comparison with Transformers (which clearly are meant to
        be reused) I think the more apt comparison is with a SAX ContentHandler, which
        generally are not reused - at least not without someone providing a reset() on
        their implementation of ContentHandler, which JAXP doesn't do.

        There are two potential questions here:
        – JAXP should perhaps document the specified behavior of TransformerHandlers
        in their next release. That's beyond our control, you need to look at
        http://java.sun.com/xml/jaxp.html if you want to influence JAXP itself (which
        Sun and the JCP own).

        – Xalan should be polite and let the user know that their TransformerHandler
        is no longer 'listening' after the endDocument() call. I'd consider this a
        useful enhancement to xalan, but not necessarily a very high priority (compared
        to a few other things on our list.
        Changed Pri/Sev to match.

        Show
        Shane Curcuru added a comment - Although I can see the comparison with Transformers (which clearly are meant to be reused) I think the more apt comparison is with a SAX ContentHandler, which generally are not reused - at least not without someone providing a reset() on their implementation of ContentHandler, which JAXP doesn't do. There are two potential questions here: – JAXP should perhaps document the specified behavior of TransformerHandlers in their next release. That's beyond our control, you need to look at http://java.sun.com/xml/jaxp.html if you want to influence JAXP itself (which Sun and the JCP own). – Xalan should be polite and let the user know that their TransformerHandler is no longer 'listening' after the endDocument() call. I'd consider this a useful enhancement to xalan, but not necessarily a very high priority (compared to a few other things on our list. Changed Pri/Sev to match.
        Hide
        Donald Leslie added a comment -

        Added the following note to "Basic Usage Patterns" (usagepatterns.html#sax):
        "If you want to perform multiple transformations with the same Templates object
        and a TransformerHandler, you must create a new TransformerHandler for each
        transformation. The Xalan-Java implementation of TransformerHandler
        (org.apache.xalan.transformer.TransformerHandlerImpl) fails to respond
        to events after the first endDocument event occurs."

        Show
        Donald Leslie added a comment - Added the following note to "Basic Usage Patterns" (usagepatterns.html#sax): "If you want to perform multiple transformations with the same Templates object and a TransformerHandler, you must create a new TransformerHandler for each transformation. The Xalan-Java implementation of TransformerHandler (org.apache.xalan.transformer.TransformerHandlerImpl) fails to respond to events after the first endDocument event occurs."
        Hide
        Joe Kesselman added a comment -

        Anyone object to marking this one as "fixed in documentation"?

        Show
        Joe Kesselman added a comment - Anyone object to marking this one as "fixed in documentation"?
        Hide
        Thomas Hallgren added a comment -

        This problem remains in version 2.4.0.

        The suggested call to TransformerImpl.reset() does not work. Not even if
        preceded with a call to TransformerImpl.setShouldReset(true).

        Creating a new TransformerHandler, even on a cached Template, seems to give a
        serious performance penalty.

        Why can't proper clean-up code be added to endDocument?

        Show
        Thomas Hallgren added a comment - This problem remains in version 2.4.0. The suggested call to TransformerImpl.reset() does not work. Not even if preceded with a call to TransformerImpl.setShouldReset(true). Creating a new TransformerHandler, even on a cached Template, seems to give a serious performance penalty. Why can't proper clean-up code be added to endDocument?
        Hide
        Pavel Ausianik added a comment -

        TranformImpl can be reused, and I think it get's most time of inittialization process
        of call

        TransformerHandler th = f.newTransformerHandler(t);

        If you look into the source of the TransformerFactoryImpl, you'll found that this call
        is equivalent of

        TransformerHandler th =
        transformer.getInputContentHandler(true);

        So, use Transfoer, do reset for transformer, but crearte new Transformer handler
        from call
        transformer.getInputContentHandler(true);

        Best regards,
        Pavel

        Show
        Pavel Ausianik added a comment - TranformImpl can be reused, and I think it get's most time of inittialization process of call TransformerHandler th = f.newTransformerHandler(t); If you look into the source of the TransformerFactoryImpl, you'll found that this call is equivalent of TransformerHandler th = transformer.getInputContentHandler(true); So, use Transfoer, do reset for transformer, but crearte new Transformer handler from call transformer.getInputContentHandler(true); Best regards, Pavel
        Hide
        Thomas Hallgren added a comment -

        Thanks Pavel,
        I tried your suggestion but I can't get it to work. Here's why.

        Calling reset() and then getInputContentHandler() on a TransformerImpl that's
        not brand new, yields the same result as before. NullPointerException the
        second time.

        Looking at the source for newTransformerHandler, I can see that this code
        creates a new Transformer every time (using a Template). So even if it does
        call getInputContentHandler(), it does this on a fresh TransformerImpl.

        Should I get to work, the code will break if I use a
        org.apache.xalan.xsltc.trax.TransformerImpl since I'm forced to use an explicit
        implementation rather than standard JAXP. Right now, I'm happy to circumvein
        this using "instanceof" or something but it sure would be nice to have a
        working JAXP implementation.

        I made some performance measurements (not very scientific, I run 1000
        transformations in a loop and measure using System.currentTimeMillis).

        Using Xalan 2.4.0 and XSLTC, the average time for a transformation on my laptop
        is 14 millisecs with a fairly simple XSL. 10 millisecs (> 70%) is spent in
        TransformerFactory.newTransformerHandler(Templates tps)! If I don't use XSLT,
        the corresponding numbers are 20 millisecs per transformation, still with 10
        millisecs in the call to newTransformerHandler() (50%). So there really is a
        need for a reusable TransformerHandler or for some serious performance
        optimizations in the reuse of templates.

        Show
        Thomas Hallgren added a comment - Thanks Pavel, I tried your suggestion but I can't get it to work. Here's why. Calling reset() and then getInputContentHandler() on a TransformerImpl that's not brand new, yields the same result as before. NullPointerException the second time. Looking at the source for newTransformerHandler, I can see that this code creates a new Transformer every time (using a Template). So even if it does call getInputContentHandler(), it does this on a fresh TransformerImpl. Should I get to work, the code will break if I use a org.apache.xalan.xsltc.trax.TransformerImpl since I'm forced to use an explicit implementation rather than standard JAXP. Right now, I'm happy to circumvein this using "instanceof" or something but it sure would be nice to have a working JAXP implementation. I made some performance measurements (not very scientific, I run 1000 transformations in a loop and measure using System.currentTimeMillis). Using Xalan 2.4.0 and XSLTC, the average time for a transformation on my laptop is 14 millisecs with a fairly simple XSL. 10 millisecs (> 70%) is spent in TransformerFactory.newTransformerHandler(Templates tps)! If I don't use XSLT, the corresponding numbers are 20 millisecs per transformation, still with 10 millisecs in the call to newTransformerHandler() (50%). So there really is a need for a reusable TransformerHandler or for some serious performance optimizations in the reuse of templates.
        Hide
        Pavel Ausianik added a comment -

        Thomas,

        Sorry, my analysis was incorrect. New ContentHandler is only created if it was not
        created before. The code uin reset() function were ContentHandler is assigned to
        null is commented out, somewhere around version 100 of TransformerImpl.jva. You
        may try to create custom copy of xalan, by uncomment this line (515 in current
        version)

        // m_inputContentHandler = null;

        Pavel

        Show
        Pavel Ausianik added a comment - Thomas, Sorry, my analysis was incorrect. New ContentHandler is only created if it was not created before. The code uin reset() function were ContentHandler is assigned to null is commented out, somewhere around version 100 of TransformerImpl.jva. You may try to create custom copy of xalan, by uncomment this line (515 in current version) // m_inputContentHandler = null; Pavel
        Hide
        Thomas Hallgren added a comment -

        Thanks Pavel,
        I uncommented the line and it works like a charm. It's much faster too. Only 2
        millisecs spent in getInputContentHandler() and for some reason, the actual
        time to transform sunk from 10 to 7 millisecs, i.e. 9 ms in all! I hope it
        still does the right thing

        I added a similar method to the org.apache.xalan.xsltc.trax.TransformerImpl.

        public ContentHandler getInputContentHandler()

        { return new TransformerHandlerImpl(this); }

        This works too but it's slow. On average the trax transformation still takes 14
        ms.

        Show
        Thomas Hallgren added a comment - Thanks Pavel, I uncommented the line and it works like a charm. It's much faster too. Only 2 millisecs spent in getInputContentHandler() and for some reason, the actual time to transform sunk from 10 to 7 millisecs, i.e. 9 ms in all! I hope it still does the right thing I added a similar method to the org.apache.xalan.xsltc.trax.TransformerImpl. public ContentHandler getInputContentHandler() { return new TransformerHandlerImpl(this); } This works too but it's slow. On average the trax transformation still takes 14 ms.
        Hide
        Henry Zongaro added a comment -
            • Bug 17345 has been marked as a duplicate of this bug. ***
        Show
        Henry Zongaro added a comment - Bug 17345 has been marked as a duplicate of this bug. ***

          People

          • Assignee:
            Unassigned
            Reporter:
            slobo
          • Votes:
            5 Vote for this issue
            Watchers:
            0 Start watching this issue

            Dates

            • Created:
              Updated:

              Development