hivemind-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From hls...@apache.org
Subject svn commit: r357642 - in /jakarta/hivemind/branches/branch-1-1: ./ framework/src/descriptor/META-INF/ framework/src/java/org/apache/hivemind/impl/ framework/src/java/org/apache/hivemind/impl/servicemodel/ framework/src/java/org/apache/hivemind/internal...
Date Mon, 19 Dec 2005 05:37:34 GMT
Author: hlship
Date: Sun Dec 18 21:37:09 2005
New Revision: 357642

URL: http://svn.apache.org/viewcvs?rev=357642&view=rev
Log:
HIVEMIND-162: Performance bottleneck with threaded services
HIVEMIND-161: ThreadLocal object is never removed in ThreadEventNotifierImpl and holds the classloader

Modified:
    jakarta/hivemind/branches/branch-1-1/framework/src/descriptor/META-INF/hivemodule.xml
    jakarta/hivemind/branches/branch-1-1/framework/src/java/org/apache/hivemind/impl/ConstructableServicePoint.java
    jakarta/hivemind/branches/branch-1-1/framework/src/java/org/apache/hivemind/impl/InvokeFactoryServiceConstructor.java
    jakarta/hivemind/branches/branch-1-1/framework/src/java/org/apache/hivemind/impl/ServicePointImpl.java
    jakarta/hivemind/branches/branch-1-1/framework/src/java/org/apache/hivemind/impl/servicemodel/AbstractServiceModelImpl.java
    jakarta/hivemind/branches/branch-1-1/framework/src/java/org/apache/hivemind/impl/servicemodel/PooledServiceModel.java
    jakarta/hivemind/branches/branch-1-1/framework/src/java/org/apache/hivemind/impl/servicemodel/PrimitiveServiceModel.java
    jakarta/hivemind/branches/branch-1-1/framework/src/java/org/apache/hivemind/impl/servicemodel/SingletonServiceModel.java
    jakarta/hivemind/branches/branch-1-1/framework/src/java/org/apache/hivemind/impl/servicemodel/ThreadedServiceModel.java
    jakarta/hivemind/branches/branch-1-1/framework/src/java/org/apache/hivemind/internal/ser/ServiceSerializationHelper.java
    jakarta/hivemind/branches/branch-1-1/framework/src/java/org/apache/hivemind/service/ThreadEventNotifier.java
    jakarta/hivemind/branches/branch-1-1/framework/src/java/org/apache/hivemind/service/impl/ServiceMessages.java
    jakarta/hivemind/branches/branch-1-1/framework/src/java/org/apache/hivemind/service/impl/ServiceStrings.properties
    jakarta/hivemind/branches/branch-1-1/framework/src/java/org/apache/hivemind/service/impl/ThreadEventNotifierImpl.java
    jakarta/hivemind/branches/branch-1-1/framework/src/java/org/apache/hivemind/service/impl/ThreadLocalStorageImpl.java
    jakarta/hivemind/branches/branch-1-1/framework/src/java/org/apache/hivemind/util/IdUtils.java
    jakarta/hivemind/branches/branch-1-1/framework/src/test/hivemind/test/services/TestThreadEventNotifier.java
    jakarta/hivemind/branches/branch-1-1/framework/src/test/hivemind/test/services/TestThreadLocalStorage.java
    jakarta/hivemind/branches/branch-1-1/framework/src/test/org/apache/hivemind/impl/TestServiceModelThreading.java
    jakarta/hivemind/branches/branch-1-1/jmx/src/java/org/apache/hivemind/management/impl/PerformanceMonitorFactory.java
    jakarta/hivemind/branches/branch-1-1/jmx/src/java/org/apache/hivemind/management/log4j/LoggerMBean.java
    jakarta/hivemind/branches/branch-1-1/jmx/src/test/org/apache/hivemind/management/TestMBeanRegistry.java
    jakarta/hivemind/branches/branch-1-1/status.xml

Modified: jakarta/hivemind/branches/branch-1-1/framework/src/descriptor/META-INF/hivemodule.xml
URL: http://svn.apache.org/viewcvs/jakarta/hivemind/branches/branch-1-1/framework/src/descriptor/META-INF/hivemodule.xml?rev=357642&r1=357641&r2=357642&view=diff
==============================================================================
--- jakarta/hivemind/branches/branch-1-1/framework/src/descriptor/META-INF/hivemodule.xml (original)
+++ jakarta/hivemind/branches/branch-1-1/framework/src/descriptor/META-INF/hivemodule.xml Sun Dec 18 21:37:09 2005
@@ -486,12 +486,10 @@
     Service which manages a thread-local map of data items. 
     This can be used for temporary storage of information when local variables can't be used. 
     All stored items are released when the thread is cleaned up.
+    Note: this service should be considered deprecated; use the threaded service model
+    instead.
       
-    <invoke-factory>
-      <construct class="service.impl.ThreadLocalStorageImpl">
-        <set-service property="notifier" service-id="ThreadEventNotifier"/>
-      </construct>
-    </invoke-factory>
+    <create-instance model="threaded" class="service.impl.ThreadLocalStorageImpl"/>
   </service-point>
   
   <configuration-point id="ServiceModels">

Modified: jakarta/hivemind/branches/branch-1-1/framework/src/java/org/apache/hivemind/impl/ConstructableServicePoint.java
URL: http://svn.apache.org/viewcvs/jakarta/hivemind/branches/branch-1-1/framework/src/java/org/apache/hivemind/impl/ConstructableServicePoint.java?rev=357642&r1=357641&r2=357642&view=diff
==============================================================================
--- jakarta/hivemind/branches/branch-1-1/framework/src/java/org/apache/hivemind/impl/ConstructableServicePoint.java (original)
+++ jakarta/hivemind/branches/branch-1-1/framework/src/java/org/apache/hivemind/impl/ConstructableServicePoint.java Sun Dec 18 21:37:09 2005
@@ -16,14 +16,14 @@
 
 import java.util.List;
 
-import org.apache.hivemind.*;
-import org.apache.hivemind.internal.ServicePoint;
+import org.apache.hivemind.events.RegistryShutdownListener;
 import org.apache.hivemind.internal.ServiceImplementationConstructor;
+import org.apache.hivemind.internal.ServicePoint;
 
 /**
- * "Private" interface used by a {@link org.apache.hivemind.internal.ServiceModel}s to access
- * non-public information about a {@link org.apache.hivemind.internal.ServicePoint}, such as its
- * instance builder and interceptors.
+ * "Private" interface used by a {@link org.apache.hivemind.internal.ServiceModel}s to access non-
+ * information about a {@link org.apache.hivemind.internal.ServicePoint}, such as its instance
+ * builder and interceptors.
  * 
  * @author Howard Lewis Ship
  */
@@ -35,11 +35,11 @@
      * comes from the &lt;service-point&gt; itself; other modules can override this default using an
      * &lt;implementation&gt; element.
      */
-    public ServiceImplementationConstructor getServiceConstructor();
+    ServiceImplementationConstructor getServiceConstructor();
 
     /**
-     * Returns a list of {@link org.apache.hivemind.internal.ServiceInterceptorContribution}s, ordered
-     * according to their dependencies. May return null or an empty list.
+     * Returns a list of {@link org.apache.hivemind.internal.ServiceInterceptorContribution}s,
+     * ordered according to their dependencies. May return null or an empty list.
      * <p>
      * Note that the order is tricky! To keep any error messages while ordering the interceptors
      * understandable, they are ordered according into runtime execution order. Example: If we want
@@ -47,8 +47,8 @@
      * following in the descriptor:
      * 
      * <pre>
-     *           &lt;interceptor service-id=&quot;hivemind.LoggingInterceptor&quot; before=&quot;*&quot;/&gt;
-     *           &lt;interceptor service-id=&quot;somepackage.SecurityInterceptor&quot;/&gt;
+     *               &lt;interceptor service-id=&quot;hivemind.LoggingInterceptor&quot; before=&quot;*&quot;/&gt;
+     *               &lt;interceptor service-id=&quot;somepackage.SecurityInterceptor&quot;/&gt;
      * </pre>
      * 
      * The <code>before</code> value for the first interceptor contribution will be assigned to
@@ -65,18 +65,27 @@
      * interceptor ... but that's an issue that applies when building the interceptor stack around
      * the core service implementation.
      */
