You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tuscany.apache.org by rf...@apache.org on 2011/07/28 01:20:35 UTC

svn commit: r1151663 - in /tuscany/sca-java-2.x/trunk/modules/common-xml/src: main/java/org/apache/tuscany/sca/common/xml/dom/ test/java/org/apache/tuscany/sca/common/xml/dom/

Author: rfeng
Date: Wed Jul 27 23:20:34 2011
New Revision: 1151663

URL: http://svn.apache.org/viewvc?rev=1151663&view=rev
Log:
Add a parser tool for DOM to avoid a JDK bug of deadlock (at com.sun.org.apache.xerces.internal.impl.dv.DTDDVFactory.getInstance)

Added:
    tuscany/sca-java-2.x/trunk/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/dom/ParserPool.java   (with props)
Modified:
    tuscany/sca-java-2.x/trunk/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/dom/DOMHelper.java
    tuscany/sca-java-2.x/trunk/modules/common-xml/src/test/java/org/apache/tuscany/sca/common/xml/dom/DOMHelperTestCase.java

Modified: tuscany/sca-java-2.x/trunk/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/dom/DOMHelper.java
URL: http://svn.apache.org/viewvc/tuscany/sca-java-2.x/trunk/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/dom/DOMHelper.java?rev=1151663&r1=1151662&r2=1151663&view=diff
==============================================================================
--- tuscany/sca-java-2.x/trunk/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/dom/DOMHelper.java (original)
+++ tuscany/sca-java-2.x/trunk/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/dom/DOMHelper.java Wed Jul 27 23:20:34 2011
@@ -40,6 +40,7 @@ import javax.xml.transform.stream.Stream
 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();
+    }
+
 }

Added: tuscany/sca-java-2.x/trunk/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/dom/ParserPool.java
URL: http://svn.apache.org/viewvc/tuscany/sca-java-2.x/trunk/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/dom/ParserPool.java?rev=1151663&view=auto
==============================================================================
--- tuscany/sca-java-2.x/trunk/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/dom/ParserPool.java (added)
+++ tuscany/sca-java-2.x/trunk/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/dom/ParserPool.java Wed Jul 27 23:20:34 2011
@@ -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;
+    }
+}

Propchange: tuscany/sca-java-2.x/trunk/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/dom/ParserPool.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: tuscany/sca-java-2.x/trunk/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/dom/ParserPool.java
------------------------------------------------------------------------------
    svn:keywords = Rev Date

Modified: tuscany/sca-java-2.x/trunk/modules/common-xml/src/test/java/org/apache/tuscany/sca/common/xml/dom/DOMHelperTestCase.java
URL: http://svn.apache.org/viewvc/tuscany/sca-java-2.x/trunk/modules/common-xml/src/test/java/org/apache/tuscany/sca/common/xml/dom/DOMHelperTestCase.java?rev=1151663&r1=1151662&r2=1151663&view=diff
==============================================================================
--- tuscany/sca-java-2.x/trunk/modules/common-xml/src/test/java/org/apache/tuscany/sca/common/xml/dom/DOMHelperTestCase.java (original)
+++ tuscany/sca-java-2.x/trunk/modules/common-xml/src/test/java/org/apache/tuscany/sca/common/xml/dom/DOMHelperTestCase.java Wed Jul 27 23:20:34 2011
@@ -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());
+
+    }
+
 }