[jboss-svn-commits] JBL Code SVN: r30951 - in labs/jbossesb/branches/JBESB_4_7_CP/product/rosetta: tests/src/org/jboss/soa/esb/actions/transformation/xslt and 1 other directory.

jboss-svn-commits at lists.jboss.org jboss-svn-commits at lists.jboss.org
Tue Jan 5 20:22:41 EST 2010


Author: beve
Date: 2010-01-05 20:22:41 -0500 (Tue, 05 Jan 2010)
New Revision: 30951

Modified:
   labs/jbossesb/branches/JBESB_4_7_CP/product/rosetta/src/org/jboss/soa/esb/actions/transformation/xslt/XsltAction.java
   labs/jbossesb/branches/JBESB_4_7_CP/product/rosetta/tests/src/org/jboss/soa/esb/actions/transformation/xslt/XsltActionUnitTest.java
Log:
Work for https://jira.jboss.org/jira/browse/JBESB-3098 "Provide a pool of transformers in XsltAction"


Modified: labs/jbossesb/branches/JBESB_4_7_CP/product/rosetta/src/org/jboss/soa/esb/actions/transformation/xslt/XsltAction.java
===================================================================
--- labs/jbossesb/branches/JBESB_4_7_CP/product/rosetta/src/org/jboss/soa/esb/actions/transformation/xslt/XsltAction.java	2010-01-05 20:19:50 UTC (rev 30950)
+++ labs/jbossesb/branches/JBESB_4_7_CP/product/rosetta/src/org/jboss/soa/esb/actions/transformation/xslt/XsltAction.java	2010-01-06 01:22:41 UTC (rev 30951)
@@ -20,10 +20,12 @@
  */
 package org.jboss.soa.esb.actions.transformation.xslt;
 
+import static org.jboss.soa.esb.listeners.ListenerTagNames.MAX_THREADS_TAG;
 import java.io.IOException;
 import java.io.InputStream;
 import java.util.Map;
 import java.util.Map.Entry;
+import java.util.concurrent.ArrayBlockingQueue;
 
 import javax.xml.parsers.ParserConfigurationException;
 import javax.xml.parsers.SAXParserFactory;
@@ -51,6 +53,7 @@
 import org.jboss.soa.esb.actions.transformation.xslt.ResultFactory.ResultType;
 import org.jboss.soa.esb.actions.transformation.xslt.TransformerFactoryConfig.Builder;
 import org.jboss.soa.esb.helpers.ConfigTree;
+import org.jboss.soa.esb.listeners.ListenerTagNames;
 import org.jboss.soa.esb.listeners.message.MessageDeliverException;
 import org.jboss.soa.esb.message.Message;
 import org.jboss.soa.esb.message.MessagePayloadProxy;
