You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tapestry.apache.org by hl...@apache.org on 2006/08/22 17:10:44 UTC

svn commit: r433663 - in /tapestry/tapestry5/tapestry-core/trunk/src: main/java/org/apache/tapestry/ main/java/org/apache/tapestry/internal/ioc/ main/java/org/apache/tapestry/internal/ioc/services/ main/java/org/apache/tapestry/ioc/ main/java/org/apach...

Author: hlship
Date: Tue Aug 22 08:10:42 2006
New Revision: 433663

URL: http://svn.apache.org/viewvc?rev=433663&view=rev
Log:
Add a shutdown() method to Registry.
Decoment Registry startup.
Start work on TapestryFilter.

Added:
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/TapestryFilter.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/services/RegistryShutdownHubImpl.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/services/RegistryShutdownHub.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/services/RegistryShutdownListener.java
    tapestry/tapestry5/tapestry-core/trunk/src/site/apt/ioc/run.apt
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/services/RegistryShutdownHubImplTest.java
Modified:
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/IOCMessages.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/IOCUtilities.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/InternalRegistry.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/ModuleImpl.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/RegistryImpl.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/services/ServiceMessages.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/services/ThreadCleanupHubImpl.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/IOCUtilities.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/Registry.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/services/ThreadCleanupHub.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/internal/ioc/IOCStrings.properties
    tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/internal/ioc/services/ServiceStrings.properties
    tapestry/tapestry5/tapestry-core/trunk/src/site/apt/ioc/module.apt
    tapestry/tapestry5/tapestry-core/trunk/src/site/apt/ioc/service.apt
    tapestry/tapestry5/tapestry-core/trunk/src/site/site.xml
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/ModuleImplTest.java
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/services/DefaultImplementationBuilderImplTest.java
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/services/PipelineBuilderImplTest.java
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/services/ThreadCleanupHubImplTest.java
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/parser/TemplateParserImplTest.java
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/ioc/IntegrationTest.java

Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/TapestryFilter.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/TapestryFilter.java?rev=433663&view=auto
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/TapestryFilter.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/TapestryFilter.java Tue Aug 22 08:10:42 2006
@@ -0,0 +1,95 @@
+// Copyright 2006 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.tapestry;
+
+import java.io.IOException;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+
+import org.apache.tapestry.ioc.IOCUtilities;
+import org.apache.tapestry.ioc.Registry;
+import org.apache.tapestry.ioc.RegistryBuilder;
+import org.apache.tapestry.services.TapestryModule;
+
+/**
+ * The TapestryFilter is responsible for intercepting all requests into the web application. It
+ * identifies the requests that are relevant to Tapestry, and lets the servlet container handle the
+ * rest. It is also responsible for initializating Tapestry.
+ * 
+ * @author Howard M. Lewis Ship
+ */
+public class TapestryFilter implements Filter
+{
+    private Registry _registry;
+
+    public void init(FilterConfig filterConfig) throws ServletException
+    {
+        RegistryBuilder builder = new RegistryBuilder();
+
+        builder.add(TapestryModule.class);
+
+        addModules(builder);
+
+        _registry = builder.build();
+
+        // Initialization code will go here.
+    }
+
+    /**
+     * Adds additional modules to the builder. This implementation adds any modules identified by
+     * {@link IOCUtilities#addDefaultModules(RegistryBuilder)}. Most subclasses will invoke this
+     * implementation, and add additional modules to the RegistryBuilder besides. Most applications
+     * will not need to override this method.
+     * <p>
+     * TODO: Check for an application module in some way.
+     * 
+     * @param builder
+     */
+    protected void addModules(RegistryBuilder builder)
+    {
+        IOCUtilities.addDefaultModules(builder);
+    }
+
+    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
+            throws IOException, ServletException
+    {
+        try
+        {
+            // This is temporary, much more to do in the future. This allows ordinary content to be
+            // accessed. We need to delegate to the tapestry.request.HTTPServletRequestHandler
+            // pipeline.
+
+            chain.doFilter(request, response);
+        }
+        finally
+        {
+            _registry.cleanupThread();
+        }
+    }
+
+    /** Shuts down and discards the registry. */
+    public void destroy()
+    {
+        _registry.shutdown();
+
+        _registry = null;
+    }
+
+}

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/IOCMessages.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/IOCMessages.java?rev=433663&r1=433662&r2=433663&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/IOCMessages.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/IOCMessages.java Tue Aug 22 08:10:42 2006
@@ -266,4 +266,9 @@
                 builderClass.getName(),
                 constructor);
     }
+
+    static String registryShutdown(String serviceId)
+    {
+        return MESSAGES.format("registry-shutdown", serviceId);
+    }
 }

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/IOCUtilities.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/IOCUtilities.java?rev=433663&r1=433662&r2=433663&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/IOCUtilities.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/IOCUtilities.java Tue Aug 22 08:10:42 2006
@@ -189,4 +189,15 @@
 
         return result;
     }
