XMLBEANS-502: Allow to manually clear ThreadLocals via a new ThreadLocalUtil.clearAllThreadLocals()
This allows to avoid memory leaks or log warnings in applications that
make heavy use of thread-pools or web-containers, e.g. Tomcat
git-svn-id: https://svn.apache.org/repos/asf/xmlbeans/trunk@1855161 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/CHANGES.txt b/CHANGES.txt
index 03a9ec0..997fe58 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,5 +1,6 @@
Changes in V3.0.3 since V3.0.2
+* XMLBEANS-502: Allow to clear all ThreadLocals from the current thread
* XMLBEANS-503: Allow to specify -nowarn in the Ant task
* XMLBEANS-537: Add missing StscState.end() to avoid memory leaks
* XMLBEANS-532: Streamline build.xml and update tests to Junit4
diff --git a/src/common/org/apache/xmlbeans/impl/common/SystemCache.java b/src/common/org/apache/xmlbeans/impl/common/SystemCache.java
index 580a1f7..0520c59 100644
--- a/src/common/org/apache/xmlbeans/impl/common/SystemCache.java
+++ b/src/common/org/apache/xmlbeans/impl/common/SystemCache.java
@@ -95,6 +95,10 @@
private ThreadLocal tl_saxLoaders = new ThreadLocal();
+ public void clearThreadLocals() {
+ tl_saxLoaders.remove();
+ }
+
public Object getSaxLoader()
{
SoftReference s = (SoftReference) tl_saxLoaders.get();
diff --git a/src/store/org/apache/xmlbeans/impl/store/CharUtil.java b/src/store/org/apache/xmlbeans/impl/store/CharUtil.java
index c3b8fa0..2c8f86d 100755
--- a/src/store/org/apache/xmlbeans/impl/store/CharUtil.java
+++ b/src/store/org/apache/xmlbeans/impl/store/CharUtil.java
@@ -909,6 +909,10 @@
private static ThreadLocal tl_charUtil =
new ThreadLocal() { protected Object initialValue() { return new SoftReference(new CharUtil( CHARUTIL_INITIAL_BUFSIZE )); } };
+ public static void clearThreadLocals() {
+ tl_charUtil.remove();
+ }
+
private CharIterator _charIter = new CharIterator();
// TODO - 64 is kinda arbitrary. Perhaps it should be configurable.
diff --git a/src/store/org/apache/xmlbeans/impl/store/Locale.java b/src/store/org/apache/xmlbeans/impl/store/Locale.java
index e63466d..ab6230f 100755
--- a/src/store/org/apache/xmlbeans/impl/store/Locale.java
+++ b/src/store/org/apache/xmlbeans/impl/store/Locale.java
@@ -1897,6 +1897,10 @@
}
};
+ public static void clearThreadLocals() {
+ tl_scrubBuffer.remove();
+ }
+
static ScrubBuffer getScrubBuffer(int wsr)
{
SoftReference softRef = (SoftReference) tl_scrubBuffer.get();
diff --git a/src/typeimpl/org/apache/xmlbeans/impl/schema/SchemaTypeLoaderImpl.java b/src/typeimpl/org/apache/xmlbeans/impl/schema/SchemaTypeLoaderImpl.java
index 04c8e47..a4e9472 100644
--- a/src/typeimpl/org/apache/xmlbeans/impl/schema/SchemaTypeLoaderImpl.java
+++ b/src/typeimpl/org/apache/xmlbeans/impl/schema/SchemaTypeLoaderImpl.java
@@ -71,6 +71,13 @@
private ThreadLocal _cachedTypeSystems =
new ThreadLocal() { protected Object initialValue() { return new ArrayList(); } };
+ @Override
+ public void clearThreadLocals() {
+ _cachedTypeSystems.remove();
+
+ super.clearThreadLocals();
+ }
+
public SchemaTypeLoader getFromTypeLoaderCache(ClassLoader cl)
{
ArrayList a = (ArrayList) _cachedTypeSystems.get();
diff --git a/src/typeimpl/org/apache/xmlbeans/impl/schema/StscState.java b/src/typeimpl/org/apache/xmlbeans/impl/schema/StscState.java
index c03a094..f464200 100644
--- a/src/typeimpl/org/apache/xmlbeans/impl/schema/StscState.java
+++ b/src/typeimpl/org/apache/xmlbeans/impl/schema/StscState.java
@@ -1267,6 +1267,10 @@
private static ThreadLocal tl_stscStack = new ThreadLocal();
+ public static void clearThreadLocals() {
+ tl_stscStack.remove();
+ }
+
public static StscState start()
{
StscStack stscStack = (StscStack) tl_stscStack.get();
diff --git a/src/typeimpl/org/apache/xmlbeans/impl/values/NamespaceContext.java b/src/typeimpl/org/apache/xmlbeans/impl/values/NamespaceContext.java
index 692197c..f7be564 100644
--- a/src/typeimpl/org/apache/xmlbeans/impl/values/NamespaceContext.java
+++ b/src/typeimpl/org/apache/xmlbeans/impl/values/NamespaceContext.java
@@ -90,6 +90,10 @@
private static ThreadLocal tl_namespaceContextStack = new ThreadLocal();
+ public static void clearThreadLocals() {
+ tl_namespaceContextStack.remove();
+ }
+
private static NamespaceContextStack getNamespaceContextStack()
{
NamespaceContextStack namespaceContextStack = (NamespaceContextStack) tl_namespaceContextStack.get();
diff --git a/src/xmlpublic/org/apache/xmlbeans/ThreadLocalUtil.java b/src/xmlpublic/org/apache/xmlbeans/ThreadLocalUtil.java
new file mode 100644
index 0000000..614cade
--- /dev/null
+++ b/src/xmlpublic/org/apache/xmlbeans/ThreadLocalUtil.java
@@ -0,0 +1,46 @@
+/* Copyright 2004 The Apache Software Foundation
+ *
+ * Licensed 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.xmlbeans;
+
+import org.apache.xmlbeans.impl.common.SystemCache;
+import org.apache.xmlbeans.impl.schema.StscState;
+import org.apache.xmlbeans.impl.store.CharUtil;
+import org.apache.xmlbeans.impl.store.Locale;
+import org.apache.xmlbeans.impl.values.NamespaceContext;
+
+public class ThreadLocalUtil {
+
+ /**
+ * Clear {@link ThreadLocal}s of the current thread.
+ *
+ * This can be used to clean out a thread before "returning"
+ * it to a thread-pool or a Web-Container like Tomcat.
+ */
+ public static void clearAllThreadLocals() {
+ // clear thread locals in all classes which may hold some
+ XmlBeans.clearThreadLocals();
+ XmlFactoryHook.ThreadContext.clearThreadLocals();
+ StscState.clearThreadLocals();
+ CharUtil.clearThreadLocals();
+ Locale.clearThreadLocals();
+ NamespaceContext.clearThreadLocals();
+
+ // SystemCache is not a singleton, but also creates ThreadLocals,
+ // so we get the current instance and clean it out as well
+ SystemCache systemCache = SystemCache.get();
+ systemCache.clearThreadLocals();
+ }
+}
diff --git a/src/xmlpublic/org/apache/xmlbeans/XmlBeans.java b/src/xmlpublic/org/apache/xmlbeans/XmlBeans.java
index 4d271bf..9cfd544 100644
--- a/src/xmlpublic/org/apache/xmlbeans/XmlBeans.java
+++ b/src/xmlpublic/org/apache/xmlbeans/XmlBeans.java
@@ -90,6 +90,11 @@
}
};
+ public static void clearThreadLocals() {
+ // clear thread local here
+ _threadLocalLoaderQNameCache.remove();
+ }
+
/**
* Returns a thread local QNameCache
*/
diff --git a/src/xmlpublic/org/apache/xmlbeans/XmlFactoryHook.java b/src/xmlpublic/org/apache/xmlbeans/XmlFactoryHook.java
index 6aca07f..55e7cc8 100644
--- a/src/xmlpublic/org/apache/xmlbeans/XmlFactoryHook.java
+++ b/src/xmlpublic/org/apache/xmlbeans/XmlFactoryHook.java
@@ -92,6 +92,10 @@
{
private static ThreadLocal threadHook = new ThreadLocal();
+ public static void clearThreadLocals() {
+ threadHook.remove();
+ }
+
/**
* Returns the current thread's hook, or null if none.
*/
diff --git a/test/src/misc/checkin/CharUtilTests.java b/test/src/misc/checkin/CharUtilTests.java
index ecf65c1..28302e5 100644
--- a/test/src/misc/checkin/CharUtilTests.java
+++ b/test/src/misc/checkin/CharUtilTests.java
@@ -22,6 +22,7 @@
import java.util.Random;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
public class CharUtilTests
{
@@ -232,4 +233,11 @@
}
private Random _rnd = new Random( 0 );
+
+ @Test
+ public void testThreadLocal() {
+ assertNotNull("Should always get a CharUtil from ThreadLocals", CharUtil.getThreadLocalCharUtil());
+ CharUtil.clearThreadLocals();
+ assertNotNull("Should always get a CharUtil from ThreadLocals", CharUtil.getThreadLocalCharUtil());
+ }
}
\ No newline at end of file
diff --git a/test/src/misc/detailed/SystemCacheTests.java b/test/src/misc/detailed/SystemCacheTests.java
index 36a6acd..16bfaee 100644
--- a/test/src/misc/detailed/SystemCacheTests.java
+++ b/test/src/misc/detailed/SystemCacheTests.java
@@ -20,10 +20,11 @@
import org.junit.Test;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
public class SystemCacheTests {
@Test
- public void testSystemCacheImplFromAPITest() throws Throwable {
+ public void testSystemCacheImplFromAPITest() {
// store the default SystemCache implementation before switch
SystemCache defaultImpl = SystemCache.get();
@@ -33,11 +34,25 @@
SystemCacheTestImpl testImpl = new SystemCacheTestImpl();
SystemCache.set(testImpl);
assertEquals("misc.detailed.SystemCacheTestImpl", testImpl.getClass().getName());
- assertEquals(testImpl.getAccessed(), 1);
+ assertEquals(SystemCacheTestImpl.getAccessed(), 1);
// switch back to default impl
SystemCache.set(defaultImpl);
assertEquals("org.apache.xmlbeans.impl.common.SystemCache", defaultImpl.getClass().getName());
}
+ @Test
+ public void testClearThreadLocal() {
+ SystemCache cache = SystemCache.get();
+ String saxLoader = "object is not cast currently...";
+
+ cache.setSaxLoader(saxLoader);
+ assertEquals(saxLoader, cache.getSaxLoader());
+
+ cache.clearThreadLocals();
+ assertNull(cache.getSaxLoader());
+
+ cache.setSaxLoader(saxLoader);
+ assertEquals(saxLoader, cache.getSaxLoader());
+ }
}
diff --git a/test/src/misc/detailed/ThreadLocalUtilTest.java b/test/src/misc/detailed/ThreadLocalUtilTest.java
new file mode 100644
index 0000000..b0335c8
--- /dev/null
+++ b/test/src/misc/detailed/ThreadLocalUtilTest.java
@@ -0,0 +1,44 @@
+/* Copyright 2004 The Apache Software Foundation
+ *
+ * Licensed 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 misc.detailed;
+
+import org.apache.xmlbeans.ThreadLocalUtil;
+import org.apache.xmlbeans.impl.common.SystemCache;
+import org.apache.xmlbeans.impl.schema.StscState;
+import org.apache.xmlbeans.impl.store.CharUtil;
+import org.junit.Test;
+
+public class ThreadLocalUtilTest {
+ @Test
+ public void testClearThreadLocalsNoData() {
+ // simply calling it without any thread locals should work
+ ThreadLocalUtil.clearAllThreadLocals();
+ }
+
+ @Test
+ public void testClearThreadLocalsWithData() {
+ // calling it with thread locals should work as well
+ CharUtil.getThreadLocalCharUtil();
+
+ SystemCache cache = SystemCache.get();
+ String saxLoader = "object is not cast currently...";
+ cache.setSaxLoader(saxLoader);
+ StscState.start();
+ StscState.end();
+
+ ThreadLocalUtil.clearAllThreadLocals();
+ }
+}