You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@commons.apache.org by ha...@apache.org on 2004/03/01 16:32:40 UTC
cvs commit: jakarta-commons-sandbox/hivemind/framework/src/java/org/apache/hivemind/service/impl ThreadLocalStorageImpl.java
harishkswamy 2004/03/01 07:32:39
Modified: hivemind/framework/src/test/hivemind/test/services
TestThreadLocalStorage.java
hivemind/framework/src/java/org/apache/hivemind/service/impl
ThreadLocalStorageImpl.java
Log:
Fix ThreadCleanupListener registration.
Revision Changes Path
1.6 +72 -7 jakarta-commons-sandbox/hivemind/framework/src/test/hivemind/test/services/TestThreadLocalStorage.java
Index: TestThreadLocalStorage.java
===================================================================
RCS file: /home/cvs/jakarta-commons-sandbox/hivemind/framework/src/test/hivemind/test/services/TestThreadLocalStorage.java,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -r1.5 -r1.6
--- TestThreadLocalStorage.java 26 Feb 2004 23:07:36 -0000 1.5
+++ TestThreadLocalStorage.java 1 Mar 2004 15:32:39 -0000 1.6
@@ -1,4 +1,4 @@
-// Copyright 2004 The Apache Software Foundation
+// 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.
@@ -14,22 +14,24 @@
package hivemind.test.services;
+import hivemind.test.FrameworkTestCase;
+
import org.apache.hivemind.service.ThreadEventNotifier;
import org.apache.hivemind.service.ThreadLocalStorage;
import org.apache.hivemind.service.impl.ThreadEventNotifierImpl;
import org.apache.hivemind.service.impl.ThreadLocalStorageImpl;
-import hivemind.test.FrameworkTestCase;
-
/**
* Tests for {@link org.apache.hivemind.service.impl.ThreadLocalStorageImpl}.
- *
- * @author Howard Lewis Ship
+ *
+ * @author Howard Lewis Ship, Harish Krishnaswamy
* @version $Id$
*/
public class TestThreadLocalStorage extends FrameworkTestCase
{
private ThreadLocalStorage _s = new ThreadLocalStorageImpl();
+ private Throwable _testRunnerFailure;
+ private boolean _testRunnerCompleted;
public void testGetEmpty()
{
@@ -67,7 +69,6 @@
ThreadLocalStorageImpl s = new ThreadLocalStorageImpl();
s.setNotifier(notifier);
- s.initializeService();
s.put("biff", "bamf");
@@ -78,4 +79,68 @@
assertNull(s.get("biff"));
}
+ private class TestRunner implements Runnable
+ {
+ private ThreadLocalStorage _local;
+ private ThreadEventNotifier _notifier;
+
+ private TestRunner(ThreadLocalStorage local, ThreadEventNotifier notifier)
+ {
+ _local = local;
+ _notifier = notifier;
+ }
+
+ public void run()
+ {
+ _local.put("session", "Test Runner Session");
+
+ assertEquals(_local.get("session"), "Test Runner Session");
+
+ _notifier.fireThreadCleanup();
+
+ assertNull(_local.get("session"));
+
+ _testRunnerCompleted = true;
+ }
+ }
+
+ private class TestThreadGroup extends ThreadGroup
+ {
+ public TestThreadGroup(String name)
+ {
+ super(name);
+ }
+
+ public void uncaughtException(Thread th, Throwable t)
+ {
+ _testRunnerFailure = t;
+ _testRunnerCompleted = true;
+ }
+ }
+
+ public void testThreadCleanup() throws Throwable
+ {
+ ThreadEventNotifier notifier = new ThreadEventNotifierImpl();
+ ThreadLocalStorageImpl local = new ThreadLocalStorageImpl();
+
+ local.setNotifier(notifier);
+
+ local.put("session", "Main Session");
+
+ TestRunner tr = new TestRunner(local, notifier);
+ TestThreadGroup tg = new TestThreadGroup("Test Thread Group");
+ new Thread(tg, tr).start();
+
+ while (!_testRunnerCompleted)
+ Thread.yield();
+
+ if (_testRunnerFailure != null)
+ throw _testRunnerFailure;
+
+ assertEquals(local.get("session"), "Main Session");
+
+ notifier.fireThreadCleanup();
+
+ assertNull(local.get("session"));
+ }
}
1.2 +55 -27 jakarta-commons-sandbox/hivemind/framework/src/java/org/apache/hivemind/service/impl/ThreadLocalStorageImpl.java
Index: ThreadLocalStorageImpl.java
===================================================================
RCS file: /home/cvs/jakarta-commons-sandbox/hivemind/framework/src/java/org/apache/hivemind/service/impl/ThreadLocalStorageImpl.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- ThreadLocalStorageImpl.java 26 Feb 2004 23:07:45 -0000 1.1
+++ ThreadLocalStorageImpl.java 1 Mar 2004 15:32:39 -0000 1.2
@@ -1,4 +1,4 @@
-// Copyright 2004 The Apache Software Foundation
+// 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.
@@ -20,41 +20,78 @@
import org.apache.hivemind.service.ThreadCleanupListener;
import org.apache.hivemind.service.ThreadEventNotifier;
import org.apache.hivemind.service.ThreadLocalStorage;
-import org.apache.hivemind.Initializable;
/**
* Implementation of {@link org.apache.hivemind.service.ThreadLocalStorage}.
- *
- * @author Howard Lewis Ship
+ *
+ * @author Howard Lewis Ship, Harish Krishnaswamy
* @version $Id$
*/
-public class ThreadLocalStorageImpl
- implements ThreadLocalStorage, Initializable, ThreadCleanupListener
+public class ThreadLocalStorageImpl implements ThreadLocalStorage, ThreadCleanupListener
{
- private ThreadLocal _local = new ThreadLocal();
+ private static final String INITIALIZED_KEY = "initialized";
- private ThreadEventNotifier _notifier;
+ private CleanableThreadLocal _local = new CleanableThreadLocal();
+ private ThreadEventNotifier _notifier;
- public Object get(String key)
+ private static class CleanableThreadLocal extends ThreadLocal
{
- Map map = (Map) _local.get();
+ /**
+ * <p>
+ * Intializes the variable with a HashMap containing a single Boolean flag to denote the
+ * initialization of the variable. The Boolean flag will be used to determine when to
+ * register the listener with {@link ThreadEventNotifier}.
+ * <p>
+ * The registration cannot be done from here because it may get lost once the caller method (
+ * {@link ThreadLocal#get()} or {@link ThreadLocal#set(java.lang.Object)} completes, if
+ * this was the first ThreadLocal variable access for the Thread.
+ */
+ protected Object initialValue()
+ {
+ // NOTE: This is a workaround to circumvent the ThreadLocal behavior.
+ // It would be easier if the implementation of ThreadLocal.get() checked for
+ // the existence of the thread local map, after initialValue() is evaluated,
+ // and used it instead of creating a new map always after initialization (possibly
+ // overwriting any variables created from within ThreadLocal.initialValue()).
- if (map == null)
- return null;
+ Map map = new HashMap();
+ map.put(INITIALIZED_KEY, Boolean.TRUE);
- return map.get(key);
+ return map;
+ }
}
- public void put(String key, Object value)
+ /**
+ * Gets the thread local variable and registers the listener with {@link ThreadEventNotifier}
+ * if the thread local variable has been initialized. The registration cannot be done from
+ * within {@link CleanableThreadLocal#initialValue()}because the notifier's thread local
+ * variable will be overwritten and the listeners for the thread will be lost.
+ */
+ private Map getThreadLocalVariable()
{
Map map = (Map) _local.get();
- if (map == null)
+ if (Boolean.TRUE.equals(map.get(INITIALIZED_KEY)) && _notifier != null)
{
- map = new HashMap();
- _local.set(map);
+ _notifier.addThreadCleanupListener(this);
+
+ map.remove(INITIALIZED_KEY);
}
+ return map;
+ }
+
+ public Object get(String key)
+ {
+ Map map = getThreadLocalVariable();
+
+ return map.get(key);
+ }
+
+ public void put(String key, Object value)
+ {
+ Map map = getThreadLocalVariable();
+
map.put(key, value);
}
@@ -69,15 +106,6 @@
public void setNotifier(ThreadEventNotifier notifier)
{
_notifier = notifier;
- }
-
- /**
- * Initializes the service; the implementation registers itself
- * with the {@link ThreadEventNotifier} as a {@link ThreadCleanupListener}.
- */
- public void initializeService()
- {
- _notifier.addThreadCleanupListener(this);
}
/**
---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org