-    public List getOrderedInterceptorContributions();
+    List getOrderedInterceptorContributions();
 
     /**
      * Invoked by the ServiceModel when constuction information (the builder and interceptors) is no
      * longer needed.
      */
-    public void clearConstructorInformation();
+    void clearConstructorInformation();
 
     /**
-     * Returns the {@link ShutdownCoordinator}, used by the service model to inform proxies that
-     * the service has shutdown.
+     * Adds a shutdown listener; HiveMind uses two coordinators; the first is the
+     * hivemind.ShutdownCoordinator service, which is the coordinator used for service
+     * implementations. The second coordinator is used by the HiveMind infrastructure directly; this
+     * method adds a listener to that coordinator. Why two? It's about order of operations during
+     * registry shutdown; the hivemind.ShutdownCoordinator service's listeners are all invoked
+     * first, the the internal coordinator, to shutdown proxies and the like. This allows services
+     * to communicate during shutdown.
+     * 
+     * @param listener
+     *            the listener to be added to the infrastructure's shutdown coordinator
+     * @since 1.1.1
      */
 
-    public ShutdownCoordinator getShutdownCoordinator();
+    void addRegistryShutdownListener(RegistryShutdownListener listener);
 }

Modified: jakarta/hivemind/branches/branch-1-1/framework/src/java/org/apache/hivemind/impl/InvokeFactoryServiceConstructor.java
URL: http://svn.apache.org/viewcvs/jakarta/hivemind/branches/branch-1-1/framework/src/java/org/apache/hivemind/impl/InvokeFactoryServiceConstructor.java?rev=357642&r1=357641&r2=357642&view=diff
==============================================================================
--- jakarta/hivemind/branches/branch-1-1/framework/src/java/org/apache/hivemind/impl/InvokeFactoryServiceConstructor.java (original)
+++ jakarta/hivemind/branches/branch-1-1/framework/src/java/org/apache/hivemind/impl/InvokeFactoryServiceConstructor.java Sun Dec 18 21:37:09 2005
@@ -50,10 +50,29 @@
     /** The parameters converted to objects as per the factory's parameter schema. */
     private List _convertedParameters;
 
-    // TODO: Should this method be synchronized?
-
     public Object constructCoreServiceImplementation()
     {
+        setupFactoryAndParameters();
+
+        try
+        {
+            ServiceImplementationFactoryParameters factoryParameters = new ServiceImplementationFactoryParametersImpl(
+                    _serviceExtensionPoint, _contributingModule, _convertedParameters);
+
+            return _factory.createCoreServiceImplementation(factoryParameters);
+        }
+        catch (Exception ex)
+        {
+            throw new ApplicationRuntimeException(ex.getMessage(), getLocation(), ex);
+        }
+    }
+
+    // A lot of changes to synchronization and service construction occured between 1.1 and 1.1.1;
+    // this method was split off and made synchronized ... otherwise, it was possible for the
+    // pooled or threaded services to get into a potential race condition through this code.
+
+    private synchronized void setupFactoryAndParameters()
+    {
         if (_factory == null)
         {
             ServicePoint factoryPoint = _contributingModule.getServicePoint(_factoryServiceId);
@@ -74,18 +93,6 @@
             _convertedParameters = processor.getElements();
 
             checkParameterCounts(errorLog, expected);
-        }
-
-        try
-        {
-            ServiceImplementationFactoryParameters factoryParameters = new ServiceImplementationFactoryParametersImpl(
-                    _serviceExtensionPoint, _contributingModule, _convertedParameters);
-
-            return _factory.createCoreServiceImplementation(factoryParameters);
-        }
-        catch (Exception ex)
-        {
-            throw new ApplicationRuntimeException(ex.getMessage(), getLocation(), ex);
         }
     }
 

Modified: jakarta/hivemind/branches/branch-1-1/framework/src/java/org/apache/hivemind/impl/ServicePointImpl.java
URL: http://svn.apache.org/viewcvs/jakarta/hivemind/branches/branch-1-1/framework/src/java/org/apache/hivemind/impl/ServicePointImpl.java?rev=357642&r1=357641&r2=357642&view=diff
==============================================================================
--- jakarta/hivemind/branches/branch-1-1/framework/src/java/org/apache/hivemind/impl/ServicePointImpl.java (original)
+++ jakarta/hivemind/branches/branch-1-1/framework/src/java/org/apache/hivemind/impl/ServicePointImpl.java Sun Dec 18 21:37:09 2005
@@ -24,6 +24,7 @@
 import org.apache.hivemind.HiveMind;
 import org.apache.hivemind.Occurances;
 import org.apache.hivemind.ShutdownCoordinator;
+import org.apache.hivemind.events.RegistryShutdownListener;
 import org.apache.hivemind.internal.ServiceImplementationConstructor;
 import org.apache.hivemind.internal.ServiceInterceptorContribution;
 import org.apache.hivemind.internal.ServiceModel;
@@ -289,14 +290,14 @@
         return orderer.getOrderedObjects();
     }
 
-    public ShutdownCoordinator getShutdownCoordinator()
+    public void setShutdownCoordinator(ShutdownCoordinator coordinator)
     {
-        return _shutdownCoordinator;
+        _shutdownCoordinator = coordinator;
     }
 
-    public void setShutdownCoordinator(ShutdownCoordinator coordinator)
+    public void addRegistryShutdownListener(RegistryShutdownListener listener)
     {
-        _shutdownCoordinator = coordinator;
+        _shutdownCoordinator.addRegistryShutdownListener(listener);
     }
 
     /**

Modified: jakarta/hivemind/branches/branch-1-1/framework/src/java/org/apache/hivemind/impl/servicemodel/AbstractServiceModelImpl.java
URL: http://svn.apache.org/viewcvs/jakarta/hivemind/branches/branch-1-1/framework/src/java/org/apache/hivemind/impl/servicemodel/AbstractServiceModelImpl.java?rev=357642&r1=357641&r2=357642&view=diff
==============================================================================
--- jakarta/hivemind/branches/branch-1-1/framework/src/java/org/apache/hivemind/impl/servicemodel/AbstractServiceModelImpl.java (original)
+++ jakarta/hivemind/branches/branch-1-1/framework/src/java/org/apache/hivemind/impl/servicemodel/AbstractServiceModelImpl.java Sun Dec 18 21:37:09 2005
@@ -21,6 +21,7 @@
 import org.apache.hivemind.ApplicationRuntimeException;
 import org.apache.hivemind.HiveMind;
 import org.apache.hivemind.ShutdownCoordinator;
+import org.apache.hivemind.events.RegistryShutdownListener;
 import org.apache.hivemind.impl.ConstructableServicePoint;
 import org.apache.hivemind.impl.InterceptorStackImpl;
 import org.apache.hivemind.impl.ProxyBuilder;
@@ -128,8 +129,8 @@
 
     /**
      * Constructs the service implementation; this is invoked from
-     * {@link org.apache.hivemind.internal.ServicePoint#getService(Class)} (for singletons),
-     * or from the generated deferrable proxy (for most service models). Primarily, invokes
+     * {@link org.apache.hivemind.internal.ServicePoint#getService(Class)} (for singletons), or from
+     * the generated deferrable proxy (for most service models). Primarily, invokes
      * {@link #constructNewServiceImplementation()} from within a block that checks for recursive
      * builds.
      */
@@ -179,13 +180,26 @@
      * 
      * @since 1.1
      */
