Robby,
could you please open an issue on JIRA and attach the patch you are currently working on?
Maybe I could help but I need to have your exact situation.

Regards.

On 07/12/2012 16:21, Robby Pelssers wrote:
Just for the sake of it.... You wouldn't run into this issue if you set the 
system property and just left the factoryclassname null.

META-INF/services/javax.xml.transform.TransformerFactory

Because in that case TRAX_FACTORY will ALWAYS create a new instance using the 
same TransformerFactory implementation.

Robby

-----Original Message-----
From: Robby Pelssers [mailto:[email protected]]
Sent: Friday, December 07, 2012 4:12 PM
To: [email protected]
Subject: possible design flaw in linking of pipelines (C3)

Hi guys,

Sorry if I make unnecessary noise here due to my incompetence. But I was trying 
to refactor
org.apache.cocoon.sax.component.XSLTTransformer by enabling users to choose a transfomerfactory of their choice. I added a new constructor and did some basic refactoring.

     public XSLTTransformer(final URL source, final Map<String, Object> 
attributes, final String factoryClassName) {
         super();
         this.loadXSLT(source, attributes, factoryClassName);
     }


private void loadXSLT(final URL source, final Map<String, Object> attributes, 
final String factoryClassName) {
     ....
             SAXTransformerFactory transformerFactory;
             if (factoryClassName != null) {
                 //we need to use factoryclassname
                 transformerFactory = 
createNewSAXTransformerFactory(factoryClassName, null);
             } else {
                 //we need to check for attributes
                 if (attributes == null || attributes.isEmpty()) {
                     //we can use static factory
                     transformerFactory = TRAX_FACTORY;
                 } else {
                     //we need to instantiate new default factory
                     transformerFactory = createNewSAXTransformerFactory();
                 }
             }
    ....
}

     private static SAXTransformerFactory createNewSAXTransformerFactory() {
         return (SAXTransformerFactory) TransformerFactory.newInstance();
     }

     private static SAXTransformerFactory createNewSAXTransformerFactory(final 
String factoryClassName, final ClassLoader classLoader) {
        return (SAXTransformerFactory) 
TransformerFactory.newInstance(factoryClassName, classLoader);
     }



But then I hit a brick wall while running the unit test below:

     public void testPipelineWithMultipleXSLTProcessors() throws Exception {
          newCachingPipeline()
              .setStarter(new 
XMLGenerator(getClass().getResource("/movies.xml")))
              .addComponent(new 
XSLTTransformer(this.getClass().getResource("/moviesByDirector.xslt"), null, 
"net.sf.saxon.TransformerFactoryImpl"))
              .addComponent(new 
XSLTTransformer(this.getClass().getResource("/indent.xslt"), null, 
"org.apache.xalan.processor.TransformerFactoryImpl"))
              .setFinisher(new XMLSerializer())
              .withEmptyConfiguration()
              .setup(System.out)
              .execute();
     }


Don’t look at linenumbers as I have different code now of course (and I added 
saxon as dependency to test this):

org.apache.cocoon.pipeline.SetupException: Could not initialize transformer 
handler.
        at 
org.apache.cocoon.sax.component.XSLTTransformer.setSAXConsumer(XSLTTransformer.java:247)
        at 
org.apache.cocoon.sax.AbstractSAXProducer.setConsumer(AbstractSAXProducer.java:39)
        at 
org.apache.cocoon.pipeline.AbstractPipeline.linkComponents(AbstractPipeline.java:214)
        at 
org.apache.cocoon.pipeline.AbstractPipeline.setupComponents(AbstractPipeline.java:187)
        at 
org.apache.cocoon.pipeline.AbstractPipeline.setup(AbstractPipeline.java:132)
        at 
org.apache.cocoon.pipeline.CachingPipeline.setup(CachingPipeline.java:183)
        at 
org.apache.cocoon.pipeline.AbstractPipeline.setup(AbstractPipeline.java:118)
        at 
org.apache.cocoon.pipeline.builder.PipelineBuilder$1$1$1$1.setup(PipelineBuilder.java:122)
        at 
org.apache.cocoon.sax.PipelineTest.testPipelineWithMultipleXSLTProcessors(PipelineTest.java:83)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at 
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
        at 
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
        at 
org.junit.internal.runners.JUnit38ClassRunner.run(JUnit38ClassRunner.java:83)
        at org.junit.runner.JUnitCore.run(JUnitCore.java:157)
        at 
com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:76)
        at 
com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:195)
        at 
com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:63)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at 
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
        at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)
Caused by: java.lang.ClassCastException: net.sf.saxon.Controller cannot be cast 
to org.apache.xalan.xsltc.trax.TransformerImpl
        at 
org.apache.xalan.xsltc.trax.TransformerFactoryImpl.newTransformerHandler(TransformerFactoryImpl.java:928)
        at 
org.apache.cocoon.sax.component.XSLTTransformer.setSAXConsumer(XSLTTransformer.java:245)
        ... 30 more


This is probably due to

     @Override
     protected void setSAXConsumer(final SAXConsumer consumer) {
         TransformerHandler transformerHandler;
         try {
             transformerHandler = 
TRAX_FACTORY.newTransformerHandler(this.templates);
         } catch (Exception e) {
             throw new SetupException("Could not initialize transformer 
handler.", e);
         }
         ...
      }

I think we shouldn’t just ALWAYS create a new transformerhandler using the 
default TRAX_FACTORY but it should the same SAXTransformerFactory we created in 
loadXSLT.

But setSAXConsumer is called from within AbstractPipeline.setConsumer which 
again translates to AbstractSAXProducer.setConsumer which sets the SaxConsumer.


mmmm....   Anyone who is expert in this matter?

Robby

--
Francesco Chicchiriccò

ASF Member, Apache Syncope PMC chair, Apache Cocoon PMC Member
http://people.apache.org/~ilgrosso/

Reply via email to