@@ -149,6 +152,18 @@
     private MessagePayloadProxy payloadProxy;
     
     /**
+     * The number of transformer instances to create upon initialization.
+     * This will be the value of the {@link ListenerTagNames#MAX_THREADS_TAG} value.
+     */
+    private int transformerPoolSize;
+    
+    /**
+     * A queue of Transformer instance which will be populated upon initialization.
+     * The size of this queue will be that of {@link #transformerPoolSize}.
+     */
+    private ArrayBlockingQueue<Transformer> transformers;
+    
+    /**
      * Sole constructor that parses the passed-in {@link ConfigTree} for 
      * mandatory attributes and sets the fields of this instance.
      * 
@@ -161,9 +176,42 @@
         transformerConfig = createConfig(config);
         failOnWarning = config.getBooleanAttribute("failOnWarning", true);
         payloadProxy = new MessagePayloadProxy(config);
+        transformerPoolSize = getMaxThreadsFromParentConfigTree(config);
     }
     
     /**
+     * Will try to extract and parse a configuration attribute named {@link ListenerTagNames#MAX_THREADS_TAG}
+     * from the parent of the passed-in ConfigTree instance. If no parent exists, that is the ConfigTree 
+     * instance passed into this method is the root, then the same attribute is extracted and parsed
+     * into an integer but from the config element.
+     * 
+     * @param config The {@link ConfigTree} instance.
+     * @return int The parsed value the {@link ListenerTagNames#MAX_THREADS_TAG} configuration attribute
+     * @throws ConfigurationException If it was not possible to parse the {@link ListenerTagNames#MAX_THREADS_TAG} attribute into a
+     * positive integer value.
+     */
+    int getMaxThreadsFromParentConfigTree(final ConfigTree config) throws ConfigurationException
+    {
+        try
+        {
+            final ConfigTree parent = config.getParent();
+            final String maxThreadsStr = parent != null ?
+                    parent.getRequiredAttribute(MAX_THREADS_TAG): 
+                    config.getRequiredAttribute(MAX_THREADS_TAG);
+                
+	        int maxThreads = Integer.parseInt(maxThreadsStr);
+	        if (maxThreads <= 0)
+	            throw new ConfigurationException(MAX_THREADS_TAG + " must be a positive integer. Was [" + maxThreads +"]");
+	        
+	        return maxThreads;
+        }
+        catch (final NumberFormatException e)
+        {
+            throw new ConfigurationException("Could not parse " + MAX_THREADS_TAG + " to an int.", e);
+        }
+    }
+    
+    /**
      * Performs the xsl transformation of the message payload.
      * 
      * @param message The ESB {@link Message} object whose payload should be transformed.
@@ -177,7 +225,6 @@
         AssertArgument.isNotNull(message, "message");
         try
         {
-            final Transformer transformer = xslTemplate.newTransformer();
             final Object payload = getPayload(message);
             final ValidationHandler validationHandler;
             final Source source;
@@ -198,7 +245,7 @@
             }
             
             // Perform the transformation.
-            transformer.transform(source, result);
+            transform(source, result);
             
             // Check for validation errors.
             if (validationHandler != null)
@@ -229,6 +276,36 @@
         }
     }
 
+    private void transform (final Source source, final Result result) throws TransformerException, ActionProcessingException
+    {
+        Transformer transformer = null;
+        try
+        {
+            transformer = transformers.take();
+        }
+        catch (final InterruptedException e)
+        {
+            throw new ActionProcessingException(e.getMessage(), e);
+        }
+        
+        try
+        {
+            transformer.transform(source, result);
+        }
+        finally
+        {
+            try
+            {
+                transformer.reset();
+                transformers.put(transformer);
+            }
+            catch (final InterruptedException e)
+            {
+                throw new ActionProcessingException(e.getMessage(), e);
+            }
+        }
+    }
+
     /**
      * Creates the XSLTemplate.
      * 
@@ -247,6 +324,12 @@
             setErrorListener(new TransformerListener(failOnWarning), factory);
             createValidationFactory(factory);
             xslTemplate = createTemplate(transformerConfig.getTemplateFile(), factory);
+            
+            transformers = new ArrayBlockingQueue<Transformer>(transformerPoolSize);
+            for (int i = transformerPoolSize; --i>=0 ;)
+            {
+                transformers.add(xslTemplate.newTransformer());
+            }
         } 
         catch (final TransformerConfigurationException e)
         {
@@ -521,4 +604,12 @@
     		throw exception;
     	}
     }
+
+    public int getNumberOfPooledTransfomers ()
+    {
+        if (transformers == null)
+            throw new IllegalStateException("The transformers have not been initialized yet. Please make sure that initialize has bee called prior to calling this method.");
+        
+        return transformers.size();
+    }
 }

Modified: labs/jbossesb/branches/JBESB_4_7_CP/product/rosetta/tests/src/org/jboss/soa/esb/actions/transformation/xslt/XsltActionUnitTest.java
===================================================================
--- labs/jbossesb/branches/JBESB_4_7_CP/product/rosetta/tests/src/org/jboss/soa/esb/actions/transformation/xslt/XsltActionUnitTest.java	2010-01-05 20:19:50 UTC (rev 30950)
+++ labs/jbossesb/branches/JBESB_4_7_CP/product/rosetta/tests/src/org/jboss/soa/esb/actions/transformation/xslt/XsltActionUnitTest.java	2010-01-06 01:22:41 UTC (rev 30951)
@@ -20,6 +20,7 @@
  */
 package org.jboss.soa.esb.actions.transformation.xslt;
 
+import static java.util.concurrent.TimeUnit.NANOSECONDS;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
@@ -49,8 +50,10 @@
 import org.jboss.soa.esb.actions.ActionProcessingException;
 import org.jboss.soa.esb.actions.transformation.xslt.ResultFactory.ResultType;
 import org.jboss.soa.esb.helpers.ConfigTree;
+import org.jboss.soa.esb.listeners.ListenerTagNames;
 import org.jboss.soa.esb.message.Message;
 import org.jboss.soa.esb.message.format.MessageFactory;
+import org.junit.Ignore;
 import org.junit.Test;
 import org.xml.sax.SAXException;
 
@@ -205,6 +208,122 @@
         }
     }
     