+
+    /**
+     * Invoked by a proxy when the registry has shutdown.
+     * 
+     * @throws IllegalStateException
+     *             always
+     */
+    public static void registryShutdown(String serviceId)
+    {
+        throw new IllegalStateException(IOCMessages.registryShutdown(serviceId));
+    }
 }

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/InternalRegistry.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/InternalRegistry.java?rev=433663&r1=433662&r2=433663&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/InternalRegistry.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/InternalRegistry.java Tue Aug 22 08:10:42 2006
@@ -25,13 +25,14 @@
 import org.apache.tapestry.ioc.ServiceLocator;
 import org.apache.tapestry.ioc.def.ServiceDef;
 import org.apache.tapestry.ioc.services.ClassFab;
+import org.apache.tapestry.ioc.services.RegistryShutdownHub;
 
 /**
  * Internal view of the module registry, adding additional methods needed by modules.
  * 
  * @author Howard M. Lewis Ship
  */
-public interface InternalRegistry extends Registry, LogSource
+public interface InternalRegistry extends Registry, LogSource, RegistryShutdownHub
 {
     /**
      * Locates a service given a fully qualified service id and the corresponding service interface

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/ModuleImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/ModuleImpl.java?rev=433663&r1=433662&r2=433663&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/ModuleImpl.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/ModuleImpl.java Tue Aug 22 08:10:42 2006
@@ -36,6 +36,7 @@
 import org.apache.tapestry.ioc.def.ServiceDef;
 import org.apache.tapestry.ioc.services.ClassFab;
 import org.apache.tapestry.ioc.services.MethodSignature;
+import org.apache.tapestry.ioc.services.RegistryShutdownListener;
 import org.apache.tapestry.util.BodyBuilder;
 
 import static java.lang.String.format;
@@ -304,17 +305,25 @@
 
         String toString = format("<Proxy for %s(%s)>", serviceId, serviceInterface.getName());
 
-        return createProxyInstance(creator, serviceId, serviceInterface, toString);
+        RegistryShutdownListener proxy = createProxyInstance(
+                creator,
+                serviceId,
+                serviceInterface,
+                toString);
+
+        _registry.addRegistryShutdownListener(proxy);
+
+        return proxy;
     }
 
-    private Object createProxyInstance(ObjectCreator creator, String serviceId,
+    private RegistryShutdownListener createProxyInstance(ObjectCreator creator, String serviceId,
             Class serviceInterface, String description)
     {
         Class proxyClass = createProxyClass(serviceId, serviceInterface, description);
 
         try
         {
-            return proxyClass.getConstructors()[0].newInstance(creator);
+            return (RegistryShutdownListener) proxyClass.getConstructors()[0].newInstance(creator);
         }
         catch (Exception ex)
         {
@@ -330,22 +339,33 @@
 
         cf.addField("_creator", ObjectCreator.class);
         cf.addField("_delegate", serviceInterface);
+        cf.addField("_shutdown", boolean.class);
 
         cf.addConstructor(new Class[]
         { ObjectCreator.class }, null, "_creator = $1;");
 
-        addDelegateGetter(cf, serviceInterface);
+        addDelegateGetter(cf, serviceInterface, serviceId);
+
+        addShutdownListenerMethod(cf);
 
         cf.proxyMethodsToDelegate(serviceInterface, "_delegate()", proxyDescription);
 
         return cf.createClass();
     }
 
-    private void addDelegateGetter(ClassFab cf, Class serviceInterface)
+    private void addDelegateGetter(ClassFab cf, Class serviceInterface, String serviceId)
     {
         BodyBuilder builder = new BodyBuilder();
         builder.begin();
 
+        // Check to see if the registry has shutdown. The registryShutdown() method
+        // throws IllegalStateException.
+
+        builder.addln(
+                "if (_shutdown) %s.registryShutdown(\"%s\");",
+                IOCUtilities.class.getName(),
+                serviceId);
+
         // We can release the creator after invoking it, we only create the service once.
 
         builder.addln("if (_delegate == null)");
@@ -364,6 +384,23 @@
         // Let's hope that they aren't lying when they say that synchronized is now super cheap!
 
         cf.addMethod(Modifier.PRIVATE | Modifier.SYNCHRONIZED, sig, builder.toString());
+    }
+
+    /**
+     * All proxies implement {@link RegistryShutdownListener}. When the registry shuts down, the
+     * proxy sets a flag that ultimately converts method invocations to
+     * {@link IllegalStateException}s, and discards its delegate and creator.
+     */
+    private void addShutdownListenerMethod(ClassFab cf)
+    {
+        cf.addInterface(RegistryShutdownListener.class);
+
+        MethodSignature sig = new MethodSignature(void.class, "registryDidShutdown", null, null);
+
+        cf.addMethod(
+                Modifier.PUBLIC | Modifier.SYNCHRONIZED,
+                sig,
+                "{ _shutdown = true; _delegate = null; _creator = null; }");
     }
 
     public String getModuleId()

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/RegistryImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/RegistryImpl.java?rev=433663&r1=433662&r2=433663&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/RegistryImpl.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/RegistryImpl.java Tue Aug 22 08:10:42 2006
@@ -22,8 +22,10 @@
 import java.util.Set;
 
 import org.apache.commons.logging.Log;
+import org.apache.tapestry.internal.annotations.OneShot;
 import org.apache.tapestry.internal.annotations.SuppressNullCheck;
 import org.apache.tapestry.internal.ioc.services.ClassFactoryImpl;
+import org.apache.tapestry.internal.ioc.services.RegistryShutdownHubImpl;
 import org.apache.tapestry.internal.ioc.services.ThreadCleanupHubImpl;
 import org.apache.tapestry.internal.util.Orderer;
 import org.apache.tapestry.ioc.Configuration;
@@ -44,6 +46,8 @@
 import org.apache.tapestry.ioc.def.ServiceDef;
 import org.apache.tapestry.ioc.services.ClassFab;
 import org.apache.tapestry.ioc.services.ClassFactory;
+import org.apache.tapestry.ioc.services.RegistryShutdownHub;
+import org.apache.tapestry.ioc.services.RegistryShutdownListener;
 import org.apache.tapestry.ioc.services.ServiceLifecycleSource;
 import org.apache.tapestry.ioc.services.ThreadCleanupHub;
 import org.apache.tapestry.util.CollectionFactory;
@@ -54,8 +58,11 @@
 /**
  * @author Howard M. Lewis Ship
  */
+@OneShot
 public class RegistryImpl implements Registry, InternalRegistry
 {
+    private static final String REGISTRY_SHUTDOWN_HUB_SERVICE_ID = "tapestry.ioc.RegistryShutdownHub";
+
     static final String THREAD_CLEANUP_HUB_SERVICE_ID = "tapestry.ioc.ThreadCleanupHub";
 
     /**
@@ -70,6 +77,19 @@
 
     private final Map<String, Class> _builtinTypes = newMap();
 
+    private final RegistryShutdownHubImpl _registryShutdownHub;
+
+    private final LogSource _logSource;
+
+    /** Keyed on module id. */
+    private final Map<String, Module> _modules = newMap();
+
+    private final Map<String, ServiceLifecycle> _lifecycles = newMap();
+
+    private final ThreadCleanupHubImpl _cleanupHub;
+
+    private final ClassFactory _classFactory;
+
     @SuppressNullCheck
     public static final class OrderedConfigurationToOrdererAdaptor<T> implements
             OrderedConfiguration<T>
@@ -87,17 +107,6 @@
         }
     }
 
