You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@santuario.apache.org by co...@apache.org on 2018/06/08 14:59:13 UTC

svn commit: r1833179 - in /santuario/xml-security-java/trunk/src: main/java/org/apache/jcp/xml/dsig/internal/dom/ main/java/org/apache/xml/security/ main/java/org/apache/xml/security/c14n/ main/java/org/apache/xml/security/encryption/ main/java/org/apa...

Author: coheigea
Date: Fri Jun  8 14:59:12 2018
New Revision: 1833179

URL: http://svn.apache.org/viewvc?rev=1833179&view=rev
Log:
Revert "Revert "[SANTUARIO-394] - Performance issue with getting XML parsers. Thanks to Anli Shundi for the patch.""

This reverts commit e961c79b9611bab69acf9adfc4a200d17c742909.

Added:
    santuario/xml-security-java/trunk/src/main/java/org/apache/xml/security/utils/WeakObjectPool.java
    santuario/xml-security-java/trunk/src/test/java/org/apache/xml/security/test/dom/utils/DocumentBuilderPoolingTest.java
Modified:
    santuario/xml-security-java/trunk/src/main/java/org/apache/jcp/xml/dsig/internal/dom/DOMRetrievalMethod.java
    santuario/xml-security-java/trunk/src/main/java/org/apache/xml/security/Init.java
    santuario/xml-security-java/trunk/src/main/java/org/apache/xml/security/c14n/Canonicalizer.java
    santuario/xml-security-java/trunk/src/main/java/org/apache/xml/security/c14n/CanonicalizerSpi.java
    santuario/xml-security-java/trunk/src/main/java/org/apache/xml/security/encryption/DocumentSerializer.java
    santuario/xml-security-java/trunk/src/main/java/org/apache/xml/security/keys/keyresolver/KeyResolverSpi.java
    santuario/xml-security-java/trunk/src/main/java/org/apache/xml/security/keys/keyresolver/implementations/KeyInfoReferenceResolver.java
    santuario/xml-security-java/trunk/src/main/java/org/apache/xml/security/keys/keyresolver/implementations/RetrievalMethodResolver.java
    santuario/xml-security-java/trunk/src/main/java/org/apache/xml/security/signature/SignedInfo.java
    santuario/xml-security-java/trunk/src/main/java/org/apache/xml/security/signature/XMLSignatureInput.java
    santuario/xml-security-java/trunk/src/main/java/org/apache/xml/security/utils/XMLUtils.java
    santuario/xml-security-java/trunk/src/test/java/org/apache/xml/security/test/dom/secure_val/ForbiddenReferenceTest.java
    santuario/xml-security-java/trunk/src/test/java/org/apache/xml/security/test/dom/signature/SignatureReferenceTest.java

Modified: santuario/xml-security-java/trunk/src/main/java/org/apache/jcp/xml/dsig/internal/dom/DOMRetrievalMethod.java
URL: http://svn.apache.org/viewvc/santuario/xml-security-java/trunk/src/main/java/org/apache/jcp/xml/dsig/internal/dom/DOMRetrievalMethod.java?rev=1833179&r1=1833178&r2=1833179&view=diff
==============================================================================
--- santuario/xml-security-java/trunk/src/main/java/org/apache/jcp/xml/dsig/internal/dom/DOMRetrievalMethod.java (original)
+++ santuario/xml-security-java/trunk/src/main/java/org/apache/jcp/xml/dsig/internal/dom/DOMRetrievalMethod.java Fri Jun  8 14:59:12 2018
@@ -36,13 +36,23 @@ import java.io.InputStream;
 import java.net.URI;
 import java.net.URISyntaxException;
 import java.security.Provider;
-import java.util.*;
-
-import javax.xml.crypto.*;
-import javax.xml.crypto.dsig.*;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+import javax.xml.crypto.Data;
+import javax.xml.crypto.MarshalException;
+import javax.xml.crypto.NodeSetData;
+import javax.xml.crypto.URIDereferencer;
+import javax.xml.crypto.URIReferenceException;
+import javax.xml.crypto.XMLCryptoContext;
+import javax.xml.crypto.XMLStructure;
 import javax.xml.crypto.dom.DOMURIReference;
+import javax.xml.crypto.dsig.Transform;
+import javax.xml.crypto.dsig.XMLSignature;
 import javax.xml.crypto.dsig.keyinfo.RetrievalMethod;
-import javax.xml.parsers.*;
+import javax.xml.parsers.DocumentBuilder;
 
 import org.apache.xml.security.utils.XMLUtils;
 import org.w3c.dom.Attr;