-    protected synchronized Object constructBridgeProxy(Object service)
+    protected Object constructBridgeProxy(Object service)
+    {
+        Class bridgeProxyClass = getBridgeProxyClass(service);
+
+        return ConstructorUtils.invokeConstructor(bridgeProxyClass, new Object[]
+        { service });
+    }
+
+    /**
+     * Factored out of {@link #constructBridgeProxy(Object)} to keep the synchronized block as small
+     * as possible.
+     * 
+     * @since 1.2
+     */
+    private synchronized Class getBridgeProxyClass(Object service)
     {
         if (_bridgeProxyClass == null)
             _bridgeProxyClass = constructBridgeProxyClass(service);
 
-        return ConstructorUtils.invokeConstructor(_bridgeProxyClass, new Object[]
-        { service });
+        return _bridgeProxyClass;
     }
 
     /**
@@ -212,9 +226,25 @@
         return cf.createClass();
     }
 
-    protected ShutdownCoordinator getShutdownCoordinatorService()
+    /**
+     * Invoked after creating a service implementation object; if the object implements
+     * {@link org.apache.hivemind.events.RegistryShutdownListener}, then the object is added as a
+     * listener.
+     * 
+     * @param service
+     *            the service implementation
+     * @see ShutdownCoordinator
+     * @since 1.2
+     */
+    protected void registerWithShutdownCoordinator(Object service)
     {
-        return ( ( ShutdownCoordinator )getServicePoint().getModule().getService( ShutdownCoordinator.class ) );
-    }
+        if (service instanceof RegistryShutdownListener)
+        {
+            ShutdownCoordinator coordinator = ((ShutdownCoordinator) getServicePoint().getModule()
+                    .getService(ShutdownCoordinator.class));
 
+            RegistryShutdownListener asListener = (RegistryShutdownListener) service;
+            coordinator.addRegistryShutdownListener(asListener);
+        }
+    }
 }

Modified: jakarta/hivemind/branches/branch-1-1/framework/src/java/org/apache/hivemind/impl/servicemodel/PooledServiceModel.java
URL: http://svn.apache.org/viewcvs/jakarta/hivemind/branches/branch-1-1/framework/src/java/org/apache/hivemind/impl/servicemodel/PooledServiceModel.java?rev=357642&r1=357641&r2=357642&view=diff
==============================================================================
--- jakarta/hivemind/branches/branch-1-1/framework/src/java/org/apache/hivemind/impl/servicemodel/PooledServiceModel.java (original)
+++ jakarta/hivemind/branches/branch-1-1/framework/src/java/org/apache/hivemind/impl/servicemodel/PooledServiceModel.java Sun Dec 18 21:37:09 2005
@@ -20,7 +20,6 @@
 import org.apache.hivemind.ApplicationRuntimeException;
 import org.apache.hivemind.HiveMind;
 import org.apache.hivemind.PoolManageable;
-import org.apache.hivemind.ShutdownCoordinator;
 import org.apache.hivemind.events.RegistryShutdownListener;
 import org.apache.hivemind.impl.ConstructableServicePoint;
 import org.apache.hivemind.impl.ProxyUtils;
@@ -42,13 +41,13 @@
      */
     protected static final String SERVICE_ACCESSOR_METHOD_NAME = "_service";
 
-    private Object _serviceProxy;
+    private final Object _serviceProxy;
 
-    private ThreadEventNotifier _notifier;
+    private final ThreadEventNotifier _notifier;
 
-    private ThreadLocal _activeService;
+    private final ThreadLocal _activeService = new ThreadLocal();
 
-    private List _servicePool;
+    private final List _servicePool = new ArrayList();
 
     /** @since 1.1 */
 
@@ -121,22 +120,18 @@
         super(servicePoint);
 
         _serviceInterface = servicePoint.getServiceInterface();
-    }
 
-    public synchronized Object getService()
-    {
-        if (_notifier == null)
-        {
-            Module module = getServicePoint().getModule();
+        Module module = getServicePoint().getModule();
 
-            _notifier = (ThreadEventNotifier) module.getService(
-                    HiveMind.THREAD_EVENT_NOTIFIER_SERVICE,
-                    ThreadEventNotifier.class);
-        }
+        _notifier = (ThreadEventNotifier) module.getService(
+                HiveMind.THREAD_EVENT_NOTIFIER_SERVICE,
+                ThreadEventNotifier.class);
 
-        if (_serviceProxy == null)
-            _serviceProxy = constructServiceProxy();
+        _serviceProxy = constructServiceProxy();
+    }
 
+    public Object getService()
+    {
         return _serviceProxy;
     }
 
@@ -161,18 +156,13 @@
         RegistryShutdownListener outerProxy = ProxyUtils
                 .createOuterProxy(intercepted, servicePoint);
 
-        ShutdownCoordinator coordinator = servicePoint.getShutdownCoordinator();
-
-        coordinator.addRegistryShutdownListener(outerProxy);
+        servicePoint.addRegistryShutdownListener(outerProxy);
 
         return outerProxy;
     }
 