-    private final LogSource _logSource;
-
-    /** Keyed on module id. */
-    private final Map<String, Module> _modules = newMap();
-
-    private final Map<String, ServiceLifecycle> _lifecycles = newMap();
-
-    private final ThreadCleanupHub _cleanupHub;
-
-    private final ClassFactory _classFactory;
-
     public RegistryImpl(Collection<ModuleDef> moduleDefs, LogSource logSource)
     {
         _logSource = logSource;
@@ -125,6 +134,15 @@
 
         addBuiltin(THREAD_CLEANUP_HUB_SERVICE_ID, ThreadCleanupHub.class, _cleanupHub);
 
+        log = _logSource.getLog(REGISTRY_SHUTDOWN_HUB_SERVICE_ID);
+
+        _registryShutdownHub = new RegistryShutdownHubImpl(log);
+
+        addBuiltin(
+                REGISTRY_SHUTDOWN_HUB_SERVICE_ID,
+                RegistryShutdownHub.class,
+                _registryShutdownHub);
+
         _lifecycles.put("singleton", new SingletonServiceLifecycle());
     }
 
@@ -134,6 +152,12 @@
         _builtinServices.put(serviceId, service);
     }
 
+    @OneShot.Lockdown
+    public synchronized void shutdown()
+    {
+        _registryShutdownHub.fireRegistryDidShutdown();
+    }
+
     /** Internal access, usualy from another module. */
     @SuppressNullCheck
     public <T> T getService(String serviceId, Class<T> serviceInterface, Module module)
@@ -511,4 +535,8 @@
         return getObject(reference, objectType, this);
     }
 