@@ -255,10 +265,11 @@ public final class DOMRetrievalMethod ex
     public XMLStructure dereferenceAsXMLStructure(XMLCryptoContext context)
         throws URIReferenceException
     {
+        DocumentBuilder db = null;
         boolean secVal = Utils.secureValidation(context);
         ApacheData data = (ApacheData)dereference(context);
         try (InputStream is = new ByteArrayInputStream(data.getXMLSignatureInput().getBytes())) {
-            DocumentBuilder db = XMLUtils.createDocumentBuilder(false, secVal);
+            db = XMLUtils.createDocumentBuilder(false, secVal);
             Document doc = db.parse(is);
             Element kiElem = doc.getDocumentElement();
             if (kiElem.getLocalName().equals("X509Data")
@@ -269,6 +280,10 @@ public final class DOMRetrievalMethod ex
             }
         } catch (Exception e) {
             throw new URIReferenceException(e);
+        } finally {
+            if (db != null) {
+                XMLUtils.repoolDocumentBuilder(db);
+            }
         }
     }
 

Modified: santuario/xml-security-java/trunk/src/main/java/org/apache/xml/security/Init.java
URL: http://svn.apache.org/viewvc/santuario/xml-security-java/trunk/src/main/java/org/apache/xml/security/Init.java?rev=1833179&r1=1833178&r2=1833179&view=diff
==============================================================================
--- santuario/xml-security-java/trunk/src/main/java/org/apache/xml/security/Init.java (original)
+++ santuario/xml-security-java/trunk/src/main/java/org/apache/xml/security/Init.java Fri Jun  8 14:59:12 2018
@@ -156,7 +156,13 @@ public class Init {
         try {
             /* read library configuration file */
             DocumentBuilder db = XMLUtils.createDocumentBuilder(false);
-            Document doc = db.parse(is);
+            Document doc;
+            try {
+                doc = db.parse(is);
+            } finally {
+                XMLUtils.repoolDocumentBuilder(db);
+                db = null;
+            }
             Node config = doc.getFirstChild();
             for (; config != null; config = config.getNextSibling()) {
                 if ("Configuration".equals(config.getLocalName())) {

Modified: santuario/xml-security-java/trunk/src/main/java/org/apache/xml/security/c14n/Canonicalizer.java
URL: http://svn.apache.org/viewvc/santuario/xml-security-java/trunk/src/main/java/org/apache/xml/security/c14n/Canonicalizer.java?rev=1833179&r1=1833178&r2=1833179&view=diff
==============================================================================
--- santuario/xml-security-java/trunk/src/main/java/org/apache/xml/security/c14n/Canonicalizer.java (original)
+++ santuario/xml-security-java/trunk/src/main/java/org/apache/xml/security/c14n/Canonicalizer.java Fri Jun  8 14:59:12 2018
@@ -282,7 +282,11 @@ public class Canonicalizer {
              */
             db.setErrorHandler(new org.apache.xml.security.utils.IgnoreAllErrorHandler());
 
-            document = db.parse(in);
+            try {
+                document = db.parse(in);
+            } finally {
+                XMLUtils.repoolDocumentBuilder(db);
+            }
         }
         return this.canonicalizeSubtree(document);
     }

Modified: santuario/xml-security-java/trunk/src/main/java/org/apache/xml/security/c14n/CanonicalizerSpi.java
URL: http://svn.apache.org/viewvc/santuario/xml-security-java/trunk/src/main/java/org/apache/xml/security/c14n/CanonicalizerSpi.java?rev=1833179&r1=1833178&r2=1833179&view=diff
==============================================================================
--- santuario/xml-security-java/trunk/src/main/java/org/apache/xml/security/c14n/CanonicalizerSpi.java (original)
+++ santuario/xml-security-java/trunk/src/main/java/org/apache/xml/security/c14n/CanonicalizerSpi.java Fri Jun  8 14:59:12 2018
@@ -61,7 +61,11 @@ public abstract class CanonicalizerSpi {
 
             DocumentBuilder db = XMLUtils.createDocumentBuilder(false, secureValidation);
 
-            document = db.parse(in);
+            try {
+                document = db.parse(in);
+            } finally {
+                XMLUtils.repoolDocumentBuilder(db);
+            }
         }
         return this.engineCanonicalizeSubTree(document);
     }

Modified: santuario/xml-security-java/trunk/src/main/java/org/apache/xml/security/encryption/DocumentSerializer.java
URL: http://svn.apache.org/viewvc/santuario/xml-security-java/trunk/src/main/java/org/apache/xml/security/encryption/DocumentSerializer.java?rev=1833179&r1=1833178&r2=1833179&view=diff
==============================================================================
--- santuario/xml-security-java/trunk/src/main/java/org/apache/xml/security/encryption/DocumentSerializer.java (original)
+++ santuario/xml-security-java/trunk/src/main/java/org/apache/xml/security/encryption/DocumentSerializer.java Fri Jun  8 14:59:12 2018
@@ -70,8 +70,9 @@ public class DocumentSerializer extends
      * @throws XMLEncryptionException
      */
     private Node deserialize(Node ctx, InputSource inputSource) throws XMLEncryptionException {
+        DocumentBuilder db = null;
         try {
-            DocumentBuilder db = XMLUtils.createDocumentBuilder(false, secureValidation);
+            db = XMLUtils.createDocumentBuilder(false, secureValidation);
             Document d = db.parse(inputSource);
 
             Document contextDocument = null;
@@ -97,6 +98,10 @@ public class DocumentSerializer extends
             throw new XMLEncryptionException(pce);
         } catch (IOException ioe) {
             throw new XMLEncryptionException(ioe);
+        } finally {
+            if (db != null) {
+                XMLUtils.repoolDocumentBuilder(db);
+            }
         }
     }
 

Modified: santuario/xml-security-java/trunk/src/main/java/org/apache/xml/security/keys/keyresolver/KeyResolverSpi.java
URL: http://svn.apache.org/viewvc/santuario/xml-security-java/trunk/src/main/java/org/apache/xml/security/keys/keyresolver/KeyResolverSpi.java?rev=1833179&r1=1833178&r2=1833179&view=diff
==============================================================================
--- santuario/xml-security-java/trunk/src/main/java/org/apache/xml/security/keys/keyresolver/KeyResolverSpi.java (original)
+++ santuario/xml-security-java/trunk/src/main/java/org/apache/xml/security/keys/keyresolver/KeyResolverSpi.java Fri Jun  8 14:59:12 2018
@@ -262,6 +262,7 @@ public abstract class KeyResolverSpi {
         this.globalResolver = globalResolver;
     }
 
+
     /**
      * Parses a byte array and returns the parsed Element.
      *
@@ -270,8 +271,9 @@ public abstract class KeyResolverSpi {
      * @throws KeyResolverException if something goes wrong
      */
     protected static Element getDocFromBytes(byte[] bytes, boolean secureValidation) throws KeyResolverException {
+        DocumentBuilder db = null;
         try (InputStream is = new ByteArrayInputStream(bytes)) {
-            DocumentBuilder db = XMLUtils.createDocumentBuilder(false, secureValidation);
+            db = XMLUtils.createDocumentBuilder(false, secureValidation);
             Document doc = db.parse(is);
             return doc.getDocumentElement();
         } catch (SAXException ex) {
@@ -280,6 +282,10 @@ public abstract class KeyResolverSpi {
             throw new KeyResolverException(ex);
         } catch (ParserConfigurationException ex) {
             throw new KeyResolverException(ex);
+        } finally {
+            if (db != null) {
+                XMLUtils.repoolDocumentBuilder(db);
+            }
         }
     }
 

Modified: santuario/xml-security-java/trunk/src/main/java/org/apache/xml/security/keys/keyresolver/implementations/KeyInfoReferenceResolver.java
URL: http://svn.apache.org/viewvc/santuario/xml-security-java/trunk/src/main/java/org/apache/xml/security/keys/keyresolver/implementations/KeyInfoReferenceResolver.java?rev=1833179&r1=1833178&r2=1833179&view=diff
==============================================================================
--- santuario/xml-security-java/trunk/src/main/java/org/apache/xml/security/keys/keyresolver/implementations/KeyInfoReferenceResolver.java (original)
+++ santuario/xml-security-java/trunk/src/main/java/org/apache/xml/security/keys/keyresolver/implementations/KeyInfoReferenceResolver.java Fri Jun  8 14:59:12 2018
@@ -250,5 +250,4 @@ public class KeyInfoReferenceResolver ex
         }
         return e;
     }
-
 }

