5 Replies Latest reply on Aug 14, 2013 3:11 AM by ndubien

    Jboss AS 7 / Xalan unable to call user-defined functions ?

    ndubien

      Hi,

       

      I am wondering how I can use extensions written in Java with JBoss AS 7 and Xalan. It worked perfectely on my local JVM but failed as I used JBoss. The idea is to process a XSL+XML file with Xalan Transformer and user-defined functions written in Java.

       

      I know that the same question has been asked one year ago on this forum but nobody answered:

      https://community.jboss.org/message/763695#763695

       

      These are the tracebacks I got when I launched the transformation:

       

      2013/08/06 11:24:36.957 ncegcolnx JFS_REG APP XslfoErrorListener    ERROR [PFX: --XSL004.web-- - 0001] Trace details for com.tdm.service.jfs.app.engine.xslfo.XslfoEngine: TransformerFactory:

      #Exception: javax.xml.transform.TransformerException

      #Message: Cannot find class 'com.tdm.service.jfs.app.engine.xslfo.functions.XalanAddOns'.

      #Stack: javax.xml.transform.TransformerException: Cannot find class 'com.tdm.service.jfs.app.engine.xslfo.functions.XalanAddOns'.

          at org.apache.xalan.xsltc.trax.TransformerFactoryImpl.passErrorsToListener(TransformerFactoryImpl.java:661)
          at org.apache.xalan.xsltc.trax.TransformerFactoryImpl.newTemplates(TransformerFactoryImpl.java:836)
          at org.apache.xalan.xsltc.trax.TransformerFactoryImpl.newTransformer(TransformerFactoryImpl.java:618)
          at __redirected.__TransformerFactory.newTransformer(__TransformerFactory.java:129)
          at com.tdm.service.jfs.app.engine.xslfo.XslfoEngine.format(XslfoEngine.java:271)
          ...

       

      2013/08/06 11:24:36.959 ncegcolnx JFS_REG APP XslfoErrorListener    ERROR [PFX: --XSL004.web-- - 0001] Trace details for com.tdm.service.jfs.app.engine.xslfo.XslfoEngine: TransformerFactory:

      #Exception: javax.xml.transform.TransformerException

      #Message: Cannot find external method 'com.tdm.service.jfs.app.engine.xslfo.functions.XalanAddOns.doSmth' (must be public).

      #Stack: javax.xml.transform.TransformerException: Cannot find external method 'com.tdm.service.jfs.app.engine.xslfo.functions.XalanAddOns.doSmth' (must be public).

          at org.apache.xalan.xsltc.trax.TransformerFactoryImpl.passErrorsToListener(TransformerFactoryImpl.java:661)
          at org.apache.xalan.xsltc.trax.TransformerFactoryImpl.newTemplates(TransformerFactoryImpl.java:836)
          at org.apache.xalan.xsltc.trax.TransformerFactoryImpl.newTransformer(TransformerFactoryImpl.java:618)
          at __redirected.__TransformerFactory.newTransformer(__TransformerFactory.java:129)
          at com.tdm.service.jfs.app.engine.xslfo.XslfoEngine.format(XslfoEngine.java:271)
         

      ...

       

      My XSL file is quite simple and had been tested on a local JVM:

       

      <?xml version="1.0" encoding="utf-8"?>

      <xsl:stylesheet version="1.0"

          xmlns:xsl="http://www.w3.org/1999/XSL/Transform"

          xmlns:fo="http://www.w3.org/1999/XSL/Format"

          xmlns:addons="xalan://com.tdm.service.jfs.app.engine.xslfo.functions.XalanAddOns"

          extension-element-prefixes="addons" >

        <xsl:output method="xml" indent="yes"/>

        <xsl:template match="/">

          <fo:root>

            <fo:layout-master-set>

              <fo:simple-page-master master-name="A4-portrait" page-height="29.7cm" page-width="21.0cm" margin="5mm">

                <fo:region-body region-name="xsl-region-body" />

              </fo:simple-page-master>

              <fo:page-sequence-master master-name="default-sequence">

                  <fo:repeatable-page-master-reference master-reference="A4-portrait"/>

              </fo:page-sequence-master>

            </fo:layout-master-set>

            <fo:page-sequence master-reference="default-sequence">

              <fo:flow flow-name="xsl-region-body">

                  <fo:block color="#770199" font-size="9px" text-align="right" border-bottom="1px solid #A5A5A5" margin-bottom="5mm">

                      <xsl:value-of select="addons:doSmth()" />

                  </fo:block>

              </fo:flow>

            </fo:page-sequence>

          </fo:root>

        </xsl:template>

      </xsl:stylesheet>

       

      And my Java code is the following:

       

      267TransformerFactory tFactory = TransformerFactory.newInstance();
      268Transformer transformer = null;
      269tFactory.setErrorListener(xslfoErrorListenerFactory);
      270tFactory.setAttribute("debug", true);
      271transformer = tFactory.newTransformer(new StreamSource(_layoutPath + _layoutFileName));
      272transformer.setErrorListener(xslfoErrorListenerTransformer);
      273transformer.transform(new StreamSource(xmlInput), new StreamResult(xalanOutput));

       

      Thank you in advance for your answer.

      Best regards,

      Nicolas DUBIEN

        • 1. Re: Jboss AS 7 / Xalan unable to call user-defined functions ?
          sfcoy

          Try using javax.xml.transform.TransformerFactory#newInstance(java.lang.String, java.lang.ClassLoader), and pass it a classloader that has access to your custom java class such as:

           

               this.getClass().getClassLoader()

           

          I'll leave it as an exercise to figure out what to use for a factoryClassName.

           

          I'm not sure that this will work btw, but it's something to try.

          • 2. Re: Jboss AS 7 / Xalan unable to call user-defined functions ?
            ndubien

            Finally I found some kind of solution but it is still incomplete.

             

            I already had a module dubbed org.apache.xalan on my JBoss directory. So I added my extensions as a jar file into this directory, added the jar into dependencies and Xalan was able to use it.

            Here is the module.xml file I have on my Xalan module directory:

             

            <?xml version="1.0" encoding="UTF-8"?>

            <module xmlns="urn:jboss:module:1.1" name="org.apache.xalan">

                <resources>

                    <resource-root path="serializer-2.7.1.jbossorg-1.jar"/>

                    <resource-root path="xalan-2.7.1.jbossorg-1.jar"/>

                    <resource-root path="XalanAddOns.jar"/>

                </resources>

                <dependencies>

                    <module name="javax.api"/>

                    <module name="org.jboss.logging" />

                </dependencies>

            </module>

             

            I also had to had this module into the jboss-deployment-structure.xml:

             

            <?xml version="1.0" encoding="UTF-8"?>

            <jboss-deployment-structure>

                <deployment>

                    <dependencies>

                        <module name="org.apache.xalan" />

                    </dependencies>

                </deployment>

            </jboss-deployment-structure>

             

             

            I am still a bit annoying as I cannot really use such trick for my project as my XalanAddOns.jar has several dependencies of which a context inherent to the application itself. I am wondering if it can be possible to give this module the right to have a full access to my application classes.

             

            Thank you in advance for your answer.

            Best regards,

            Nicolas DUBIEN

            • 3. Re: Jboss AS 7 / Xalan unable to call user-defined functions ?
              ndubien

              As I explained it before, I am trying to add a dependency to my war file main application into xalan module.

              Here is the file structure I am using in my project:

               

              ./standalone/deployments/JFAS-3.3.5.0.war

              ./org/apache/xalan/main/*

               

              I added the following line to xalan module.xml:

               

              <module name="deployment.JFAS-3.3.5.0.war" optional="true" />

               

               

              I put the optional="true" argument otherwise JBoss Server did not start. But xalan module is still unable to load classes from the war file.

              I am wondering if the module name I put is correct.

              • 4. Re: Jboss AS 7 / Xalan unable to call user-defined functions ?
                sfcoy

                If you:

                1. Restore the original JBossAS/WildFly modules
                2. Remove the jboss-deployment-structure.xml file from your application
                3. Repackage your application as an EAR, where your have xalan.jar/serializer.jar in the EAR/lib directory, together with a jar containing the xalan extensions
                4. Create your TransformerFactory like: TransformerFactory tFactory = TransformerFactory.newInstance("org.apache.xalan.processor.TransformerFactoryImpl", this.class.getClassLoader());

                 

                then I think it will work for you. Your application would not normally have direct visibility of the xalan jars in JBossAS/WildFly, and it will use the one in the EAR instead. This copy of xalan will have visibility of your library code provided it is deployed in the EAR.

                 

                I don't believe you can accomplish this with just a WAR deployment because jars in the WEB-INF/lib directory will always be loaded before anything else, which can interfere with the server's XML parsers.

                • 5. Re: Jboss AS 7 / Xalan unable to call user-defined functions ?
                  ndubien

                  Hi Stephen,

                   

                  Thank you for your answers. I find another solution by trying several combinations.

                   

                  I linked the Xalan-jboss and Serializer-jboss libraries to my project. At the beginning it did not work because the provider was not found.

                   

                  Instead of using :

                   

                       System.setProperty("javax.xml.transform.TransformerFactory", "org.apache.xalan.processor.TransformerFactoryImpl");

                       TransformerFactory tFactory = TransformerFactory.newInstance();

                       Transformer transformer = tFactory.newTransformer();

                   

                  Which failed to find the provider even if it was given as a library - I am wondering if javax.xml.transformer used the same class loader - , I use :

                   

                       org.apache.xalan.processor.TransformerFactoryImpl tFactory = new org.apache.xalan.processor.TransformerFactoryImpl();

                       Transformer transformer = tFactory.newTransformer();

                   

                   

                  During my tests I tried to know which jar file was used to load the class in order to know exactely which problem I needed to tackle. As it helped me a bit, I think that maybe it could help other people. Here is a simplified example, I used it on stack traces to locate each Java class.

                   

                  java.lang.Throwable ex;

                  java.security.CodeSource codeSource = ex.getClass().getProtectionDomain().getCodeSource();

                  if(codeSource != null)

                       System.out.println(codeSource.getLocation());

                   

                  Regards,

                  Nicolas DUBIEN