+    public void addRegistryShutdownListener(RegistryShutdownListener listener)
+    {
+        _registryShutdownHub.addRegistryShutdownListener(listener);
+    }
 }

Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/services/RegistryShutdownHubImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/services/RegistryShutdownHubImpl.java?rev=433663&view=auto
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/services/RegistryShutdownHubImpl.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/services/RegistryShutdownHubImpl.java Tue Aug 22 08:10:42 2006
@@ -0,0 +1,71 @@
+// Copyright 2006 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.tapestry.internal.ioc.services;
+
+import java.util.List;
+
+import org.apache.commons.logging.Log;
+import org.apache.tapestry.internal.annotations.OneShot;
+import org.apache.tapestry.ioc.services.RegistryShutdownHub;
+import org.apache.tapestry.ioc.services.RegistryShutdownListener;
+
+import static org.apache.tapestry.util.CollectionFactory.newThreadSafeList;
+
+/**
+ * @author Howard M. Lewis Ship
+ */
+@OneShot
+public class RegistryShutdownHubImpl implements RegistryShutdownHub
+{
+    private final Log _log;
+
+    private final List<RegistryShutdownListener> _listeners = newThreadSafeList();
+
+    public RegistryShutdownHubImpl(Log log)
+    {
+        _log = log;
+    }
+
+    public void addRegistryShutdownListener(RegistryShutdownListener listener)
+    {
+        _listeners.add(listener);
+    }
+
+    /**
+     * Fires the {@link RegistryShutdownListener#registryDidShutdown()} method on each listener. At
+     * the end, all the listeners are discarded.
+     * 
+     * @param log
+     *            used if any listener throws an exception
+     */
+    @OneShot.Lockdown
+    public void fireRegistryDidShutdown()
+    {
+        for (RegistryShutdownListener l : _listeners)
+        {
+            try
+            {
+                l.registryDidShutdown();
+            }
+            catch (Exception ex)
+            {
+                _log.error(ServiceMessages.shutdownListenerError(l, ex), ex);
+            }
+        }
+
+        _listeners.clear();
+    }
+
+}

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/services/ServiceMessages.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/services/ServiceMessages.java?rev=433663&r1=433662&r2=433663&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/services/ServiceMessages.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/services/ServiceMessages.java Tue Aug 22 08:10:42 2006
@@ -136,4 +136,8 @@
         return MESSAGES.format("unknown-object-provider", prefix, reference);
     }
 
+    static String shutdownListenerError(Object listener, Throwable cause)
+    {
+        return MESSAGES.format("shutdown-listener-error", listener, cause);
+    }
 }

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/services/ThreadCleanupHubImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/services/ThreadCleanupHubImpl.java?rev=433663&r1=433662&r2=433663&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/services/ThreadCleanupHubImpl.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/services/ThreadCleanupHubImpl.java Tue Aug 22 08:10:42 2006
@@ -50,6 +50,10 @@
         _holder.get().add(listener);
     }
 