Modified: santuario/xml-security-java/trunk/src/main/java/org/apache/xml/security/keys/keyresolver/implementations/RetrievalMethodResolver.java
URL: http://svn.apache.org/viewvc/santuario/xml-security-java/trunk/src/main/java/org/apache/xml/security/keys/keyresolver/implementations/RetrievalMethodResolver.java?rev=1833179&r1=1833178&r2=1833179&view=diff
==============================================================================
--- santuario/xml-security-java/trunk/src/main/java/org/apache/xml/security/keys/keyresolver/implementations/RetrievalMethodResolver.java (original)
+++ santuario/xml-security-java/trunk/src/main/java/org/apache/xml/security/keys/keyresolver/implementations/RetrievalMethodResolver.java Fri Jun  8 14:59:12 2018
@@ -281,7 +281,7 @@ public class RetrievalMethodResolver ext
         }
         return resource;
     }
-   
+
     /**
      * Method engineResolveSecretKey
      * {@inheritDoc}

Modified: santuario/xml-security-java/trunk/src/main/java/org/apache/xml/security/signature/SignedInfo.java
URL: http://svn.apache.org/viewvc/santuario/xml-security-java/trunk/src/main/java/org/apache/xml/security/signature/SignedInfo.java?rev=1833179&r1=1833178&r2=1833179&view=diff
==============================================================================
--- santuario/xml-security-java/trunk/src/main/java/org/apache/xml/security/signature/SignedInfo.java (original)
+++ santuario/xml-security-java/trunk/src/main/java/org/apache/xml/security/signature/SignedInfo.java Fri Jun  8 14:59:12 2018
@@ -22,6 +22,7 @@ import java.io.ByteArrayInputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
+
 import javax.crypto.SecretKey;
 import javax.crypto.spec.SecretKeySpec;
 import javax.xml.parsers.ParserConfigurationException;
@@ -31,9 +32,9 @@ import org.apache.xml.security.c14n.Cano
 import org.apache.xml.security.c14n.Canonicalizer;
 import org.apache.xml.security.c14n.InvalidCanonicalizerException;
 import org.apache.xml.security.exceptions.XMLSecurityException;
+import org.apache.xml.security.transforms.params.InclusiveNamespaces;
 import org.apache.xml.security.utils.Constants;
 import org.apache.xml.security.utils.XMLUtils;
-import org.apache.xml.security.transforms.params.InclusiveNamespaces;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
 import org.w3c.dom.Node;
@@ -218,6 +219,8 @@ public class SignedInfo extends Manifest
                             newdoc.getDocumentElement(), true);
                     element.getParentNode().replaceChild(imported, element);
                     return (Element) imported;
+                } finally {
+                    XMLUtils.repoolDocumentBuilder(db);
                 }
             } catch (ParserConfigurationException ex) {
                 throw new XMLSecurityException(ex);

Modified: santuario/xml-security-java/trunk/src/main/java/org/apache/xml/security/signature/XMLSignatureInput.java
URL: http://svn.apache.org/viewvc/santuario/xml-security-java/trunk/src/main/java/org/apache/xml/security/signature/XMLSignatureInput.java?rev=1833179&r1=1833178&r2=1833179&view=diff
==============================================================================
--- santuario/xml-security-java/trunk/src/main/java/org/apache/xml/security/signature/XMLSignatureInput.java (original)
+++ santuario/xml-security-java/trunk/src/main/java/org/apache/xml/security/signature/XMLSignatureInput.java Fri Jun  8 14:59:12 2018
@@ -33,9 +33,9 @@ import javax.xml.parsers.DocumentBuilder
 import javax.xml.parsers.ParserConfigurationException;
 
 import org.apache.xml.security.c14n.CanonicalizationException;
-import org.apache.xml.security.c14n.implementations.CanonicalizerBase;
-import org.apache.xml.security.c14n.implementations.Canonicalizer20010315OmitComments;
 import org.apache.xml.security.c14n.implementations.Canonicalizer11_OmitComments;
+import org.apache.xml.security.c14n.implementations.Canonicalizer20010315OmitComments;
+import org.apache.xml.security.c14n.implementations.CanonicalizerBase;
 import org.apache.xml.security.exceptions.XMLSecurityRuntimeException;
 import org.apache.xml.security.utils.JavaUtils;
 import org.apache.xml.security.utils.XMLUtils;
@@ -593,6 +593,7 @@ public class XMLSignatureInput {
                 this.subNode = document.getDocumentElement().getFirstChild().getFirstChild();
             }
         } finally {
+            XMLUtils.repoolDocumentBuilder(db);
             if (this.inputOctetStreamProxy != null) {
                 this.inputOctetStreamProxy.close();
             }

Added: santuario/xml-security-java/trunk/src/main/java/org/apache/xml/security/utils/WeakObjectPool.java
URL: http://svn.apache.org/viewvc/santuario/xml-security-java/trunk/src/main/java/org/apache/xml/security/utils/WeakObjectPool.java?rev=1833179&view=auto
==============================================================================
--- santuario/xml-security-java/trunk/src/main/java/org/apache/xml/security/utils/WeakObjectPool.java (added)
+++ santuario/xml-security-java/trunk/src/main/java/org/apache/xml/security/utils/WeakObjectPool.java Fri Jun  8 14:59:12 2018
@@ -0,0 +1,114 @@
+/**
+ * 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.xml.security.utils;
+
+import java.lang.ref.WeakReference;
+import java.util.Collections;
+import java.util.Map;
+import java.util.WeakHashMap;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingDeque;
+
+/**
+ * Abstract base class for pooling objects.  The two public methods are
+ * {@link #getObject()} and ({@link #repool(Object)}.  Objects are held through
+ * weak references so even objects that are not repooled are subject to garbage collection.
+ *
+ * Subclasses must implement the abstract {@link #createObject()}.
+ * <p>
+ *
+ * Internally, the pool is stored in a java.util.concurrent.LinkedBlockingDeque
+ * instance.
+ */
+public abstract class WeakObjectPool<T, E extends Throwable> {
+
+    private static final Integer MARKER_VALUE = Integer.MAX_VALUE;//once here rather than auto-box it?
+
+    /** created, available objects to be checked out to clients */
+    private final BlockingQueue<WeakReference<T>> available;
+
+    /**
+     * Synchronized, identity map of loaned out objects (WeakHashMap);
+     * use to ensure we repool only object originating from here
+     * and do it once.
+     */
+    private final Map<T, Integer> onLoan;
+
+    /**
+     * The lone constructor.
+     */
+    protected WeakObjectPool() {
+        //alternative implementations: ArrayBlockingQueue has a fixed size
+        //  PriorityBlockingQueue: requires a dummy comparator; less memory but more overhead
+        available = new LinkedBlockingDeque<WeakReference<T>>();
+        this.onLoan = Collections.synchronizedMap(new WeakHashMap<T, Integer>());
+    }
+
+    /**
+     * Called whenever a new pool object is desired; subclasses must implement.
+     *
+     * @return object of the type desired by the subclass
+     * @throws E Throwable's subclass
+     */
+    protected abstract T createObject() throws E;
+
+
+    /**
+     * Subclasses can subclass to return a more specific type.
+     *
+     * @return an object from the pool; will block until an object is available
+     * @throws E
+     */
+    public T getObject() throws E {
+        WeakReference<T> ref;
+        T retValue = null;
+        do {
+            //remove any stale entries as well
+            ref = available.poll();
+        } while (ref != null && (retValue = ref.get()) == null);
+
+        if (retValue == null) {
+            //empty pool; create & add new one
+            retValue = createObject();
+        }
+        onLoan.put(retValue, MARKER_VALUE);
+        return retValue;
+    }
+
+
+    /**
+     * Adds the given object to the pool, provided that the object
+     * was created by this pool.
+     *
+     * @param obj the object to return to the pool
+     * @return whether the object was successfully added as available
+     */
+    public boolean repool(T obj) {
+        if (obj != null && onLoan.containsKey(obj)) {
+            //synchronize to protect against a caller returning the same object again...
+            synchronized (obj) {
+                //...and check to see that it was removed
+                if (onLoan.remove(obj) != null) {
+                    return available.offer(new WeakReference<T>(obj));
+                }
+            }
+        }
+        return false;
+    }
+}

