You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2010/05/11 09:13:38 UTC
svn commit: r943024 - in /camel/trunk/camel-core/src:
main/java/org/apache/camel/converter/jaxp/XmlConverter.java
test/java/org/apache/camel/builder/xml/XPathTest.java
test/java/org/apache/camel/converter/jaxp/XmlConverterTest.java
Author: davsclaus
Date: Tue May 11 07:13:38 2010
New Revision: 943024
URL: http://svn.apache.org/viewvc?rev=943024&view=rev
Log:
CAMEL-2692: Fixed thread safety issue when converting Node to Dom.
Modified:
camel/trunk/camel-core/src/main/java/org/apache/camel/converter/jaxp/XmlConverter.java
camel/trunk/camel-core/src/test/java/org/apache/camel/builder/xml/XPathTest.java
camel/trunk/camel-core/src/test/java/org/apache/camel/converter/jaxp/XmlConverterTest.java
Modified: camel/trunk/camel-core/src/main/java/org/apache/camel/converter/jaxp/XmlConverter.java
URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/main/java/org/apache/camel/converter/jaxp/XmlConverter.java?rev=943024&r1=943023&r2=943024&view=diff
==============================================================================
--- camel/trunk/camel-core/src/main/java/org/apache/camel/converter/jaxp/XmlConverter.java (original)
+++ camel/trunk/camel-core/src/main/java/org/apache/camel/converter/jaxp/XmlConverter.java Tue May 11 07:13:38 2010
@@ -384,9 +384,10 @@ public class XmlConverter {
@Converter
public DOMSource toDOMSourceFromStream(StreamSource source) throws ParserConfigurationException, IOException, SAXException {
- DocumentBuilder builder = createDocumentBuilder();
+ Document document;
String systemId = source.getSystemId();
- Document document = null;
+
+ DocumentBuilder builder = createDocumentBuilder();
Reader reader = source.getReader();
if (reader != null) {
document = builder.parse(new InputSource(reader));
@@ -397,7 +398,7 @@ public class XmlConverter {
inputsource.setSystemId(systemId);
document = builder.parse(inputsource);
} else {
- throw new IOException("No input stream or reader available");
+ throw new IOException("No input stream or reader available on StreamSource: " + source);
}
}
return new DOMSource(document, systemId);
@@ -550,13 +551,14 @@ public class XmlConverter {
/**
* Create a DOM document from the given Node.
- * If the node is an document, just cast it,
- * if the node is an root element, retrieve its
- * owner element or create a new document and import
- * the node.
+ *
+ * If the node is an document, just cast it, if the node is an root element, retrieve its
+ * owner element or create a new document and import the node.
*/
@Converter
- public Document toDOMDocument(Node node) throws ParserConfigurationException, TransformerException {
+ public Document toDOMDocument(final Node node) throws ParserConfigurationException, TransformerException {
+ ObjectHelper.notNull(node, "node");
+
// If the node is the document, just cast it
if (node instanceof Document) {
return (Document) node;
@@ -569,23 +571,27 @@ public class XmlConverter {
// else, create a new doc and copy the element inside it
} else {
Document doc = createDocument();
- doc.appendChild(doc.importNode(node, true));
+ // import node must no occur concurrent on the same node
+ // so we need to synchronize on it
+ synchronized (node) {
+ doc.appendChild(doc.importNode(node, true));
+ }
return doc;
}
// other element types are not handled
} else {
- throw new TransformerException("Unable to convert DOM node to a Document");
+ throw new TransformerException("Unable to convert DOM node to a Document: " + node);
}
}
@Converter
- public InputStream toInputStrean(DOMSource source) throws TransformerException, IOException {
+ public InputStream toInputStream(DOMSource source) throws TransformerException, IOException {
String s = toString(source);
return new ByteArrayInputStream(s.getBytes());
}
@Converter
- public InputStream toInputStrean(Document dom) throws TransformerException, IOException {
+ public InputStream toInputStream(Document dom) throws TransformerException, IOException {
String s = toString(dom);
return new ByteArrayInputStream(s.getBytes());
}
Modified: camel/trunk/camel-core/src/test/java/org/apache/camel/builder/xml/XPathTest.java
URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/test/java/org/apache/camel/builder/xml/XPathTest.java?rev=943024&r1=943023&r2=943024&view=diff
==============================================================================
--- camel/trunk/camel-core/src/test/java/org/apache/camel/builder/xml/XPathTest.java (original)
+++ camel/trunk/camel-core/src/test/java/org/apache/camel/builder/xml/XPathTest.java Tue May 11 07:13:38 2010
@@ -17,20 +17,29 @@
package org.apache.camel.builder.xml;
import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.Callable;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
import javax.xml.transform.dom.DOMSource;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFunctionResolver;
-import org.w3c.dom.Document;
-import org.w3c.dom.Node;
-import org.w3c.dom.NodeList;
-import org.xml.sax.InputSource;
-
import org.apache.camel.ContextTestSupport;
import org.apache.camel.Exchange;
import org.apache.camel.Expression;
import org.apache.camel.Predicate;
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.InputSource;
import static org.apache.camel.builder.xml.XPathBuilder.xpath;
@@ -313,4 +322,51 @@ public class XPathTest extends ContextTe
assertEquals(true, bool.booleanValue());
}
+ public void testXPathSplit() throws Exception {
+ Object node = XPathBuilder.xpath("foo/bar").nodeResult()
+ .evaluate(createExchange("<foo><bar>cheese</bar><bar>cake</bar><bar>beer</bar></foo>"));
+ assertNotNull(node);
+
+ Document doc = context.getTypeConverter().convertTo(Document.class, node);
+ assertNotNull(doc);
+ }
+
+ public void testXPathSplitConcurrent() throws Exception {
+ int size = 100;
+
+ final Object node = XPathBuilder.xpath("foo/bar").nodeResult()
+ .evaluate(createExchange("<foo><bar>cheese</bar><bar>cake</bar><bar>beer</bar></foo>"));
+ assertNotNull(node);
+
+ // convert the node concurrently to test that XML Parser is not thread safe when
+ // importing nodes to a new Document, so try a test for that
+
+ final Set<Document> result = new HashSet<Document>();
+ ExecutorService executor = Executors.newFixedThreadPool(size);
+ final CountDownLatch latch = new CountDownLatch(size);
+ for (int i = 0; i < size; i++) {
+ executor.submit(new Callable<Document>() {
+ public Document call() throws Exception {
+ Document doc = context.getTypeConverter().convertTo(Document.class, node);
+ result.add(doc);
+ latch.countDown();
+ return doc;
+ }
+ });
+ }
+
+ // give time to convert concurrently
+ latch.await(20, TimeUnit.SECONDS);
+
+ assertEquals(size, result.size());
+ Iterator<Document> it = result.iterator();
+ int count = 0;
+ while (it.hasNext()) {
+ count++;
+ Document doc = it.next();
+ assertNotNull(doc);
+ }
+ assertEquals(size, count);
+ }
+
}
Modified: camel/trunk/camel-core/src/test/java/org/apache/camel/converter/jaxp/XmlConverterTest.java
URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/test/java/org/apache/camel/converter/jaxp/XmlConverterTest.java?rev=943024&r1=943023&r2=943024&view=diff
==============================================================================
--- camel/trunk/camel-core/src/test/java/org/apache/camel/converter/jaxp/XmlConverterTest.java (original)
+++ camel/trunk/camel-core/src/test/java/org/apache/camel/converter/jaxp/XmlConverterTest.java Tue May 11 07:13:38 2010
@@ -346,7 +346,7 @@ public class XmlConverterTest extends Co
XmlConverter conv = new XmlConverter();
Document doc = context.getTypeConverter().convertTo(Document.class, "<?xml version=\"1.0\" encoding=\"UTF-8\"?><foo>bar</foo>");
- InputStream is = conv.toInputStrean(doc);
+ InputStream is = conv.toInputStream(doc);
assertNotNull(is);
assertEquals("<foo>bar</foo>", context.getTypeConverter().convertTo(String.class, is));
}
@@ -365,7 +365,7 @@ public class XmlConverterTest extends Co
XmlConverter conv = new XmlConverter();
DOMSource source = conv.toDOMSource("<foo>bar</foo>");
- InputStream out = conv.toInputStrean(source);
+ InputStream out = conv.toInputStream(source);
assertNotSame(source, out);
String s = context.getTypeConverter().convertTo(String.class, out);