[maven-release-plugin] copy for tag xmlsec-2.0.11

git-svn-id: https://svn.apache.org/repos/asf/santuario/xml-security-java/tags/xmlsec-2.0.11@1833053 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/pom.xml b/pom.xml
index 8f761f2..727dbbb 100644
--- a/pom.xml
+++ b/pom.xml
@@ -573,6 +573,12 @@
             <version>${bcprov.version}</version>
             <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>com.carrotsearch</groupId>
+            <artifactId>junit-benchmarks</artifactId>
+            <version>0.7.2</version>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
 
     <distributionManagement>
diff --git a/src/main/java/org/apache/xml/security/utils/XMLUtils.java b/src/main/java/org/apache/xml/security/utils/XMLUtils.java
index e627db8..9aa9919 100644
--- a/src/main/java/org/apache/xml/security/utils/XMLUtils.java
+++ b/src/main/java/org/apache/xml/security/utils/XMLUtils.java
@@ -23,14 +23,12 @@
 import java.security.AccessController;
 import java.security.PrivilegedAction;
 import java.util.ArrayList;
-import java.util.Collections;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
-import java.util.Map;
 import java.util.Set;
-import java.util.WeakHashMap;
 
+import javax.xml.XMLConstants;
 import javax.xml.parsers.DocumentBuilder;
 import javax.xml.parsers.DocumentBuilderFactory;
 import javax.xml.parsers.ParserConfigurationException;
@@ -61,8 +59,14 @@
             }
         });
 
-    private static final Map<ClassLoader, DocumentBuilder[][]> DOCUMENT_BUILDERS =
-        Collections.synchronizedMap(new WeakHashMap<ClassLoader, DocumentBuilder[][]>());
+    @SuppressWarnings("unchecked")
+    private static final ThreadLocal<DocumentBuilder> tl[][] = new ThreadLocal[2][2];
+    static {
+        tl[0][0] = new MyThreadLocal(false, false);
+        tl[0][1] = new MyThreadLocal(false, true);
+        tl[1][0] = new MyThreadLocal(true, false);
+        tl[1][1] = new MyThreadLocal(true, true);
+    }
 
     private static volatile String dsPrefix = "ds";
     private static volatile String ds11Prefix = "dsig11";
@@ -1057,9 +1061,9 @@
     public static DocumentBuilder createDocumentBuilder(
         boolean validating, boolean disAllowDocTypeDeclarations
     ) throws ParserConfigurationException {
-        DocumentBuilder db = getDocumentBuilder(validating, disAllowDocTypeDeclarations);
-        db.reset();
-        return db;
+        DocumentBuilder documentBuilder = tl[validating ? 1 : 0][disAllowDocTypeDeclarations ? 1 : 0].get();
+        documentBuilder.reset();
+        return documentBuilder;
     }
 
     /**
@@ -1072,63 +1076,31 @@
         return true;
     }
 
-    private static DocumentBuilder getDocumentBuilder(boolean validating, boolean disAllowDocTypeDeclarations) throws ParserConfigurationException {
-        ClassLoader loader = getContextClassLoader();
-        if (loader == null) {
-            loader = getClassLoader(XMLUtils.class);
-        }
-        if (loader == null) {
-            return newDocumentBuilder(validating, disAllowDocTypeDeclarations);
+    private static final class MyThreadLocal extends ThreadLocal<DocumentBuilder> {
+        private final boolean validating;
+        private final boolean disAllowDocTypeDeclarations;
+
+        public MyThreadLocal(boolean validating, boolean disAllowDocTypeDeclarations) {
+            this.validating = validating;
+            this.disAllowDocTypeDeclarations = disAllowDocTypeDeclarations;
         }
 
-        DocumentBuilder[][] cacheValue = DOCUMENT_BUILDERS.get(loader);
-        if (cacheValue == null) {
-            cacheValue = new DocumentBuilder[2][2];
-            DOCUMENT_BUILDERS.put(loader, cacheValue);
-        }
-
-        DocumentBuilder db = cacheValue[validating ? 1 : 0][disAllowDocTypeDeclarations ? 1 : 0];
-        if (db == null) {
-            db = newDocumentBuilder(validating, disAllowDocTypeDeclarations);
-            cacheValue[validating ? 1 : 0][disAllowDocTypeDeclarations ? 1 : 0] = db;
-        }
-
-        return db;
-    }
-
-    private static DocumentBuilder newDocumentBuilder(boolean validating, boolean disAllowDocTypeDeclarations) throws ParserConfigurationException {
-        DocumentBuilderFactory f = DocumentBuilderFactory.newInstance();
-        f.setNamespaceAware(true);
-        f.setFeature(javax.xml.XMLConstants.FEATURE_SECURE_PROCESSING, true);
-        if (disAllowDocTypeDeclarations) {
-            f.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
-        }
-        f.setValidating(validating);
-        return f.newDocumentBuilder();
-    }
-
-    private static ClassLoader getContextClassLoader() {
-        final SecurityManager sm = System.getSecurityManager();
-        if (sm != null) {
-            return AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() {
-                public ClassLoader run() {
-                    return Thread.currentThread().getContextClassLoader();
+        @Override
+        protected DocumentBuilder initialValue() {
+            DocumentBuilderFactory dfactory = DocumentBuilderFactory.newInstance();
+            try {
+                dfactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, Boolean.TRUE);
+                if (disAllowDocTypeDeclarations) {
+                    dfactory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
                 }
-            });
-        }
-        return Thread.currentThread().getContextClassLoader();
-    }
+                dfactory.setValidating(validating);
+                dfactory.setNamespaceAware(true);
 
-    private static ClassLoader getClassLoader(final Class<?> clazz) {
-        final SecurityManager sm = System.getSecurityManager();
-        if (sm != null) {
-            return AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() {
-                public ClassLoader run() {
-                    return clazz.getClassLoader();
-                }
-            });
+                return dfactory.newDocumentBuilder();
+            } catch (ParserConfigurationException e) {
+               throw new RuntimeException(e);
+            }
         }
-        return clazz.getClassLoader();
     }
 
 }
diff --git a/src/test/java/org/apache/xml/security/test/dom/utils/XMLUtilsPerformanceTest.java b/src/test/java/org/apache/xml/security/test/dom/utils/XMLUtilsPerformanceTest.java
new file mode 100644
index 0000000..3d896bb
--- /dev/null
+++ b/src/test/java/org/apache/xml/security/test/dom/utils/XMLUtilsPerformanceTest.java
@@ -0,0 +1,42 @@
+/**
+ * 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 java.io.StringReader;
+
+import org.apache.xml.security.utils.XMLUtils;
+import org.junit.Test;
+import org.xml.sax.InputSource;
+
+import com.carrotsearch.junitbenchmarks.AbstractBenchmark;
+import com.carrotsearch.junitbenchmarks.BenchmarkOptions;
+
+/**
+ * Some benchmark tests for the caching logic in XMLUtils
+ */
+public class XMLUtilsPerformanceTest extends AbstractBenchmark {
+
+    @BenchmarkOptions(callgc = false, benchmarkRounds = 100000, warmupRounds = 100)
+    @Test
+    public void testCreateDocumentBuilder() throws Exception {
+        InputSource inputSource = new InputSource(new StringReader("<xml>123</xml>"));
+        XMLUtils.createDocumentBuilder(false).parse(inputSource);
+    }
+
+}