Modified: santuario/xml-security-java/trunk/src/main/java/org/apache/xml/security/utils/XMLUtils.java
URL: http://svn.apache.org/viewvc/santuario/xml-security-java/trunk/src/main/java/org/apache/xml/security/utils/XMLUtils.java?rev=1833179&r1=1833178&r2=1833179&view=diff
==============================================================================
--- santuario/xml-security-java/trunk/src/main/java/org/apache/xml/security/utils/XMLUtils.java (original)
+++ santuario/xml-security-java/trunk/src/main/java/org/apache/xml/security/utils/XMLUtils.java Fri Jun  8 14:59:12 2018
@@ -18,7 +18,9 @@
  */
 package org.apache.xml.security.utils;
 
+import java.io.File;
 import java.io.IOException;
+import java.io.InputStream;
 import java.io.OutputStream;
 import java.math.BigInteger;
 import java.security.AccessController;
@@ -34,17 +36,23 @@ import javax.xml.XMLConstants;
 import javax.xml.parsers.DocumentBuilder;
 import javax.xml.parsers.DocumentBuilderFactory;
 import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.validation.Schema;
 
 import org.apache.xml.security.c14n.CanonicalizationException;
 import org.apache.xml.security.c14n.Canonicalizer;
 import org.apache.xml.security.c14n.InvalidCanonicalizerException;
 import org.w3c.dom.Attr;