-    public synchronized Object getServiceImplementationForCurrentThread()
+    public Object getServiceImplementationForCurrentThread()
     {
-        if (_activeService == null)
-            _activeService = new ThreadLocal();
-
         PooledService pooled = (PooledService) _activeService.get();
 
         if (pooled == null)
@@ -200,7 +190,7 @@
 
     private synchronized PooledService getServiceFromPool()
     {
-        int count = _servicePool == null ? 0 : _servicePool.size();
+        int count = _servicePool.size();
 
         if (count == 0)
             return null;
@@ -210,13 +200,10 @@
 
     private synchronized void returnServiceToPool(PooledService pooled)
     {
-        if (_servicePool == null)
-            _servicePool = new ArrayList();
-
         _servicePool.add(pooled);
     }
 
-    private synchronized PooledService constructPooledService()
+    private PooledService constructPooledService()
     {
         try
         {
@@ -226,10 +213,9 @@
 
             if (!_serviceInterface.isInstance(core))
                 core = constructBridgeProxy(core);
-            if( core instanceof RegistryShutdownListener )
-            {
-                getShutdownCoordinatorService().addRegistryShutdownListener( ( RegistryShutdownListener )core );
-            }
+
+            registerWithShutdownCoordinator(core);
+
             return new PooledService(core);
         }
         catch (Exception ex)
@@ -242,8 +228,6 @@
 
     private void unbindPooledServiceFromCurrentThread(PooledService pooled)
     {
-        _notifier.removeThreadCleanupListener(pooled);
-
         _activeService.set(null);
 
         pooled.passivate();

Modified: jakarta/hivemind/branches/branch-1-1/framework/src/java/org/apache/hivemind/impl/servicemodel/PrimitiveServiceModel.java
URL: http://svn.apache.org/viewcvs/jakarta/hivemind/branches/branch-1-1/framework/src/java/org/apache/hivemind/impl/servicemodel/PrimitiveServiceModel.java?rev=357642&r1=357641&r2=357642&view=diff
==============================================================================
--- jakarta/hivemind/branches/branch-1-1/framework/src/java/org/apache/hivemind/impl/servicemodel/PrimitiveServiceModel.java (original)
+++ jakarta/hivemind/branches/branch-1-1/framework/src/java/org/apache/hivemind/impl/servicemodel/PrimitiveServiceModel.java Sun Dec 18 21:37:09 2005
@@ -14,7 +14,6 @@
 
 package org.apache.hivemind.impl.servicemodel;
 
-import org.apache.hivemind.events.RegistryShutdownListener;
 import org.apache.hivemind.impl.ConstructableServicePoint;
 
 /**
@@ -40,17 +39,15 @@
         if (_constructedService == null)
         {
             _constructedService = constructServiceImplementation();
-            if( _constructedService instanceof RegistryShutdownListener )
-            {
-                getShutdownCoordinatorService().addRegistryShutdownListener( ( RegistryShutdownListener )_constructedService );
-            }
+
+            registerWithShutdownCoordinator(_constructedService);
         }
 
         // Note: if the service's declared interface is a class AND
         // the service has interceptors, then it will not be possible
         // to cast the result (since the returned interceptor will implement
         // the synthetic service interface).
-        
+
         return _constructedService;
     }
 

Modified: jakarta/hivemind/branches/branch-1-1/framework/src/java/org/apache/hivemind/impl/servicemodel/SingletonServiceModel.java
URL: http://svn.apache.org/viewcvs/jakarta/hivemind/branches/branch-1-1/framework/src/java/org/apache/hivemind/impl/servicemodel/SingletonServiceModel.java?rev=357642&r1=357641&r2=357642&view=diff
==============================================================================
--- jakarta/hivemind/branches/branch-1-1/framework/src/java/org/apache/hivemind/impl/servicemodel/SingletonServiceModel.java (original)
+++ jakarta/hivemind/branches/branch-1-1/framework/src/java/org/apache/hivemind/impl/servicemodel/SingletonServiceModel.java Sun Dec 18 21:37:09 2005
@@ -27,9 +27,9 @@
 import org.apache.hivemind.service.MethodSignature;
 
 /**
- * Subclass of {@link org.apache.hivemind.impl.servicemodel.AbstractServiceModelImpl} which
- * supports creation of a singleton service proxy (deferring the actual construction of the service
- * until absolutely necessary). This is used with the singleton service type, which is the default.
+ * Subclass of {@link org.apache.hivemind.impl.servicemodel.AbstractServiceModelImpl} which supports
+ * creation of a singleton service proxy (deferring the actual construction of the service until
+ * absolutely necessary). This is used with the singleton service type, which is the default.
  * 
  * @author Howard Lewis Ship
  */
@@ -65,12 +65,11 @@
     public synchronized Object getActualServiceImplementation()
     {
         if (_constructedService == null)
-            _constructedService = constructServiceImplementation();
-
-        if( _constructedService instanceof RegistryShutdownListener )
         {
-            getShutdownCoordinatorService().addRegistryShutdownListener( ( RegistryShutdownListener )_constructedService );
+            _constructedService = constructServiceImplementation();
+            registerWithShutdownCoordinator(_constructedService);
         }
+
         // The inner proxy needs the service to implement the service interface.
         // For bean services (not interface services) with no interceptors,
         // the implementation may be the bean provided by the factory ... which
@@ -78,7 +77,7 @@
         // So we introduce a "bridge" between the two.
 
         Class serviceInterface = getServicePoint().getServiceInterface();
-    
+
         if (!serviceInterface.isInstance(_constructedService))
             _constructedService = constructBridgeProxy(_constructedService);
 
@@ -120,8 +119,9 @@
             _innerProxy = (SingletonInnerProxy) c.newInstance(new Object[]
             { result, this });
 
-            getServicePoint().getShutdownCoordinator().addRegistryShutdownListener(
-                    (RegistryShutdownListener) result);
+            RegistryShutdownListener asListener = (RegistryShutdownListener) result;
+
+            getServicePoint().addRegistryShutdownListener(asListener);
 
             return result;
         }
@@ -153,12 +153,12 @@
 
         classFab.addField("_inner", serviceInterface);
         classFab.addField("_shutdown", boolean.class);
-        if( !RegistryShutdownListener.class.isAssignableFrom( serviceInterface ) )
+        if (!RegistryShutdownListener.class.isAssignableFrom(serviceInterface))
         {
             classFab.addInterface(RegistryShutdownListener.class);
 
             classFab.addMethod(Modifier.PUBLIC | Modifier.FINAL, new MethodSignature(void.class,
-                "registryDidShutdown", null, null), "{ _shutdown = true; }");
+                    "registryDidShutdown", null, null), "{ _shutdown = true; }");
         }
         classFab.addMethod(
                 Modifier.PUBLIC | Modifier.SYNCHRONIZED | Modifier.FINAL,

Modified: jakarta/hivemind/branches/branch-1-1/framework/src/java/org/apache/hivemind/impl/servicemodel/ThreadedServiceModel.java
URL: http://svn.apache.org/viewcvs/jakarta/hivemind/branches/branch-1-1/framework/src/java/org/apache/hivemind/impl/servicemodel/ThreadedServiceModel.java?rev=357642&r1=357641&r2=357642&view=diff
==============================================================================
--- jakarta/hivemind/branches/branch-1-1/framework/src/java/org/apache/hivemind/impl/servicemodel/ThreadedServiceModel.java (original)
+++ jakarta/hivemind/branches/branch-1-1/framework/src/java/org/apache/hivemind/impl/servicemodel/ThreadedServiceModel.java Sun Dec 18 21:37:09 2005
@@ -17,7 +17,6 @@
 import org.apache.hivemind.ApplicationRuntimeException;
 import org.apache.hivemind.Discardable;
 import org.apache.hivemind.HiveMind;
-import org.apache.hivemind.ShutdownCoordinator;
 import org.apache.hivemind.events.RegistryShutdownListener;
 import org.apache.hivemind.impl.ConstructableServicePoint;
 import org.apache.hivemind.impl.ProxyUtils;
@@ -26,10 +25,10 @@
 import org.apache.hivemind.service.ThreadEventNotifier;
 
 /**
- * Like {@link org.apache.hivemind.impl.servicemodel.SingletonServiceModel}, this method returns a proxy
- * (implementing the service interface); unlike SingletonServiceModel, it <em>always</em> returns
- * the proxy. Invoking a service method on the proxy constructs a service implementation and binds
- * it to the current thread.
+ * Like {@link org.apache.hivemind.impl.servicemodel.SingletonServiceModel}, this method returns a
+ * proxy (implementing the service interface); unlike SingletonServiceModel, it <em>always</em>
+ * returns the proxy. Invoking a service method on the proxy constructs a service implementation and
+ * binds it to the current thread.
  * 
  * @author Howard Lewis Ship
  */
@@ -40,25 +39,38 @@
      */
     protected static final String SERVICE_ACCESSOR_METHOD_NAME = "_service";
 
-    private Object _serviceProxy;
+    private final Object _serviceProxy;
+
+    private final ThreadEventNotifier _notifier;
+
+    /**
+     * Used to store the active service for the current thread.
+     */
+    private final ThreadLocal _activeService = new ThreadLocal();
 
-    private ThreadEventNotifier _notifier;
-    
     /** @since 1.1 */
-    
+
     private Class _serviceInterface;
 
     public ThreadedServiceModel(ConstructableServicePoint servicePoint)
     {
         super(servicePoint);
-        
+
         _serviceInterface = servicePoint.getServiceInterface();
+
+        Module module = getServicePoint().getModule();
+
+        _notifier = (ThreadEventNotifier) module.getService(
+                HiveMind.THREAD_EVENT_NOTIFIER_SERVICE,
+                ThreadEventNotifier.class);
+
+        _serviceProxy = createServiceProxy();
     }
 
     class CleanupListener implements ThreadCleanupListener
     {
         // The core itself
-        private Object _core;
+        private final Object _core;
 
         CleanupListener(Object core)
         {
@@ -67,9 +79,6 @@
 
         public void threadDidCleanup()
         {
-            // Orhpan this object
-            _notifier.removeThreadCleanupListener(this);
-
             unbindServiceFromCurrentThread();
 
             if (_core instanceof Discardable)
@@ -82,30 +91,12 @@
     }
 
     /**
-     * Used to store the active service for the current thread.
-     */
-    private ThreadLocal _activeService;
-
-    /**
      * Always returns the service proxy.
      */
-    public synchronized Object getService()
+    public Object getService()
     {
-        // _activeService will be null on first invocation; a good
-        // time to create it, the proxy, and find the notifier.
-
-        if (_activeService == null)
-        {
-            _activeService = new ThreadLocal();
-
-            Module module = getServicePoint().getModule();
-
-            _notifier = (ThreadEventNotifier) module.getService(
-                    HiveMind.THREAD_EVENT_NOTIFIER_SERVICE,
-                    ThreadEventNotifier.class);
-
-            _serviceProxy = createServiceProxy();
-        }
+        // In 1.1 and earlier, we would lazily create the _serviceProxy here; but that meant the
+        // method had to be synchronized, which created a choke point.
 
         // The result is an interceptor stack, where the final (most deeply nested) object
         // is the serviceProxy. The serviceProxy obtains the instance for the current thread
@@ -138,9 +129,7 @@
         RegistryShutdownListener outerProxy = ProxyUtils
                 .createOuterProxy(intercepted, servicePoint);
 
-        ShutdownCoordinator coordinator = servicePoint.getShutdownCoordinator();
-
-        coordinator.addRegistryShutdownListener(outerProxy);
+        servicePoint.addRegistryShutdownListener(outerProxy);
 
         return outerProxy;
     }
@@ -154,12 +143,12 @@
         Object result = _activeService.get();
 
         if (result == null)
-            result = constructServiceForCurrentThread();
+            result = constructInstanceForCurrentThread();
 
         return result;
     }
 
-    private synchronized Object constructServiceForCurrentThread()
+    private Object constructInstanceForCurrentThread()
     {
         try
         {
@@ -176,7 +165,7 @@
 
             if (!_serviceInterface.isInstance(core))
                 core = constructBridgeProxy(core);
-            
+
             _activeService.set(core);
 
             return core;

Modified: jakarta/hivemind/branches/branch-1-1/framework/src/java/org/apache/hivemind/internal/ser/ServiceSerializationHelper.java
URL: http://svn.apache.org/viewcvs/jakarta/hivemind/branches/branch-1-1/framework/src/java/org/apache/hivemind/internal/ser/ServiceSerializationHelper.java?rev=357642&r1=357641&r2=357642&view=diff
==============================================================================
--- jakarta/hivemind/branches/branch-1-1/framework/src/java/org/apache/hivemind/internal/ser/ServiceSerializationHelper.java (original)
+++ jakarta/hivemind/branches/branch-1-1/framework/src/java/org/apache/hivemind/internal/ser/ServiceSerializationHelper.java Sun Dec 18 21:37:09 2005
@@ -16,8 +16,6 @@
 
 import java.lang.ref.WeakReference;
 
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
 import org.apache.hivemind.ApplicationRuntimeException;
 
 /**
@@ -30,8 +28,6 @@
  */
 public class ServiceSerializationHelper
 {
-    private static final Log LOG = LogFactory.getLog(ServiceSerializationHelper.class);
-
     private static final ThreadLocal _threadLocal = new ThreadLocal();
 
     /**

Modified: jakarta/hivemind/branches/branch-1-1/framework/src/java/org/apache/hivemind/service/ThreadEventNotifier.java
URL: http://svn.apache.org/viewcvs/jakarta/hivemind/branches/branch-1-1/framework/src/java/org/apache/hivemind/service/ThreadEventNotifier.java?rev=357642&r1=357641&r2=357642&view=diff
==============================================================================
--- jakarta/hivemind/branches/branch-1-1/framework/src/java/org/apache/hivemind/service/ThreadEventNotifier.java (original)
+++ jakarta/hivemind/branches/branch-1-1/framework/src/java/org/apache/hivemind/service/ThreadEventNotifier.java Sun Dec 18 21:37:09 2005
@@ -15,27 +15,34 @@
 package org.apache.hivemind.service;
 
 /**
- * Service which acts as a dispatch hub for events about the lifecycle of
- * the current thread.
- *
+ * Service which acts as a dispatch hub for events about the lifecycle of the current thread.
+ * <p>
+ * Note: prior to release 1.1.1, the ThreadEventNotifier implementation would retain the listeners
+ * after {@link #fireThreadCleanup()}, which could allow certain threads to retain a reference to a
+ * listener, and thus that listener's class loader, even after the an application redeployment,
+ * resulting in a massive memory leak. Starting with release 1.1.1, all listeners are discarded by
+ * {@link #fireThreadCleanup()}.
+ * 
  * @author Howard Lewis Ship
  */
 public interface ThreadEventNotifier
 {
     /**
-     * Adds the listener.
+     * Adds the listener. The notifier retains the listener until {@link #fireThreadCleanup()} is
+     * invoked, at which point is discarded.
      */
     public void addThreadCleanupListener(ThreadCleanupListener listener);
 
     /**
-     * Removes the listener, if it has been previously added.  If the listener
-     * has been added multiple times, only one instance is removed.
+     * Removes the listener, if it has been previously added. If the listener has been added
+     * multiple times, only one instance is removed. Note that this method is rarely used, because
+     * all listeners are automatically removed by {@link #fireThreadCleanup()}.
      */
     public void removeThreadCleanupListener(ThreadCleanupListener listener);
 
     /**
-     * Invokes {@link ThreadCleanupListener#threadDidCleanup()} on all
-     * listeners.
+     * Invokes {@link ThreadCleanupListener#threadDidCleanup()} on all listeners, and discards the
+     * list of listeners.
      */
     public void fireThreadCleanup();
 }

Modified: jakarta/hivemind/branches/branch-1-1/framework/src/java/org/apache/hivemind/service/impl/ServiceMessages.java
URL: http://svn.apache.org/viewcvs/jakarta/hivemind/branches/branch-1-1/framework/src/java/org/apache/hivemind/service/impl/ServiceMessages.java?rev=357642&r1=357641&r2=357642&view=diff
==============================================================================
--- jakarta/hivemind/branches/branch-1-1/framework/src/java/org/apache/hivemind/service/impl/ServiceMessages.java (original)
+++ jakarta/hivemind/branches/branch-1-1/framework/src/java/org/apache/hivemind/service/impl/ServiceMessages.java Sun Dec 18 21:37:09 2005
@@ -163,4 +163,11 @@
     {
         return _formatter.format("unable-to-create-interface", name, cause);
     }
+
+    /** @since 1.1.1 */
+
+    static String threadCleanupException(Throwable cause)
+    {
+        return _formatter.format("thread-cleanup-exception", cause);
+    }
 }

Modified: jakarta/hivemind/branches/branch-1-1/framework/src/java/org/apache/hivemind/service/impl/ServiceStrings.properties
URL: http://svn.apache.org/viewcvs/jakarta/hivemind/branches/branch-1-1/framework/src/java/org/apache/hivemind/service/impl/ServiceStrings.properties?rev=357642&r1=357641&r2=357642&view=diff
==============================================================================
--- jakarta/hivemind/branches/branch-1-1/framework/src/java/org/apache/hivemind/service/impl/ServiceStrings.properties (original)
+++ jakarta/hivemind/branches/branch-1-1/framework/src/java/org/apache/hivemind/service/impl/ServiceStrings.properties Sun Dec 18 21:37:09 2005
@@ -35,4 +35,5 @@
 invalid-service-property-locator=''{0}'' is not a valid locator for use with the service-property object provider. It should be the id of a service, a comma, and the name of a property provided by that service.
 failure-building-service=Error building service {0}: {1}
 autowire-property-failure=Unable to autowire property {0} of service {1}: {2}
-unable-to-find-autowire-constructor=Unable to find constructor applicable for autowiring. Use explicit constructor parameters.
\ No newline at end of file
+unable-to-find-autowire-constructor=Unable to find constructor applicable for autowiring. Use explicit constructor parameters.
+thread-cleanup-exception=Thread cleanup exception: {0}
\ No newline at end of file

Modified: jakarta/hivemind/branches/branch-1-1/framework/src/java/org/apache/hivemind/service/impl/ThreadEventNotifierImpl.java
URL: http://svn.apache.org/viewcvs/jakarta/hivemind/branches/branch-1-1/framework/src/java/org/apache/hivemind/service/impl/ThreadEventNotifierImpl.java?rev=357642&r1=357641&r2=357642&view=diff
==============================================================================
--- jakarta/hivemind/branches/branch-1-1/framework/src/java/org/apache/hivemind/service/impl/ThreadEventNotifierImpl.java (original)
+++ jakarta/hivemind/branches/branch-1-1/framework/src/java/org/apache/hivemind/service/impl/ThreadEventNotifierImpl.java Sun Dec 18 21:37:09 2005
@@ -16,19 +16,38 @@
 
 import java.util.Iterator;
 
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
 import org.apache.hivemind.service.ThreadCleanupListener;
 import org.apache.hivemind.service.ThreadEventNotifier;
+import org.apache.hivemind.util.Defense;
 import org.apache.hivemind.util.EventListenerList;
 
 /**
- * Implementation of {@link org.apache.hivemind.service.ThreadEventNotifier},
- * available as service <code>hivemind.ThreadEventNotifier</code>.
- *
+ * Implementation of {@link org.apache.hivemind.service.ThreadEventNotifier}, available as service
+ * <code>hivemind.ThreadEventNotifier</code>.
+ * 
  * @author Howard Lewis Ship
  */
 public class ThreadEventNotifierImpl implements ThreadEventNotifier
 {
-    private ThreadLocal _storage = new ThreadLocal();
+    private static final Log DEFAULT_LOG = LogFactory.getLog(ThreadEventNotifier.class);
+
+    private final Log _log;
+
+    private final ThreadLocal _storage = new ThreadLocal();
+
+    public ThreadEventNotifierImpl()
+    {
+        this(DEFAULT_LOG);
+    }
+
+    public ThreadEventNotifierImpl(Log log)
+    {
+        Defense.notNull(log, "log");
+
+        _log = log;
+    }
 
     public void addThreadCleanupListener(ThreadCleanupListener listener)
     {
@@ -45,7 +64,7 @@
 
     public void removeThreadCleanupListener(ThreadCleanupListener listener)
     {
-		EventListenerList list = (EventListenerList) _storage.get();
+        EventListenerList list = (EventListenerList) _storage.get();
 
         if (list != null)
             list.removeListener(listener);
@@ -57,24 +76,35 @@
         // are free to unregister as listeners from threadDidCleanup() and
         // we need to avoid concurrent modification errors.
 
-		EventListenerList list = (EventListenerList) _storage.get();
+        EventListenerList list = (EventListenerList) _storage.get();
 
         if (list == null)
             return;
 
         Iterator i = list.getListeners();
 
+        // Discard the list of listeners as early as possible to ensure that
+        // they can in no way be retained, even if this thread aborts abnormally.
+
+        _storage.set(null);
+
         while (i.hasNext())
         {
             ThreadCleanupListener listener = (ThreadCleanupListener) i.next();
 
-			// Each listener may decide to remove itself; that's OK,
-			// EventListenerList handles that kind of concurrent modification
-			// well.
-			
-            listener.threadDidCleanup();
+            // Each listener may decide to remove itself; that's OK,
+            // EventListenerList handles that kind of concurrent modification
+            // well.
+
+            try
+            {
+                listener.threadDidCleanup();
+            }
+            catch (RuntimeException ex)
+            {
+                _log.warn(ServiceMessages.threadCleanupException(ex), ex);
+            }
         }
-
     }
 
 }

Modified: jakarta/hivemind/branches/branch-1-1/framework/src/java/org/apache/hivemind/service/impl/ThreadLocalStorageImpl.java
URL: http://svn.apache.org/viewcvs/jakarta/hivemind/branches/branch-1-1/framework/src/java/org/apache/hivemind/service/impl/ThreadLocalStorageImpl.java?rev=357642&r1=357641&r2=357642&view=diff
==============================================================================
--- jakarta/hivemind/branches/branch-1-1/framework/src/java/org/apache/hivemind/service/impl/ThreadLocalStorageImpl.java (original)
+++ jakarta/hivemind/branches/branch-1-1/framework/src/java/org/apache/hivemind/service/impl/ThreadLocalStorageImpl.java Sun Dec 18 21:37:09 2005
@@ -17,103 +17,34 @@
 import java.util.HashMap;
 import java.util.Map;
 
-import org.apache.hivemind.service.ThreadCleanupListener;
-import org.apache.hivemind.service.ThreadEventNotifier;
 import org.apache.hivemind.service.ThreadLocalStorage;
 
 /**
  * Implementation of {@link org.apache.hivemind.service.ThreadLocalStorage}.
+ * <p>
+ * Starting with release 1.2, this implementation was simplified, and its service model changed to
+ * threaded.
  * 
  * @author Howard Lewis Ship, Harish Krishnaswamy
  */
-public class ThreadLocalStorageImpl implements ThreadLocalStorage, ThreadCleanupListener
+public class ThreadLocalStorageImpl implements ThreadLocalStorage
 {
-    private static final String INITIALIZED_KEY =
-        "$org.apache.hivemind.service.impl.ThreadLocalStorageImpl#initialized$";
+    // Created anew for each instance of TLS in each thread.
 
-    private CleanableThreadLocal _local = new CleanableThreadLocal();
-    private ThreadEventNotifier _notifier;
-
-    private static class CleanableThreadLocal extends ThreadLocal
-    {
-        /**
-         * <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()).
-
-            Map map = new HashMap();
-            map.put(INITIALIZED_KEY, Boolean.TRUE);
-
-            return map;
-        }
-    }
-
-    /**
-     * 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 (Boolean.TRUE.equals(map.get(INITIALIZED_KEY)) && _notifier != null)
-        {
-            _notifier.addThreadCleanupListener(this);
-
-            map.remove(INITIALIZED_KEY);
-        }
-
-        return map;
-    }
+    private final Map _map = new HashMap();
 
     public Object get(String key)
     {
-        Map map = getThreadLocalVariable();
-
-        return map.get(key);
+        return _map.get(key);
     }
 
     public void put(String key, Object value)
     {
-        Map map = getThreadLocalVariable();
-
-        map.put(key, value);
+        _map.put(key, value);
     }
 
     public void clear()
     {
-        Map map = (Map) _local.get();
-
-        if (map != null)
-            map.clear();
-    }
-
-    public void setNotifier(ThreadEventNotifier notifier)
-    {
-        _notifier = notifier;
+        _map.clear();
     }
-
-    /**
-     * Invokes {@link #clear()}.
-     */
-    public void threadDidCleanup()
-    {
-        clear();
-    }
-
 }

Modified: jakarta/hivemind/branches/branch-1-1/framework/src/java/org/apache/hivemind/util/IdUtils.java
URL: http://svn.apache.org/viewcvs/jakarta/hivemind/branches/branch-1-1/framework/src/java/org/apache/hivemind/util/IdUtils.java?rev=357642&r1=357641&r2=357642&view=diff
==============================================================================
--- jakarta/hivemind/branches/branch-1-1/framework/src/java/org/apache/hivemind/util/IdUtils.java (original)
+++ jakarta/hivemind/branches/branch-1-1/framework/src/java/org/apache/hivemind/util/IdUtils.java Sun Dec 18 21:37:09 2005
@@ -18,16 +18,15 @@
 
 /**
  * A collection of utilities for handling qualified and unqualified ids.
- *
+ * 
  * @author Howard Lewis Ship
  */
 public class IdUtils
 {
 
     /**
-     * Returns a fully qualfied id.  If the id contains a '.', then it
-     * is returned unchanged.  Otherwise, the module's id is prefixed (with a 
-     * seperator '.') and returned;
+     * Returns a fully qualfied id. If the id contains a '.', then it is returned unchanged.
+     * Otherwise, the module's id is prefixed (with a seperator '.') and returned;
      */
     public static String qualify(String moduleId, String id)
     {
@@ -38,8 +37,8 @@
     }
 
     /**
-     * Qualifies a list of interceptor service ids provided for an interceptor
-     * contribution.  The special value "*" is not qualified.
+     * Qualifies a list of interceptor service ids provided for an interceptor contribution. The
+     * special value "*" is not qualified.
      */
     public static String qualifyList(String sourceModuleId, String list)
     {
@@ -53,7 +52,7 @@
 
         return StringUtils.join(items, ',');
     }
-    
+
     /**
      * Removes the module name from a fully qualified id
      */
@@ -62,19 +61,20 @@
         int lastPoint = id.lastIndexOf('.');
         if (lastPoint > 0)
             return id.substring(lastPoint + 1, id.length());
-        else return id;
+
+        return id;
     }
 
     /**
-     * Extracts the module name from a fully qualified id
-     * Returns null if id contains no module
+     * Extracts the module name from a fully qualified id Returns null if id contains no module
      */
     public static String extractModule(String id)
     {
         int lastPoint = id.lastIndexOf('.');
         if (lastPoint > 0)
             return id.substring(0, lastPoint);
-        else return null;
+
+        return null;
     }
 
 }

Modified: jakarta/hivemind/branches/branch-1-1/framework/src/test/hivemind/test/services/TestThreadEventNotifier.java
URL: http://svn.apache.org/viewcvs/jakarta/hivemind/branches/branch-1-1/framework/src/test/hivemind/test/services/TestThreadEventNotifier.java?rev=357642&r1=357641&r2=357642&view=diff
==============================================================================
--- jakarta/hivemind/branches/branch-1-1/framework/src/test/hivemind/test/services/TestThreadEventNotifier.java (original)
+++ jakarta/hivemind/branches/branch-1-1/framework/src/test/hivemind/test/services/TestThreadEventNotifier.java Sun Dec 18 21:37:09 2005
@@ -14,6 +14,7 @@
 
 package hivemind.test.services;
 
+import org.apache.commons.logging.Log;
 import org.apache.hivemind.service.ThreadCleanupListener;
 import org.apache.hivemind.service.ThreadEventNotifier;
 import org.apache.hivemind.service.impl.ThreadEventNotifierImpl;
@@ -22,7 +23,7 @@
 
 /**
  * Tests for {@link org.apache.hivemind.service.impl.ThreadEventNotifierImpl}.
- *
+ * 
  * @author Howard Lewis Ship
  */
 public class TestThreadEventNotifier extends FrameworkTestCase
@@ -38,24 +39,6 @@
 
     }
 
-    static class ConcurMod implements ThreadCleanupListener
-    {
-        boolean _cleanup;
-        ThreadEventNotifier _notifier;
-
-        ConcurMod(ThreadEventNotifier notifier)
-        {
-            _notifier = notifier;
-        }
-
-        public void threadDidCleanup()
-        {
-            _cleanup = true;
-            _notifier.removeThreadCleanupListener(this);
-        }
-
-    }
-
     public void testAdd()
     {
         ThreadEventNotifier n = new ThreadEventNotifierImpl();
@@ -84,33 +67,51 @@
         assertEquals(true, l2._cleanup);
     }
 
-    public void testConcur()
+    public void testNotifierClearsListenerListAfterFire()
     {
         ThreadEventNotifier n = new ThreadEventNotifierImpl();
 
-        Listener l1 = new Listener();
-        ConcurMod l2 = new ConcurMod(n);
-        Listener l3 = new Listener();
+        Listener l = new Listener();
 
-        n.addThreadCleanupListener(l1);
-        n.addThreadCleanupListener(l2);
-        n.addThreadCleanupListener(l3);
+        n.addThreadCleanupListener(l);
 
         n.fireThreadCleanup();
 
-        assertEquals(true, l1._cleanup);
-        assertEquals(true, l2._cleanup);
-        assertEquals(true, l3._cleanup);
+        assertEquals(true, l._cleanup);
 
-        l1._cleanup = false;
-        l2._cleanup = false;
-        l3._cleanup = false;
+        l._cleanup = false;
 
         n.fireThreadCleanup();
 
-        assertEquals(true, l1._cleanup);
-        assertEquals(false, l2._cleanup);
-        assertEquals(true, l3._cleanup);
+        // Don't expect a notification, because the notifier's list is gone
+
+        assertEquals(false, l._cleanup);
     }
 
+    public void testListenerThrowsException()
+    {
+        Log log = (Log) newMock(Log.class);
+
+        final RuntimeException re = new RuntimeException("Listener Failure");
+
+        log.warn("Thread cleanup exception: Listener Failure", re);
+
+        replayControls();
+
+        ThreadCleanupListener l = new ThreadCleanupListener()
+        {
+            public void threadDidCleanup()
+            {
+                throw re;
+            }
+        };
+
+        ThreadEventNotifier n = new ThreadEventNotifierImpl(log);
+
+        n.addThreadCleanupListener(l);
+
+        n.fireThreadCleanup();
+
+        verifyControls();
+    }
 }

Modified: jakarta/hivemind/branches/branch-1-1/framework/src/test/hivemind/test/services/TestThreadLocalStorage.java
URL: http://svn.apache.org/viewcvs/jakarta/hivemind/branches/branch-1-1/framework/src/test/hivemind/test/services/TestThreadLocalStorage.java?rev=357642&r1=357641&r2=357642&view=diff
==============================================================================
--- jakarta/hivemind/branches/branch-1-1/framework/src/test/hivemind/test/services/TestThreadLocalStorage.java (original)
+++ jakarta/hivemind/branches/branch-1-1/framework/src/test/hivemind/test/services/TestThreadLocalStorage.java Sun Dec 18 21:37:09 2005
@@ -16,9 +16,7 @@
 
 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;
 
 /**
@@ -29,8 +27,6 @@
 public class TestThreadLocalStorage extends FrameworkTestCase
 {
     private ThreadLocalStorage _s = new ThreadLocalStorageImpl();
-    private Throwable          _testRunnerFailure;
-    private boolean            _testRunnerCompleted;
 
     public void testGetEmpty()
     {
@@ -60,86 +56,5 @@
         _s.clear();
 
         assertNull(_s.get("foo"));
-    }
-
-    public void testWithNotifier()
-    {
-        ThreadEventNotifier notifier = new ThreadEventNotifierImpl();
-        ThreadLocalStorageImpl s = new ThreadLocalStorageImpl();
-
-        s.setNotifier(notifier);
-
-        s.put("biff", "bamf");
-
-        assertEquals("bamf", s.get("biff"));
-
-        notifier.fireThreadCleanup();
-
-        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"));
     }
 }

Modified: jakarta/hivemind/branches/branch-1-1/framework/src/test/org/apache/hivemind/impl/TestServiceModelThreading.java
URL: http://svn.apache.org/viewcvs/jakarta/hivemind/branches/branch-1-1/framework/src/test/org/apache/hivemind/impl/TestServiceModelThreading.java?rev=357642&r1=357641&r2=357642&view=diff
==============================================================================
--- jakarta/hivemind/branches/branch-1-1/framework/src/test/org/apache/hivemind/impl/TestServiceModelThreading.java (original)
+++ jakarta/hivemind/branches/branch-1-1/framework/src/test/org/apache/hivemind/impl/TestServiceModelThreading.java Sun Dec 18 21:37:09 2005
@@ -18,16 +18,18 @@
 import org.apache.hivemind.test.HiveMindTestCase;
 
 /**
- * Tests to verify that the service models work properly even under high-thread count
- * concurrent stress.
- *
+ * Tests to verify that the service models work properly even under high-thread count concurrent
+ * stress.
+ * 
  * @author Howard Lewis Ship
  */
 public class TestServiceModelThreading extends HiveMindTestCase
 {
-    public static final int THREAD_COUNT = 20;
-    public static final int ITERATIONS = 10;
-    public static final long JOIN_WAIT = 500;
+    public static final int THREAD_COUNT = 150;
+
+    public static final int ITERATIONS = 20;
+
+    public static final long JOIN_WAIT = 1000;
 
     private static class RunnableFixture implements Runnable
     {
@@ -47,8 +49,11 @@
     private static class RunnableManager implements Runnable
     {
         private Registry _registry;
+
         private Worker _worker;
+
         private Runnable _runnable;
+
         private boolean _completed = false;
 
         private RunnableManager(Registry registry, Worker worker, Runnable runnable)
@@ -113,28 +118,28 @@
         }
 
         assertEquals(
-            "Number of executions of the RunnableFixture",
-            THREAD_COUNT * ITERATIONS,
-            fixture.getInvokeCount());
+                "Number of executions of the RunnableFixture",
+                THREAD_COUNT * ITERATIONS,
+                fixture.getInvokeCount());
     }
 
     public void testPrimitive() throws Exception
     {
         execute("hivemind.test.threading.PrimitiveWorker");
     }
-    
+
     public void testSingleton() throws Exception
     {
-    	execute("hivemind.test.threading.SingletonWorker");
+        execute("hivemind.test.threading.SingletonWorker");
     }
-    
+
     public void testThreaded() throws Exception
     {
-    	execute("hivemind.test.threading.ThreadedWorker");
+        execute("hivemind.test.threading.ThreadedWorker");
     }
-    
+
     public void testPooled() throws Exception
     {
-    	execute("hivemind.test.threading.PooledWorker");
+        execute("hivemind.test.threading.PooledWorker");
     }
 }

Modified: jakarta/hivemind/branches/branch-1-1/jmx/src/java/org/apache/hivemind/management/impl/PerformanceMonitorFactory.java
URL: http://svn.apache.org/viewcvs/jakarta/hivemind/branches/branch-1-1/jmx/src/java/org/apache/hivemind/management/impl/PerformanceMonitorFactory.java?rev=357642&r1=357641&r2=357642&view=diff
==============================================================================
--- jakarta/hivemind/branches/branch-1-1/jmx/src/java/org/apache/hivemind/management/impl/PerformanceMonitorFactory.java (original)
+++ jakarta/hivemind/branches/branch-1-1/jmx/src/java/org/apache/hivemind/management/impl/PerformanceMonitorFactory.java Sun Dec 18 21:37:09 2005
@@ -106,8 +106,8 @@
                     _counter.addMeasurement(signature, endTime - startTime);
                     return result;
                 }
-                else
-                    return method.invoke(_inner, args);
+
+                return method.invoke(_inner, args);
             }
             catch (InvocationTargetException ex)
             {

Modified: jakarta/hivemind/branches/branch-1-1/jmx/src/java/org/apache/hivemind/management/log4j/LoggerMBean.java
URL: http://svn.apache.org/viewcvs/jakarta/hivemind/branches/branch-1-1/jmx/src/java/org/apache/hivemind/management/log4j/LoggerMBean.java?rev=357642&r1=357641&r2=357642&view=diff
==============================================================================
--- jakarta/hivemind/branches/branch-1-1/jmx/src/java/org/apache/hivemind/management/log4j/LoggerMBean.java (original)
+++ jakarta/hivemind/branches/branch-1-1/jmx/src/java/org/apache/hivemind/management/log4j/LoggerMBean.java Sun Dec 18 21:37:09 2005
@@ -42,14 +42,10 @@
 import org.apache.log4j.jmx.AppenderDynamicMBean;
 
 /**
- * MBean for the management of a Log4j logger.
- * Allows to change the level and add appenders.
- * 
- * This is a copy of the {@link org.apache.log4j.jmx.LoggerDynamicMBean} from the
- * log4 library. The copy was made to fix an issue with jboss 3.2.7, that don't 
- * accept spaces in attribute names. 
- * If somebody feels that such a copy from one apache project to another is not
- * ok, please tell me.
+ * MBean for the management of a Log4j logger. Allows to change the level and add appenders. This is
+ * a copy of the {@link org.apache.log4j.jmx.LoggerDynamicMBean} from the log4 library. The copy was
+ * made to fix an issue with jboss 3.2.7, that don't accept spaces in attribute names. If somebody
+ * feels that such a copy from one apache project to another is not ok, please tell me.
  * 
  * @author Achim Huegen
  */
@@ -153,13 +149,9 @@
         {
             Level l = _logger.getLevel();
             if (l == null)
-            {
                 return null;
-            }
-            else
-            {
-                return l.toString();
-            }
+
+            return l.toString();
         }
         else if (attributeName.startsWith("appender="))
         {
@@ -248,6 +240,7 @@
 
     /**
      * Register a mbean for an appender.
+     * 
      * @param appender
      */
     void registerAppenderMBean(Appender appender)
@@ -259,13 +252,14 @@
         {
             objectName = new ObjectName("log4j", "appender", name);
             // register appender as mbean if not already existing
-            if (!getMBeanServer().isRegistered(objectName)) {
+            if (!getMBeanServer().isRegistered(objectName))
+            {
                 AppenderDynamicMBean appenderMBean = new AppenderDynamicMBean(appender);
                 getMBeanServer().registerMBean(appenderMBean, objectName);
-    
-                _attributes
-                        .add(new MBeanAttributeInfo("appender=" + name, "javax.management.ObjectName",
-                                "The " + name + " appender.", true, true, false));
+
+                _attributes.add(new MBeanAttributeInfo("appender=" + name,
+                        "javax.management.ObjectName", "The " + name + " appender.", true, true,
+                        false));
             }
 
         }

Modified: jakarta/hivemind/branches/branch-1-1/jmx/src/test/org/apache/hivemind/management/TestMBeanRegistry.java
URL: http://svn.apache.org/viewcvs/jakarta/hivemind/branches/branch-1-1/jmx/src/test/org/apache/hivemind/management/TestMBeanRegistry.java?rev=357642&r1=357641&r2=357642&view=diff
==============================================================================
--- jakarta/hivemind/branches/branch-1-1/jmx/src/test/org/apache/hivemind/management/TestMBeanRegistry.java (original)
+++ jakarta/hivemind/branches/branch-1-1/jmx/src/test/org/apache/hivemind/management/TestMBeanRegistry.java Sun Dec 18 21:37:09 2005
@@ -195,8 +195,8 @@
                     EqualsMatcher matcher = new EqualsMatcher();
                     return matcher.matches(arg0, arg1);
                 }
-                else
-                    return arg1[0].getClass().equals(StandardMBean.class);
+
+                return arg1[0].getClass().equals(StandardMBean.class);
             }
 
             public String toString(Object[] arg0)

Modified: jakarta/hivemind/branches/branch-1-1/status.xml
URL: http://svn.apache.org/viewcvs/jakarta/hivemind/branches/branch-1-1/status.xml?rev=357642&r1=357641&r2=357642&view=diff
==============================================================================
--- jakarta/hivemind/branches/branch-1-1/status.xml (original)
+++ jakarta/hivemind/branches/branch-1-1/status.xml Sun Dec 18 21:37:09 2005
@@ -28,7 +28,11 @@
     </actions>
   </todo>
   <changes>
-    <release version="1.1" date="unreleased">
+    <release version="1.1.1" date="unreleased">
+      <action type="fix" dev="HLS" fixes-bug="HIVEMIND-162">Performance bottleneck with threaded services</action>
+      <action type="fix" dev="HLS" fixes-bug="HIVEMIND-161">ThreadLocal object is never removed in ThreadEventNotifierImpl and holds the classloader</action>
+    </release>    
+    <release version="1.1" date="Oct 26 2005">
       <action type="update" dev="HLS">Change project web site navigation</action>
       <action type="update" dev="HLS">Split up the dist-build target so that just documentation can be built</action>
     </release>



---------------------------------------------------------------------
To unsubscribe, e-mail: hivemind-cvs-unsubscribe@jakarta.apache.org
For additional commands, e-mail: hivemind-cvs-help@jakarta.apache.org


Mime
View raw message