Javax Transformer fails on high concurrent environment

1.6k views Asked by At

I have a platform with a Singleton Bean where I load a Transformer instance (because the xslt is so big to create an instance on every request) .

At normal load everything works fine , but making a stress test with a huge number of concurrent requests the transformer starts to throw an ArrayIndexOutOfBoundsException and stops working so I have to restart my server instance or redeploy the application.

This is the way I create my instance when the application is deployed:

private Transformer createCFDI33TransformerInstance() {

            InputStream in = new URL("http://www.sat.gob.mx/sitio_internet/cfd/3/cadenaoriginal_3_3/cadenaoriginal_3_3.xslt").openStream();

            TransformerFactory factory = TransformerFactory.newInstance();            
            Transformer transformer
                    = factory.newTransformer(new StreamSource(in));
            Logger.getLogger(PadeSingleton.class.getName()).log(Level.INFO, " Se ha cargado la instancia de XSLT");
            return transformer;
        } catch (TransformerConfigurationException | IOException ex) {
// Loading a remote instance was not possible so I will load a local instance
            Logger.getLogger(PadeSingleton.class.getName()).log(Level.SEVERE, "No fue posible cargar una nueva instancia de cadena original, se usara la del sistema", ex);
            InputStream in = CFDIv33Tools.class.getClassLoader()
                    .getResourceAsStream("com/soft/cadenaoriginal_3_3.xslt");

            TransformerFactory factory = TransformerFactory.newInstance();
            Transformer transformer;
            try {
                transformer = factory.newTransformer(new StreamSource(in));
                Logger.getLogger(PadeSingleton.class.getName()).log(Level.WARNING, "No fue posible cargar la instancia, se cargara una local");
            } catch (TransformerConfigurationException ex1) {
                Logger.getLogger(PadeSingleton.class.getName()).log(Level.SEVERE, null, ex1);
                // Estamos en problemas 
                throw new Exception("Error critico");
            }
            return transformer;
        }
    }

So in other bean I inject my Singleton Bean and call a method to get my Transformer instance.

public static String transform(String xml, Transformer instance) throws Exception {

        StringWriter writer = new StringWriter();

        try {

            instance.transform(new StreamSource(new StringReader(xml)), new StreamResult(writer));

        } catch (TransformerException e) {
            throw new Exception("El comprobante contiene simbolos no permitidos o esta mal formado", e);
        }

        return writer.toString();
    }

In this method is where I get an ArrayIndexOutOfBoundsException

Caused by: javax.xml.transform.TransformerException: java.lang.ArrayIndexOutOfBoundsException: -1
    at com.sun.org.apache.xalan.internal.xsltc.trax.TransformerImpl.transform(TransformerImpl.java:746)
    at com.sun.org.apache.xalan.internal.xsltc.trax.TransformerImpl.transform(TransformerImpl.java:351)
    at com.icontech.pade.common.xml.tools.CFDIv33Tools.calcularCadenaOriginalV2(CFDIv33Tools.java:93)
    ... 138 more

I repeat this happens when I making a stress test, when this exception is throwed the following requests fails with this same exception. I suppose my instance is corrupted.. or something.

1

There are 1 answers

0
Michael Kay On BEST ANSWER

The Transformer is not thread-safe. You should create a single Templates object representing the compiled stylesheet, and then instantiate a new Transformer object for each transformation.

(In principle the Transformer is serially reusable, so you could reuse a transformer within the same thread once one transformation is finished. I don't know if there are any benefits in doing that with Xalan; in the case of Saxon, it's better to create a new Transformer each time.)