+import org.w3c.dom.DOMImplementation;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
 import org.w3c.dom.NamedNodeMap;
 import org.w3c.dom.Node;
 import org.w3c.dom.NodeList;
 import org.w3c.dom.Text;
+import org.xml.sax.EntityResolver;
+import org.xml.sax.ErrorHandler;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
 
 /**
  * DOM and XML accessibility and comfort functions.
@@ -56,6 +64,15 @@ public final class XMLUtils {
         AccessController.doPrivileged(
             (PrivilegedAction<Boolean>) () -> Boolean.getBoolean("org.apache.xml.security.ignoreLineBreaks"));
 
+    @SuppressWarnings("unchecked")
+    private static final WeakObjectPool<DocumentBuilder, ParserConfigurationException> pools[] = new WeakObjectPool[4];
+    static {
+        pools[0] = new DocumentBuilderPool(false, false);
+        pools[1] = new DocumentBuilderPool(false, true);
+        pools[2] = new DocumentBuilderPool(true, false);
+        pools[3] = new DocumentBuilderPool(true, true);
+    }
+
     private static volatile String dsPrefix = "ds";
     private static volatile String ds11Prefix = "dsig11";
     private static volatile String xencPrefix = "xenc";
@@ -1052,15 +1069,8 @@ public final class XMLUtils {
     public static DocumentBuilder createDocumentBuilder(
         boolean validating, boolean disAllowDocTypeDeclarations
     ) throws ParserConfigurationException {
-        DocumentBuilderFactory dfactory = DocumentBuilderFactory.newInstance();
-        dfactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, Boolean.TRUE);
-        if (disAllowDocTypeDeclarations) {
-            dfactory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
-        }
-        dfactory.setValidating(validating);        
-        dfactory.setNamespaceAware(true);
-        
-        return dfactory.newDocumentBuilder();
+        int idx = getPoolsIndex(validating, disAllowDocTypeDeclarations);
+        return pools[idx].getObject();
     }
 
 
@@ -1069,9 +1079,15 @@ public final class XMLUtils {
      * @param db DocumentBuilder returned from any of {@link #createDocumentBuilder} methods.
      * @return whether it was successfully returned to the pool
      */