+    @Test public void getMaxThreadsFromParentConfigTree() throws Exception
+    {
+        final int expectedMaxThreads = 2;
+        final ConfigTree configTree = new ConfigBuilder(expectedMaxThreads).resultType(ResultType.STRING).templateFile(TEST_XSL_1).build();
+        final XsltAction action = new XsltAction(configTree);
+        final int actualMaxThreads = action.getMaxThreadsFromParentConfigTree(configTree);
+        
+        assertEquals(expectedMaxThreads, actualMaxThreads);
+    }
+
+    @Test (expected = ConfigurationException.class)
+    public void shouldThrowIfMaxThreadsIsInvalid() throws Exception
+    {
+        final int expectedMaxThreads = -1;
+        final ConfigTree configTree = new ConfigBuilder(expectedMaxThreads).resultType(ResultType.STRING).templateFile(TEST_XSL_1).build();
+        final XsltAction action = new XsltAction(configTree);
+        action.initialise();
+    }
+
+    /**
+     * This method tries to make sure that transformers in the pool do not interfer with each other.
+     * Only one instance of the XsltAction is created and it will have a pool of Transformer instance.
+     */
+    @Test public void processUsingPooledTransformers() throws Exception
+    {
+        final int poolSize = 8;
+        final XsltAction action = new XsltAction(new ConfigBuilder(poolSize).resultType(ResultType.STRING).templateFile(TEST_XSL_1).build());
+        action.initialise();
+        
+        final int nrOfTransformers = action.getNumberOfPooledTransfomers();
+        assertEquals(poolSize, nrOfTransformers);
+        
+        final String validXml = "<a><b><c><b></b></c></b></a>";
+        final String inValidXml = "<a>";
+        for (int i = 100; --i >= 0 ;)
+        {
+	        new Thread(new ProcessRunnable(validXml, action)).start();
+	        new Thread(new ProcessRunnable(inValidXml, action, true)).start();
+        }
+    }
+    
+    private static class ProcessRunnable implements Runnable
+    {
+        private final String xml;
+        private final boolean ignoreException;
+        private final XsltAction action;
+
+        public ProcessRunnable (final String xml, XsltAction action)
+        {
+            this(xml, action, false);
+        }
+        
+        public ProcessRunnable (final String xml, XsltAction action, boolean ignoreException)
+        {
+            this.xml = xml;
+            this.action = action;
+            this.ignoreException = ignoreException;
+        }
+
+        @Override
+        public void run ()
+        {
+            final Message message = MessageFactory.getInstance().getMessage();
+            message.getBody().add(xml);
+            Message processed;
+            try
+            {
+                processed = action.process(message);
+                assertTrue(XMLHelper.compareXMLContent("<xxx/>", (String) processed.getBody().get()));
+            }
+            catch (final Exception e)
+            {
+                if (ignoreException == false)
+                {
+	                e.printStackTrace();
+	                fail(e.getMessage());
+                }
+            }
+        }
+        
+    }
+
+    @Test 
+    @Ignore
+    public void performance() throws Exception
+    {
+        final XsltAction action = new XsltAction(new ConfigBuilder().resultType(ResultType.STRING).templateFile(TEST_XSL_1).build());
+        action.initialise();
+        
+        final MessageFactory messageFactory = MessageFactory.getInstance();
+        Message processed = null;
+        
+        // warm up 
+        for (int i = 0; i < 50000; i++)
+        {
+            final Message message = messageFactory.getMessage();
+            final String xml = "<a><b><c><b></b></c></b></a>";
+            message.getBody().add(xml);
+            processed = action.process(message);
+        }
+        
+        final int iterations = 1000000;
+        final long start = System.nanoTime();
+        for (int i = 0; i < iterations; i++)
+        {
+            final Message message = messageFactory.getMessage();
+            final String xml = "<a><b><c><b></b></c></b></a>";
+            message.getBody().add(xml);
+            processed = action.process(message);
+        }
+        final long duration = System.nanoTime() - start;
+        System.out.println(iterations + " took : " + NANOSECONDS.toSeconds(duration) + "s");
+        
+        assertTrue(XMLHelper.compareXMLContent("<xxx/>", (String) processed.getBody().get()));
+    }
+
     private void processOneReaderSource() throws Exception
     {
         final XsltAction action = new XsltAction(new ConfigBuilder().resultType(ResultType.STRING).templateFile(TEST_XSL_1).build());
@@ -258,9 +377,16 @@
         
         public ConfigBuilder()
         {
-            config = new ConfigTree("xsltUnitTest");
+            this(1);
         }
         
+        public ConfigBuilder(final int maxThreads)
+        {
+            ConfigTree parent = new ConfigTree("parent");
+            parent.setAttribute(ListenerTagNames.MAX_THREADS_TAG, Integer.toString(maxThreads));
+            config = new ConfigTree("xsltUnitTest", parent);
+        }
+        
         public ConfigBuilder templateFile(final String xslt)
         {
             config.setAttribute("templateFile", xslt);



More information about the jboss-svn-commits mailing list