+    /**
+     * Instructs the hub to notify all its listeners (for the current thread). It also discards its
+     * list of listeners.
+     */
     public void cleanup()
     {
         List<ThreadCleanupListener> listeners = _holder.get();

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/IOCUtilities.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/IOCUtilities.java?rev=433663&r1=433662&r2=433663&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/IOCUtilities.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/IOCUtilities.java Tue Aug 22 08:10:42 2006
@@ -41,7 +41,7 @@
      * 
      * @return constructed Registry
      */
-    public static Registry buildDefaultRegistry(String... classnames)
+    public static Registry buildDefaultRegistry()
     {
         RegistryBuilder builder = new RegistryBuilder();
 

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/Registry.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/Registry.java?rev=433663&r1=433662&r2=433663&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/Registry.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/Registry.java Tue Aug 22 08:10:42 2006
@@ -26,6 +26,17 @@
      * the current request.
      * 
      * @see org.apache.tapestry.ioc.services.ThreadCleanupHub
+     * @see org.apache.tapestry.ioc.services.ThreadCleanupListener
      */
     void cleanupThread();
+
+    /**
+     * Shuts down a Registry instance. Notifies all listeners that the registry has shutdown.
+     * Further method invocations on the Registry are no longer allowed, and the Registry instance
+     * should be discarded.
+     * 
+     * @see org.apache.tapestry.ioc.services.RegistryShutdownHub
+     * @see org.apache.tapestry.ioc.services.RegistryShutdownListener
+     */
+    void shutdown();
 }

Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/services/RegistryShutdownHub.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/services/RegistryShutdownHub.java?rev=433663&view=auto
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/services/RegistryShutdownHub.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/services/RegistryShutdownHub.java Tue Aug 22 08:10:42 2006
@@ -0,0 +1,26 @@
+// Copyright 2006 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.tapestry.ioc.services;
+
+/**
+ * Event hub for notifications when the IOC {@link org.apache.tapestry.ioc.Registry} shuts down.
+ * 
+ * @author Howard M. Lewis Ship
+ */
+public interface RegistryShutdownHub
+{
+    /** Adds a listener for eventual notification. */
+    void addRegistryShutdownListener(RegistryShutdownListener listener);
+}

Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/services/RegistryShutdownListener.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/services/RegistryShutdownListener.java?rev=433663&view=auto
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/services/RegistryShutdownListener.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/services/RegistryShutdownListener.java Tue Aug 22 08:10:42 2006
@@ -0,0 +1,32 @@
+// Copyright 2006 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.tapestry.ioc.services;
+
+import java.util.EventListener;
+
+/**
+ * Event listener interfaces for objects that need to know when the Registry shutsdown.
+ * 
+ * @author Howard M. Lewis Ship
+ */
+public interface RegistryShutdownListener extends EventListener
+{
+    /**
+     * Invoked when the registry shuts down, giving services a chance to perform any final
+     * operations. Service implementations should not attempt to invoke methods on other services
+     * (via proxies) as the service proxies may themselves be shutdown.
+     */
+    void registryDidShutdown();
+}

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/services/ThreadCleanupHub.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/services/ThreadCleanupHub.java?rev=433663&r1=433662&r2=433663&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/services/ThreadCleanupHub.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/services/ThreadCleanupHub.java Tue Aug 22 08:10:42 2006
@@ -32,10 +32,4 @@
      *            to add
      */
     void addThreadCleanupListener(ThreadCleanupListener listener);
-
-    /**
-     * Instructs the hub to notify all its listeners (for the current thread). It also discards its
-     * list of listeners.
-     */
-    void cleanup();
 }

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/internal/ioc/IOCStrings.properties
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/internal/ioc/IOCStrings.properties?rev=433663&r1=433662&r2=433663&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/internal/ioc/IOCStrings.properties (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/internal/ioc/IOCStrings.properties Tue Aug 22 08:10:42 2006
@@ -72,4 +72,5 @@
   The first constructor, %s, is being used. \
   You should change the class to have only a single public constructor.
 recursive-module-constructor=The constructor for module '%s' (class %s) is recursive: it depends on itself in some way. \
-  The constructor, %s, is in some way is triggering a service builder, decorator or contribution method within the class.
\ No newline at end of file
+  The constructor, %s, is in some way is triggering a service builder, decorator or contribution method within the class.
+registry-shutdown=Proxy for service %s is no longer active because the IOC Registry has been shut down.

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/internal/ioc/services/ServiceStrings.properties
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/internal/ioc/services/ServiceStrings.properties?rev=433663&r1=433662&r2=433663&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/internal/ioc/services/ServiceStrings.properties (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/internal/ioc/services/ServiceStrings.properties Tue Aug 22 08:10:42 2006
@@ -29,4 +29,5 @@
 extra-filter-method=Method %s of filter interface %s does not have a matching method in %s.
 unmatched-service-method=Method %s has no match in filter interface %s.
 object-reference-format-error=Object reference '%s' does not contain an provider prefix (such as 'service:').
-unknown-object-provider=Object provider '%s' does not exist (in object reference '%s').
\ No newline at end of file
+unknown-object-provider=Object provider '%s' does not exist (in object reference '%s').
+shutdown-listener-error=Error notifying %s of registry shutdown: %s

Modified: tapestry/tapestry5/tapestry-core/trunk/src/site/apt/ioc/module.apt
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/site/apt/ioc/module.apt?rev=433663&r1=433662&r2=433663&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/site/apt/ioc/module.apt (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/site/apt/ioc/module.apt Tue Aug 22 08:10:42 2006
@@ -131,7 +131,7 @@
   
   Tapestry detects these scenarios and throws a runtime exception to prevent an endless loop.
     
-Autoloading modules
+{Autoloading modules}
 
   When setting up the registry, Tapestry can automatically locate modules packaged into JARs.
   It does this by searching for a particular global manifest entry. 

Added: tapestry/tapestry5/tapestry-core/trunk/src/site/apt/ioc/run.apt
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/site/apt/ioc/run.apt?rev=433663&view=auto
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/site/apt/ioc/run.apt (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/site/apt/ioc/run.apt Tue Aug 22 08:10:42 2006
@@ -0,0 +1,56 @@
+ ----
+ Starting the Tapestry IOC Registry
+ ----
+ 
+Starting the Tapestry IOC Registry
+
+ Primarily, you will use the IOC Registry as part of a Tapestry application.
+ In those situations, the 
+ {{{../apidocs/org/apache/tapestry/TapestryFilter.html}TapestryFilter}} will
+ be responsible for starting and stopping the registry.
+ 
+ However, you may want to do some integration testing using the Registry
+ from within a test case, or you may even use Tapestry IOC separately from
+ Tapestry.
+ 
+Building the Registry
+
+  The class
+  {{{../apidocs/org/apache/tapestry/ioc/RegistryBuilder.html}RegistryBuilder}}
+  is used to create a Registry.
+  
++---+
+RegistryBuilder builder = new RegistryBuilder();
+
+builder.add(AppModule.class, UtilModule.class);
+
+Registry registry = builder.build();
++---+
+
+  You may invoke add() as many times as you wish, or pass as many module classes
+  as you wish.
+  
+  Using this approach, you will form a Registry containing
+  the builtin services from the
+  {{{../apidocs/org/apache/tapestry/ioc/services/TapestryIOCModule.html}tapestry.ioc module}}, plus
+  the modules you explicitly list.
+  
+Building the Default Registry
+
+  The default registry is available by invoking the static method
+  {{{../apidocs/org/apache/tapestry/ioc/IOCUtilities.html#buildDefaultRegistry()}IOCUtilities.buildDefaultRegistry()}}.
+  This method builds a Registry using
+  {{{module.html#Autoloading modules}autoloading logic}}, where modules to load
+  are identified via a JAR Manifest entry.
+  
+Shutting down the Registry
+
+  The method
+  {{{../apidocs/org/apache/tapestry/ioc/Registry.html#shutdown()}Registry.shutdown()}}
+  will shutdown the Registry. This immediately invalidates all service proxies.
+  Some services may have chosen to register for shutdown notification (for example,
+  to do cleanup work such as closing a database connection).
+  
+  Once the Registry is shutdown, it may not be used again: it will not be possible to
+  access services within the Registry, or invoke methods on services previously
+  acquired.  All you can do is release the Registry to the garbage collector.

Modified: tapestry/tapestry5/tapestry-core/trunk/src/site/apt/ioc/service.apt
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/site/apt/ioc/service.apt?rev=433663&r1=433662&r2=433663&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/site/apt/ioc/service.apt (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/site/apt/ioc/service.apt Tue Aug 22 08:10:42 2006
@@ -248,15 +248,17 @@
   in the
   {{{../apidocs/org/apache/tapestry/ioc/services/TapestryIOCModule.html}TapestryIOCModule}} class.
   
-*-------------------------------+-----------------------------------------------------------------------------------------+
-| <<Service Id>>                | <<Service Interface>>                                                                   |
-*-------------------------------+-----------------------------------------------------------------------------------------+
-| tapestry.ioc.ClassFactory     | {{{../apidocs/org/apache/tapestry/ioc/services/ClassFactory.html}ClassFactory}}         |
-*-------------------------------+-----------------------------------------------------------------------------------------+
-| tapestry.ioc.LogSource        | {{{../apidocs/org/apache/tapestry/ioc/LogSource.html}LogSource}}                        |
-*-------------------------------+-----------------------------------------------------------------------------------------+
-| tapestry.ioc.ThreadCleanupHub | {{{../apidocs/org/apache/tapestry/ioc/services/ThreadCleanupHub.html}ThreadCleanupHub}} |
-*-------------------------------+-----------------------------------------------------------------------------------------+
+*----------------------------------+-----------------------------------------------------------------------------------------+
+| <<Service Id>>                   | <<Service Interface>>                                                                   |
+*----------------------------------+-----------------------------------------------------------------------------------------+
+| tapestry.ioc.ClassFactory        | {{{../apidocs/org/apache/tapestry/ioc/services/ClassFactory.html}ClassFactory}}         |
+*----------------------------------+-----------------------------------------------------------------------------------------+
+| tapestry.ioc.LogSource           | {{{../apidocs/org/apache/tapestry/ioc/LogSource.html}LogSource}}                        |
+*----------------------------------+-----------------------------------------------------------------------------------------+
+| tapestry.ioc.RegistryShutdownHub | {{{../apidocs/org/apache/tapestry/ioc/RegistryShutdownHub.html}RegistryShutdownHub}}    |
+*----------------------------------+-----------------------------------------------------------------------------------------+
+| tapestry.ioc.ThreadCleanupHub    | {{{../apidocs/org/apache/tapestry/ioc/services/ThreadCleanupHub.html}ThreadCleanupHub}} |
+*----------------------------------+-----------------------------------------------------------------------------------------+
 
   
 Mutually Dependant Services

Modified: tapestry/tapestry5/tapestry-core/trunk/src/site/site.xml
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/site/site.xml?rev=433663&r1=433662&r2=433663&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/site/site.xml (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/site/site.xml Tue Aug 22 08:10:42 2006
@@ -56,6 +56,7 @@
             <item name="Services" href="ioc/service.html"/>
             <item name="Decorators" href="ioc/decorator.html"/>
             <item name="Configuration" href="ioc/configuration.html"/>
+            <item name="Starting the Registry" href="ioc/run.html"/>
             <item name="Object Providers" href="ioc/provider.html"/>
             <item name="Ordering" href="ioc/order.html"/>
             <item name="Chain Of Command" href="ioc/command.html"/>

Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/ModuleImplTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/ModuleImplTest.java?rev=433663&r1=433662&r2=433663&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/ModuleImplTest.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/ModuleImplTest.java Tue Aug 22 08:10:42 2006
@@ -27,9 +27,11 @@
 import org.apache.tapestry.ioc.def.ModuleDef;
 import org.apache.tapestry.ioc.def.ServiceDef;
 import org.apache.tapestry.ioc.services.ClassFactory;
+import org.apache.tapestry.ioc.services.RegistryShutdownListener;
 import org.testng.annotations.Test;
 
 import static org.easymock.EasyMock.contains;
+import static org.easymock.EasyMock.isA;
 
 /**
  * @author Howard M. Lewis Ship
@@ -56,6 +58,8 @@
 
         trainNewClass(registry, factory, UpcaseService.class);
 
+        registry.addRegistryShutdownListener(isA(RegistryShutdownListener.class));
+
         trainIsDebugEnabled(log, false);
 
         trainFindDecoratorsForService(registry);
@@ -94,6 +98,8 @@
         trainGetLifecycle(registry, "singleton", new SingletonServiceLifecycle());
 
         trainNewClass(registry, factory, UpcaseService.class);
+
+        registry.addRegistryShutdownListener(isA(RegistryShutdownListener.class));
 
         trainIsDebugEnabled(log, false);
 

Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/services/DefaultImplementationBuilderImplTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/services/DefaultImplementationBuilderImplTest.java?rev=433663&r1=433662&r2=433663&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/services/DefaultImplementationBuilderImplTest.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/services/DefaultImplementationBuilderImplTest.java Tue Aug 22 08:10:42 2006
@@ -17,6 +17,7 @@
 import org.apache.tapestry.internal.test.InternalBaseTestCase;
 import org.apache.tapestry.ioc.Registry;
 import org.apache.tapestry.ioc.services.DefaultImplementationBuilder;
+import org.testng.annotations.AfterClass;
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.Test;
 
@@ -25,18 +26,29 @@
  */
 public class DefaultImplementationBuilderImplTest extends InternalBaseTestCase
 {
+    private Registry _registry;
+
     private DefaultImplementationBuilder _builder;
 
     @BeforeClass
     public void setup_builder()
     {
-        Registry registry = buildRegistry();
+        _registry = buildRegistry();
 
-        _builder = registry.getService(
+        _builder = _registry.getService(
                 "tapestry.ioc.DefaultImplementationBuilder",
                 DefaultImplementationBuilder.class);
     }
 
+    @AfterClass
+    public void shutdown_registry()
+    {
+        _registry.shutdown();
+
+        _builder = null;
+        _registry = null;
+    }
+
     @Test
     public void simple_interface()
     {
@@ -68,7 +80,7 @@
 
         // With tests in parallel, there's a harmless race condition that can cause r1 != r2
         // for one pass, so we give it a second chance to prove itself.
-        
+
         for (int i = 0; i < 2; i++)
         {
             r1 = _builder.createDefaultImplementation(Runnable.class);

Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/services/PipelineBuilderImplTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/services/PipelineBuilderImplTest.java?rev=433663&r1=433662&r2=433663&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/services/PipelineBuilderImplTest.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/services/PipelineBuilderImplTest.java Tue Aug 22 08:10:42 2006
@@ -21,6 +21,7 @@
 import org.apache.tapestry.internal.test.InternalBaseTestCase;
 import org.apache.tapestry.ioc.Registry;
 import org.apache.tapestry.ioc.services.PipelineBuilder;
+import org.testng.annotations.AfterClass;
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.Test;
 
@@ -36,13 +37,22 @@
 
     private PipelineBuilder _builder;
 
+    private Registry _registry;
+
     @BeforeClass
     public void setup_builder()
     {
-        Registry registry = buildRegistry();
+        _registry = buildRegistry();
+        _builder = _registry.getService("tapestry.ioc.PipelineBuilder", PipelineBuilder.class);
+    }
 
-        _builder = registry.getService("tapestry.ioc.PipelineBuilder", PipelineBuilder.class);
+    @AfterClass
+    public void shutdown_builder()
+    {
+        _registry.shutdown();
 
+        _builder = null;
+        _registry = null;
     }
 
     @Test

Added: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/services/RegistryShutdownHubImplTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/services/RegistryShutdownHubImplTest.java?rev=433663&view=auto
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/services/RegistryShutdownHubImplTest.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/services/RegistryShutdownHubImplTest.java Tue Aug 22 08:10:42 2006
@@ -0,0 +1,93 @@
+// Copyright 2006 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.tapestry.internal.ioc.services;
+
+import org.apache.commons.logging.Log;
+import org.apache.tapestry.internal.test.InternalBaseTestCase;
+import org.apache.tapestry.ioc.services.RegistryShutdownListener;
+import org.testng.annotations.Test;
+
+import static org.easymock.EasyMock.contains;
+import static org.easymock.EasyMock.same;
+
+/**
+ * @author Howard M. Lewis Ship
+ */
+public class RegistryShutdownHubImplTest extends InternalBaseTestCase
+{
+
+    @Test
+    public void add_and_notify()
+    {
+        RegistryShutdownListener l1 = newListener();
+        RegistryShutdownListener l2 = newListener();
+        Log log = newLog();
+
+        l1.registryDidShutdown();
+        l2.registryDidShutdown();
+
+        replay();
+
+        RegistryShutdownHubImpl hub = new RegistryShutdownHubImpl(log);
+
+        hub.addRegistryShutdownListener(l1);
+        hub.addRegistryShutdownListener(l2);
+
+        hub.fireRegistryDidShutdown();
+
+        verify();
+    }
+
+    /**
+     * Shows that multiple listener will be notified, and that an error in one doesn't prevent
+     * others from being notified.
+     */
+    @Test
+    public void notification_error()
+    {
+        RegistryShutdownListener l1 = newListener();
+        RegistryShutdownListener l2 = newListener();
+        RegistryShutdownListener l3 = newListener();
+
+        Log log = newLog();
+
+        Throwable t = new RuntimeException("Shutdown failure.");
+
+        l1.registryDidShutdown();
+        l2.registryDidShutdown();
+        setThrowable(t);
+
+        log.error(contains("Shutdown failure."), same(t));
+
+        l3.registryDidShutdown();
+
+        replay();
+
+        RegistryShutdownHubImpl hub = new RegistryShutdownHubImpl(log);
+
+        hub.addRegistryShutdownListener(l1);
+        hub.addRegistryShutdownListener(l2);
+        hub.addRegistryShutdownListener(l3);
+
+        hub.fireRegistryDidShutdown();
+
+        verify();
+    }
+
+    private RegistryShutdownListener newListener()
+    {
+        return newMock(RegistryShutdownListener.class);
+    }
+}

Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/services/ThreadCleanupHubImplTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/services/ThreadCleanupHubImplTest.java?rev=433663&r1=433662&r2=433663&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/services/ThreadCleanupHubImplTest.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/services/ThreadCleanupHubImplTest.java Tue Aug 22 08:10:42 2006
@@ -16,7 +16,6 @@
 
 import org.apache.commons.logging.Log;
 import org.apache.tapestry.internal.test.InternalBaseTestCase;
-import org.apache.tapestry.ioc.services.ThreadCleanupHub;
 import org.apache.tapestry.ioc.services.ThreadCleanupListener;
 import org.testng.annotations.Test;
 
@@ -47,7 +46,7 @@
 
         replay();
 
-        ThreadCleanupHub hub = new ThreadCleanupHubImpl(log);
+        ThreadCleanupHubImpl hub = new ThreadCleanupHubImpl(log);
 
         hub.addThreadCleanupListener(listener);
 
@@ -92,7 +91,7 @@
 
         replay();
 
-        ThreadCleanupHub hub = new ThreadCleanupHubImpl(log);
+        ThreadCleanupHubImpl hub = new ThreadCleanupHubImpl(log);
 
         hub.addThreadCleanupListener(listener);
 

Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/parser/TemplateParserImplTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/parser/TemplateParserImplTest.java?rev=433663&r1=433662&r2=433663&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/parser/TemplateParserImplTest.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/parser/TemplateParserImplTest.java Tue Aug 22 08:10:42 2006
@@ -21,6 +21,7 @@
 import org.apache.tapestry.Resource;
 import org.apache.tapestry.internal.ClasspathResource;
 import org.apache.tapestry.test.BaseTestCase;
+import org.testng.annotations.AfterClass;
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.Test;
 
@@ -42,9 +43,15 @@
      * will actually do a very good job of simulating how a parser is used in production.
      */
     @BeforeClass
-    public void setupParser()
+    public void setup_parser()
     {
         _parser = new TemplateParserImpl();
+    }
+
+    @AfterClass
+    public void discard_parser()
+    {
+        _parser = null;
     }
 
     private ComponentTemplate parse(String file)

Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/ioc/IntegrationTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/ioc/IntegrationTest.java?rev=433663&r1=433662&r2=433663&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/ioc/IntegrationTest.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/ioc/IntegrationTest.java Tue Aug 22 08:10:42 2006
@@ -37,6 +37,34 @@
         return buildRegistry(FredModule.class, BarneyModule.class);
     }
 
+    @Test
+    public void shutdown_deactivates_proxies()
+    {
+        Registry r = buildRegistry();
+
+        Runnable service = r.getService("fred.Fred", Runnable.class);
+
+        service.run();
+
+        r.shutdown();
+
+        try
+        {
+            service.run();
+            unreachable();
+        }
+        catch (IllegalStateException ex)
+        {
+            assertEquals(
+                    ex.getMessage(),
+                    "Proxy for service fred.Fred is no longer active because the IOC Registry has been shut down.");
+        }
+
+        // Show that toString() still works, even for a shutdown proxy.
+
+        assertEquals(service.toString(), "<Proxy for fred.Fred(java.lang.Runnable)>");
+    }
+
     /**
      * Along the way, we also test a few other things, such as decorator matching and automatic
      * dependency resolution.