-    @Deprecated
     public static boolean repoolDocumentBuilder(DocumentBuilder db) {
-        return true;
+        if (!(db instanceof DocumentBuilderProxy)) {
+            return false;
+        }
+        db.reset();
+        boolean disAllowDocTypeDeclarations =
+            ((DocumentBuilderProxy)db).disAllowDocTypeDeclarations();
+        int idx = getPoolsIndex(db.isValidating(), disAllowDocTypeDeclarations);
+        return pools[idx].repool(db);
     }
 
     /**
@@ -1119,4 +1135,121 @@ public final class XMLUtils {
         return resizedBytes;
     }
 
+    /**
+     * We need this proxy wrapping DocumentBuilder to record the value
+     * passed to disAllowDoctypeDeclarations.  It's needed to figure out
+     * on which pool to return.
+     */
+    private static class DocumentBuilderProxy extends DocumentBuilder {
+        private final DocumentBuilder delegate;
+        private final boolean disAllowDocTypeDeclarations;
+
+        private DocumentBuilderProxy(DocumentBuilder actual, boolean disAllowDocTypeDeclarations) {
+            delegate = actual;
+            this.disAllowDocTypeDeclarations = disAllowDocTypeDeclarations;
+        }
+
+        boolean disAllowDocTypeDeclarations() {
+            return disAllowDocTypeDeclarations;
+        }
+
+        public void reset() {
+            delegate.reset();
+        }
+
+        public Document parse(InputStream is) throws SAXException, IOException {
+            return delegate.parse(is);
+        }
+
+        public Document parse(InputStream is, String systemId)
+                throws SAXException, IOException {
+            return delegate.parse(is, systemId);
+        }
+
+        public Document parse(String uri) throws SAXException, IOException {
+            return delegate.parse(uri);
+        }
+
+        public Document parse(File f) throws SAXException, IOException {
+            return delegate.parse(f);
+        }
+
+        public Schema getSchema() {
+            return delegate.getSchema();
+        }
+
+        public boolean isXIncludeAware() {
+            return delegate.isXIncludeAware();
+        }
+
+        @Override
+        public Document parse(InputSource is) throws SAXException, IOException {
+            return delegate.parse(is);
+        }
+
+        @Override
+        public boolean isNamespaceAware() {
+            return delegate.isNamespaceAware();
+        }
+
+        @Override
+        public boolean isValidating() {
+            return delegate.isValidating();
+        }
+
+        @Override
+        public void setEntityResolver(EntityResolver er) {
+            delegate.setEntityResolver(er);
+        }
+
+        @Override
+        public void setErrorHandler(ErrorHandler eh) {
+            delegate.setErrorHandler(eh);
+        }
+
+        @Override
+        public Document newDocument() {
+            return delegate.newDocument();
+        }
+
+        @Override
+        public DOMImplementation getDOMImplementation() {
+            return delegate.getDOMImplementation();
+        }
+
+    }
+
+    private static final class DocumentBuilderPool
+        extends WeakObjectPool<DocumentBuilder, ParserConfigurationException> {
+
+        private final boolean validating, disAllowDocTypeDeclarations;
+
+        public DocumentBuilderPool(boolean validating, boolean disAllowDocTypeDeclarations) {
+            this.validating = validating;
+            this.disAllowDocTypeDeclarations = disAllowDocTypeDeclarations;
+        }
+
+        @Override
+        protected DocumentBuilder createObject() throws ParserConfigurationException {
+            DocumentBuilderFactory dfactory = DocumentBuilderFactory.newInstance();
+            dfactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, Boolean.TRUE);
+            if (disAllowDocTypeDeclarations) {
+                dfactory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
+            }
+            dfactory.setValidating(validating);
+            dfactory.setNamespaceAware(true);
+            return new DocumentBuilderProxy(dfactory.newDocumentBuilder(), disAllowDocTypeDeclarations);
+        }
+    }
+
+    /**
+     * Maps the two boolean configuration options for the factories to the array index for the WeakObjectPool
+     * @param validating
+     * @param disAllowDocTypeDeclarations
+     * @return the index to the {@link #pools}
+     */
+    private static int getPoolsIndex(boolean validating, boolean disAllowDocTypeDeclarations) {
+        return (validating ? 2 : 0) + (disAllowDocTypeDeclarations ? 1 : 0);
+    }
+
 }

