[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