summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrfeng <rfeng@13f79535-47bb-0310-9956-ffa450edef68>2011-07-27 23:20:34 +0000
committerrfeng <rfeng@13f79535-47bb-0310-9956-ffa450edef68>2011-07-27 23:20:34 +0000
commit859ece142d7941cb567885cd23d81432017683ba (patch)
treeefe33a98df07ae59b15dfba57f98ef11c3b51b6b
parent6a91d3d69f594af8cad6203ec4473a5ea81dc80e (diff)
Add a parser tool for DOM to avoid a JDK bug of deadlock (at com.sun.org.apache.xerces.internal.impl.dv.DTDDVFactory.getInstance)
git-svn-id: http://svn.us.apache.org/repos/asf/tuscany@1151663 13f79535-47bb-0310-9956-ffa450edef68
-rw-r--r--sca-java-2.x/trunk/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/dom/DOMHelper.java89
-rw-r--r--sca-java-2.x/trunk/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/dom/ParserPool.java99
-rw-r--r--sca-java-2.x/trunk/modules/common-xml/src/test/java/org/apache/tuscany/sca/common/xml/dom/DOMHelperTestCase.java27
3 files changed, 205 insertions, 10 deletions
diff --git a/sca-java-2.x/trunk/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/dom/DOMHelper.java b/sca-java-2.x/trunk/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/dom/DOMHelper.java
index 304275beb7..c5e7015364 100644
--- a/sca-java-2.x/trunk/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/dom/DOMHelper.java
+++ b/sca-java-2.x/trunk/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/dom/DOMHelper.java
@@ -40,6 +40,7 @@ import javax.xml.transform.stream.StreamResult;
import org.apache.tuscany.sca.common.xml.dom.impl.SAX2DOMAdapter;
import org.apache.tuscany.sca.core.ExtensionPointRegistry;
import org.apache.tuscany.sca.core.FactoryExtensionPoint;
+import org.apache.tuscany.sca.core.LifeCycleListener;
import org.apache.tuscany.sca.core.UtilityExtensionPoint;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
@@ -57,15 +58,19 @@ import org.xml.sax.ext.LexicalHandler;
* @version $Rev$ $Date$
* @tuscany.spi.extension.asclient
*/
-public class DOMHelper {
+public class DOMHelper implements LifeCycleListener {
+ protected static final int INITIAL_POOL_SIZE = 8;
+ protected static final int MAX_POOL_SIZE = 64;
private DocumentBuilderFactory documentBuilderFactory;
private TransformerFactory transformerFactory;
+ protected ParserPool<DocumentBuilder> builderPool;
+ protected ParserPool<Transformer> transformerPool;
public static DOMHelper getInstance(ExtensionPointRegistry registry) {
UtilityExtensionPoint utilities = registry.getExtensionPoint(UtilityExtensionPoint.class);
return utilities.getUtility(DOMHelper.class);
}
-
+
public DOMHelper(ExtensionPointRegistry registry) {
FactoryExtensionPoint factories = registry.getExtensionPoint(FactoryExtensionPoint.class);
documentBuilderFactory = factories.getFactory(DocumentBuilderFactory.class);
@@ -84,11 +89,24 @@ public class DOMHelper {
}
public Document newDocument() {
- return newDocumentBuilder().newDocument();
+ DocumentBuilder builder = newDocumentBuilder();
+ try {
+ return builder.newDocument();
+ } finally {
+ returnDocumentBuilder(builder);
+ }
}
public DocumentBuilder newDocumentBuilder() {
+ return builderPool.borrowFromPool();
+ }
+
+ public void returnDocumentBuilder(DocumentBuilder builder) {
+ builderPool.returnToPool(builder);
+ }
+
+ private DocumentBuilder createDocumentBuilder() {
try {
return documentBuilderFactory.newDocumentBuilder();
} catch (ParserConfigurationException e) {
@@ -98,10 +116,14 @@ public class DOMHelper {
public Document load(String xmlString) throws IOException, SAXException {
DocumentBuilder builder = newDocumentBuilder();
- InputSource is = new InputSource(new StringReader(xmlString));
- return builder.parse(is);
+ try {
+ InputSource is = new InputSource(new StringReader(xmlString));
+ return builder.parse(is);
+ } finally {
+ returnDocumentBuilder(builder);
+ }
}
-
+
public Document load(Source source) {
Transformer transformer = newTransformer();
DOMResult result = new DOMResult(newDocument());
@@ -109,6 +131,8 @@ public class DOMHelper {
transformer.transform(source, result);
} catch (TransformerException e) {
throw new IllegalArgumentException(e);
+ } finally {
+ transformerPool.returnToPool(transformer);
}
return (Document)result.getNode();
}
@@ -128,11 +152,21 @@ public class DOMHelper {
transformer.transform(new DOMSource(node), result);
} catch (TransformerException e) {
throw new IllegalArgumentException(e);
+ } finally {
+ returnTransformer(transformer);
}
return result.getWriter().toString();
}
- private Transformer newTransformer() {
+ public Transformer newTransformer() {
+ return transformerPool.borrowFromPool();
+ }
+
+ public void returnTransformer(Transformer transformer) {
+ transformerPool.returnToPool(transformer);
+ }
+
+ private Transformer createTransformer() {
Transformer transformer = null;
try {
transformer = transformerFactory.newTransformer();
@@ -143,12 +177,14 @@ public class DOMHelper {
}
public void saveAsSAX(Node node, ContentHandler contentHandler) {
- Transformer transformer = newTransformer();
+ Transformer transformer = transformerPool.borrowFromPool();
SAXResult result = new SAXResult(contentHandler);
try {
transformer.transform(new DOMSource(node), result);
} catch (TransformerException e) {
throw new IllegalArgumentException(e);
+ } finally {
+ returnTransformer(transformer);
}
}
@@ -209,7 +245,7 @@ public class DOMHelper {
}
return doc;
}
-
+
public static String getPrefix(Element element, String namespace) {
if (element.isDefaultNamespace(namespace)) {
return XMLConstants.DEFAULT_NS_PREFIX;
@@ -228,4 +264,39 @@ public class DOMHelper {
Node getNode();
}
+ @Override
+ public void start() {
+ builderPool = new ParserPool<DocumentBuilder>(MAX_POOL_SIZE, INITIAL_POOL_SIZE) {
+
+ @Override
+ protected DocumentBuilder newInstance() {
+ return createDocumentBuilder();
+ }
+
+ @Override
+ protected void resetInstance(DocumentBuilder obj) {
+ obj.reset();
+ }
+ };
+
+ transformerPool = new ParserPool<Transformer>(64, 8) {
+
+ @Override
+ protected Transformer newInstance() {
+ return createTransformer();
+ }
+
+ @Override
+ protected void resetInstance(Transformer obj) {
+ obj.reset();
+ }
+ };
+ }
+
+ @Override
+ public void stop() {
+ builderPool.clear();
+ transformerPool.clear();
+ }
+
}
diff --git a/sca-java-2.x/trunk/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/dom/ParserPool.java b/sca-java-2.x/trunk/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/dom/ParserPool.java
new file mode 100644
index 0000000000..6c987b39d4
--- /dev/null
+++ b/sca-java-2.x/trunk/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/dom/ParserPool.java
@@ -0,0 +1,99 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.tuscany.sca.common.xml.dom;
+
+import java.util.IdentityHashMap;
+import java.util.Map;
+
+public abstract class ParserPool<V> {
+ private int maxSize;
+ private Map<V, Boolean> objects;
+
+ public ParserPool() {
+ this(32, 0);
+ }
+
+ public ParserPool(int maxSize, int initialSize) {
+ super();
+ this.maxSize = maxSize;
+ this.objects = new IdentityHashMap<V, Boolean>(maxSize);
+ for (int i = 0; i < Math.min(initialSize, maxSize); i++) {
+ objects.put(newInstance(), Boolean.FALSE);
+ }
+ }
+
+ public synchronized V borrowFromPool() {
+ while (true) {
+ for (Map.Entry<V, Boolean> e : objects.entrySet()) {
+ if (Boolean.FALSE.equals(e.getValue())) {
+ e.setValue(Boolean.TRUE); // in use
+ return e.getKey();
+ }
+ }
+ if (objects.size() < maxSize) {
+ V obj = newInstance();
+ objects.put(obj, Boolean.TRUE);
+ return obj;
+ }
+ try {
+ wait();
+ } catch (InterruptedException e1) {
+ throw new IllegalStateException(e1);
+ }
+ }
+ }
+
+ public synchronized void returnToPool(V obj) {
+ resetInstance(obj);
+ objects.put(obj, Boolean.FALSE);
+ notifyAll();
+ }
+
+ public synchronized void clear() {
+ objects.clear();
+ }
+
+ public synchronized int inUse() {
+ int size = 0;
+ for (Map.Entry<V, Boolean> e : objects.entrySet()) {
+ if (Boolean.TRUE.equals(e.getValue())) {
+ size++;
+ }
+ }
+ return size;
+ }
+
+ /**
+ * Create a new instance
+ * @return
+ */
+ protected abstract V newInstance();
+
+ /**
+ * Reset the instance before returning to the pool
+ * @param obj
+ */
+ protected abstract void resetInstance(V obj);
+
+ // Expose it for testing purpose
+ public Map<V, Boolean> getObjects() {
+ return objects;
+ }
+}
diff --git a/sca-java-2.x/trunk/modules/common-xml/src/test/java/org/apache/tuscany/sca/common/xml/dom/DOMHelperTestCase.java b/sca-java-2.x/trunk/modules/common-xml/src/test/java/org/apache/tuscany/sca/common/xml/dom/DOMHelperTestCase.java
index 176ea35c1c..1be852ba05 100644
--- a/sca-java-2.x/trunk/modules/common-xml/src/test/java/org/apache/tuscany/sca/common/xml/dom/DOMHelperTestCase.java
+++ b/sca-java-2.x/trunk/modules/common-xml/src/test/java/org/apache/tuscany/sca/common/xml/dom/DOMHelperTestCase.java
@@ -20,13 +20,15 @@
package org.apache.tuscany.sca.common.xml.dom;
import static org.junit.Assert.assertNotNull;
-import junit.framework.Assert;
+
+import javax.xml.parsers.DocumentBuilder;
import org.apache.tuscany.sca.common.xml.sax.SAXHelper;
import org.apache.tuscany.sca.core.DefaultExtensionPointRegistry;
import org.apache.tuscany.sca.core.ExtensionPointRegistry;
import org.custommonkey.xmlunit.XMLAssert;
import org.junit.AfterClass;
+import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
import org.w3c.dom.Document;
@@ -78,4 +80,27 @@ public class DOMHelperTestCase {
XMLAssert.assertXMLEqual(XML, xml);
}
+ @Test
+ public void testPool() {
+ DOMHelper helper = DOMHelper.getInstance(registry);
+
+ DocumentBuilder buidler1 = helper.newDocumentBuilder();
+ Assert.assertTrue(helper.builderPool.getObjects().get(buidler1));
+
+ Assert.assertEquals(1, helper.builderPool.inUse());
+
+ DocumentBuilder buidler2 = helper.newDocumentBuilder();
+ Assert.assertTrue(helper.builderPool.getObjects().get(buidler2));
+ Assert.assertEquals(2, helper.builderPool.inUse());
+
+ helper.returnDocumentBuilder(buidler2);
+ Assert.assertFalse(helper.builderPool.getObjects().get(buidler2));
+ Assert.assertEquals(1, helper.builderPool.inUse());
+
+ helper.returnDocumentBuilder(buidler1);
+ Assert.assertFalse(helper.builderPool.getObjects().get(buidler1));
+ Assert.assertEquals(0, helper.builderPool.inUse());
+
+ }
+
}