Modified: santuario/xml-security-java/trunk/src/test/java/org/apache/xml/security/test/dom/secure_val/ForbiddenReferenceTest.java
URL: http://svn.apache.org/viewvc/santuario/xml-security-java/trunk/src/test/java/org/apache/xml/security/test/dom/secure_val/ForbiddenReferenceTest.java?rev=1833179&r1=1833178&r2=1833179&view=diff
==============================================================================
--- santuario/xml-security-java/trunk/src/test/java/org/apache/xml/security/test/dom/secure_val/ForbiddenReferenceTest.java (original)
+++ santuario/xml-security-java/trunk/src/test/java/org/apache/xml/security/test/dom/secure_val/ForbiddenReferenceTest.java Fri Jun  8 14:59:12 2018
@@ -73,6 +73,7 @@ public class ForbiddenReferenceTest exte
 
         javax.xml.parsers.DocumentBuilder db = XMLUtils.createDocumentBuilder(false);
         org.w3c.dom.Document doc = db.parse(f);
+        XMLUtils.repoolDocumentBuilder(db);
 
         Element manifestElement =
             (Element) doc.getElementsByTagNameNS(Constants.SignatureSpecNS,

Modified: santuario/xml-security-java/trunk/src/test/java/org/apache/xml/security/test/dom/signature/SignatureReferenceTest.java
URL: http://svn.apache.org/viewvc/santuario/xml-security-java/trunk/src/test/java/org/apache/xml/security/test/dom/signature/SignatureReferenceTest.java?rev=1833179&r1=1833178&r2=1833179&view=diff
==============================================================================
--- santuario/xml-security-java/trunk/src/test/java/org/apache/xml/security/test/dom/signature/SignatureReferenceTest.java (original)
+++ santuario/xml-security-java/trunk/src/test/java/org/apache/xml/security/test/dom/signature/SignatureReferenceTest.java Fri Jun  8 14:59:12 2018
@@ -127,6 +127,8 @@ public class SignatureReferenceTest {
         referenceElement.appendChild(digestValue);
 
         new WrappedReference(referenceElement, "_54321", null);
+
+        XMLUtils.repoolDocumentBuilder(db);
     }
 
     /**

Added: santuario/xml-security-java/trunk/src/test/java/org/apache/xml/security/test/dom/utils/DocumentBuilderPoolingTest.java
URL: http://svn.apache.org/viewvc/santuario/xml-security-java/trunk/src/test/java/org/apache/xml/security/test/dom/utils/DocumentBuilderPoolingTest.java?rev=1833179&view=auto
==============================================================================
--- santuario/xml-security-java/trunk/src/test/java/org/apache/xml/security/test/dom/utils/DocumentBuilderPoolingTest.java (added)
+++ santuario/xml-security-java/trunk/src/test/java/org/apache/xml/security/test/dom/utils/DocumentBuilderPoolingTest.java Fri Jun  8 14:59:12 2018
@@ -0,0 +1,175 @@
+/**
+ * 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.xml.security.test.dom.utils;
+
+import org.apache.xml.security.utils.WeakObjectPool;
+import org.apache.xml.security.utils.XMLUtils;
+import org.junit.Test;
+
+import javax.xml.parsers.DocumentBuilder;
+import java.lang.ref.WeakReference;
+import java.lang.reflect.Field;
+import java.util.Iterator;
+import java.util.concurrent.*;
+
+import static org.junit.Assert.*;
+
+public class DocumentBuilderPoolingTest {
+
+    private static final String DOCUMENTBUILDERPROXY_CLASSNAME =
+            "org.apache.xml.security.utils.XMLUtils$DocumentBuilderProxy";
+
+    @Test
+    public void testEquals() throws Exception {
+        DocumentBuilder documentBuilder = XMLUtils.createDocumentBuilder(true);
+        assertEquals(documentBuilder, documentBuilder);
+    }
+
+    @Test
+    public void testGetValidatingDocumentBuilder() throws Exception {
+        DocumentBuilder documentBuilder = XMLUtils.createDocumentBuilder(true);
+        assertTrue(documentBuilder.isValidating());
+    }
+
+    @Test
+    public void testGetNonValidatingDocumentBuilder() throws Exception {
+        DocumentBuilder documentBuilder = XMLUtils.createDocumentBuilder(false);
+        assertFalse(documentBuilder.isValidating());
+    }
+
+    @Test
+    public void testGetValidatingAndAllowDocTypeDeclarationsDocumentBuilder() throws Exception {
+        DocumentBuilder documentBuilder = XMLUtils.createDocumentBuilder(true, false);
+        assertTrue(documentBuilder.isValidating());
+        assertEquals(documentBuilder.getClass().getName(), DOCUMENTBUILDERPROXY_CLASSNAME);
+        assertAllowDocTypeDeclarations(documentBuilder, false);
+    }
+
+    @Test
+    public void testGetValidatingAndDisAllowDocTypeDeclarationsDocumentBuilder() throws Exception {
+        DocumentBuilder documentBuilder = XMLUtils.createDocumentBuilder(true, true);
+        assertTrue(documentBuilder.isValidating());
+        assertEquals(documentBuilder.getClass().getName(), DOCUMENTBUILDERPROXY_CLASSNAME);
+        assertAllowDocTypeDeclarations(documentBuilder, true);
+    }
+
+    private void assertAllowDocTypeDeclarations(DocumentBuilder documentBuilder, boolean allow) throws Exception {
+        Field field = documentBuilder.getClass().getDeclaredField("disAllowDocTypeDeclarations");
+        field.setAccessible(true);
+        assertEquals(allow, field.get(documentBuilder));
+    }
+
+    @Test
+    public void testNewDocumentBuilderInstances() throws Exception {
+        int count = 4;
+
+        // get all possible combinations of DocumentBuilders:
+        DocumentBuilder[] documentBuilders = new DocumentBuilder[count];
+        for (int i = 0; i < count; i++) {
+            documentBuilders[i] = XMLUtils.createDocumentBuilder(i / 2 > 0, i % 2 == 1);
+        }
+
+        //test that we got always a new instance:
+        for (int i = 0; i < count; i++) {
+            for (int j = i + 1; j < count; j++) {
+                assertNotEquals(documentBuilders[i], documentBuilders[j]);
+                assertNotSame(documentBuilders[i], documentBuilders[j]);
+            }
+        }
+    }
+
+    @Test
+    public void testRepoolingTwice() throws Exception {
+        DocumentBuilder documentBuilder = XMLUtils.createDocumentBuilder(true);
+        assertTrue(XMLUtils.repoolDocumentBuilder(documentBuilder));
+        assertFalse("can't repool the same object twice!", XMLUtils.repoolDocumentBuilder(documentBuilder));
+    }
+
+    @Test(timeout = 30000)
+    public void testPooling() throws Exception {
+        int nThreads = 8;
+        ExecutorService exec = Executors.newFixedThreadPool(nThreads);
+        Future<?>[] results = new Future[nThreads];
+        for (int i = 0; i < nThreads - 1; i++) {
+            results[i] = exec.submit(new Runnable() {
+                @Override
+                public void run() {
+                    try {
+                        while (true) {
+                            // retrieve some DocumentBuilders...
+                            DocumentBuilder documentBuilders[] = new DocumentBuilder[10];
+                            for (int j = 0; j < documentBuilders.length; j++) {
+                                documentBuilders[j] = XMLUtils.createDocumentBuilder(false);
+                                assertNotNull(documentBuilders[j]);
+                            }
+                            // ...then repool them so that another thread may pickup them again
+                            for (int j = 0; j < documentBuilders.length; j++) {
+                                assertTrue(XMLUtils.repoolDocumentBuilder(documentBuilders[j]));
+                            }
+                        }
+                    } catch (Exception e) {
+                        throw new RuntimeException(e);
+                    }
+                }
+            });
+        }
+        // more or less mimic gc
+        results[nThreads - 1] = exec.submit(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    final Field poolField = XMLUtils.class.getDeclaredField("pools");
+                    poolField.setAccessible(true);
+                    final WeakObjectPool[] weakObjectPools = (WeakObjectPool[]) poolField.get(null);
+
+                    final Field availableField = WeakObjectPool.class.getDeclaredField("available");
+                    availableField.setAccessible(true);
+
+                    while (true) {
+                        final BlockingDeque blockingDeque = (BlockingDeque) availableField.get(weakObjectPools[1]);
+                        Iterator iterator = blockingDeque.iterator();
+                        while (iterator.hasNext()) {
+                            ((WeakReference) iterator.next()).clear();
+                        }
+                        Thread.sleep(200);
+                    }
+                } catch (InterruptedException e) {
+                    return;
+                } catch (Exception e) {
+                    throw new RuntimeException(e);
+                }
+            }
+        });
+
+        exec.shutdown();
+        exec.awaitTermination(5, TimeUnit.SECONDS);
+        for (Future<?> f : results) {
+            if (!f.isDone()) {
+                f.cancel(false);
+            }
+            try {
+                assertNull(f.get(1000, TimeUnit.MILLISECONDS));
+            } catch (CancellationException ce) {
+                //expected since we did cancel it
+            } catch (TimeoutException e) {
+                fail(f + "didn't cancel after timeout?");
+            }
+        }
+    }
+}