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/07/28 21:56:01 UTC

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

Author: hlship
Date: Fri Jul 28 12:56:00 2006
New Revision: 426656

URL: http://svn.apache.org/viewvc?rev=426656&view=rev
Log:
Add support for adding additional service lifecycles.
Start work on perthread service lifecycle.

Added:
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/services/PerThreadServiceLifecycle.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/services/ServiceLifecycleSource.java
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/ioc/UnknownLifecycleModule.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/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/ioc/ServiceLifecycle.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/services/TapestryIOCModule.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/internal/ioc/IOCStrings.properties
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/ioc/IntegrationTest.java

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=426656&r1=426655&r2=426656&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 Fri Jul 28 12:56:00 2006
@@ -235,4 +235,9 @@
                 contributionDef,
                 existingDef);
     }
+
+    static String errorBuildingService(String serviceId, ServiceDef serviceDef, Throwable cause)
+    {
+        return MESSAGES.format("error-building-service", serviceId, serviceDef, cause);
+    }
 }

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=426656&r1=426655&r2=426656&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 Fri Jul 28 12:56:00 2006
@@ -184,60 +184,68 @@
      */
     private Object create(ServiceDef def)
     {
-        ensureModuleBuilderExists();
-
         String serviceId = def.getServiceId();
 
         if (_underConstruction.contains(serviceId))
             throw new IllegalStateException(IOCMessages.recursiveServiceBuild(def));
 
-        _underConstruction.add(serviceId);
-
         Log log = _registry.getLog(serviceId);
 
         if (log.isDebugEnabled())
             log.debug(IOCMessages.creatingService(serviceId));
 
-        // TODO: Check for recursive service build? This could happen if the
-        // builder method for the service (or a decorator method applied to the service)
-        // takes the service as a parameter.
-
-        ServiceLifecycle lifecycle = _registry.getServiceLifecycle(def.getServiceLifeycle());
-
-        ServiceCreatorResources resources = new ServiceResourcesImpl(_registry, this, def, log);
-
-        // Build up a stack of operations that will be needed to instantiate the service
-        // (by the proxy, at a later date).
-
-        ServiceCreator creator = def.createServiceCreator(_moduleBuilder, resources);
-
-        creator = new LifecycleWrappedServiceCreator(lifecycle, resources, creator);
-
-        // Built in services are not decorated, ever.
-
-        if (!_moduleDef.getModuleId().equals(INTERNAL_MODULE_ID))
-            creator = new InterceptorStackBuilder(this, serviceId, creator);
-
-        // Add a wrapper that makes sure that it only gets created once. For primitive (or
-        // other non-proxy lifecycle)
-        // services, we rely upon _underConstruction to track the ids of services
-        // being created (that's because a recursive call in a primitive service's
-        // service builder method will cause a new ServiceCreator stack to be created,
-        // with an eventual Java stack overflow).
-
-        creator = new OneShotServiceCreator(def, creator);
-
-        // For primitive services, we just create the service right here. For non-primitive services
-        // we create the proxy the defers creation until needed.
-
-        Object service = lifecycle.getCreateProxy() ? createProxy(resources, creator) : creator
-                .createService();
-
-        _services.put(serviceId, service);
-
-        _underConstruction.remove(serviceId);
+        _underConstruction.add(serviceId);
 
-        return service;
+        try
+        {
+            ServiceLifecycle lifecycle = _registry.getServiceLifecycle(def.getServiceLifeycle());
+
+            ServiceCreatorResources resources = new ServiceResourcesImpl(_registry, this, def, log);
+
+            // Build up a stack of operations that will be needed to instantiate the service
+            // (by the proxy, at a later date).
+
+            ServiceCreator creator = def.createServiceCreator(getModuleBuilder(), resources);
+
+            creator = new LifecycleWrappedServiceCreator(lifecycle, resources, creator);
+
+            // Built in services are not decorated, ever.
+
+            if (!_moduleDef.getModuleId().equals(INTERNAL_MODULE_ID))
+                creator = new InterceptorStackBuilder(this, serviceId, creator);
+
+            Object service = null;
+
+            if (lifecycle.getCreateProxy())
+            {
+                service = createProxy(resources, creator);
+            }
+            else
+            {
+                // Add a wrapper that makes sure that it only gets created once. For primitive (or
+                // other non-proxy lifecycle)
+                // services, we rely upon _underConstruction to track the ids of services
+                // being created (that's because a recursive call in a primitive service's
+                // service builder method will cause a new ServiceCreator stack to be created,
+                // with an eventual Java stack overflow).
+
+                creator = new OneShotServiceCreator(def, creator);
+
+                service = creator.createService();
+            }
+
+            _services.put(serviceId, service);
+
+            return service;
+        }
+        catch (Exception ex)
+        {
+            throw new RuntimeException(IOCMessages.errorBuildingService(serviceId, def, ex), ex);
+        }
+        finally
+        {
+            _underConstruction.remove(serviceId);
+        }
     }
 
     private synchronized void ensureModuleBuilderExists()

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=426656&r1=426655&r2=426656&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 Fri Jul 28 12:56:00 2006
@@ -38,6 +38,7 @@
 import org.apache.tapestry.ioc.def.DecoratorDef;
 import org.apache.tapestry.ioc.def.ModuleDef;
 import org.apache.tapestry.ioc.def.ServiceDef;
+import org.apache.tapestry.ioc.services.ServiceLifecycleSource;
 import org.apache.tapestry.util.CollectionFactory;
 
 import static org.apache.tapestry.util.CollectionFactory.newList;
@@ -316,7 +317,13 @@
     {
         ServiceLifecycle result = _lifecycles.get(lifecycle);
 
-        // TODO: Check elsewhere for contributed lifecycles if not one of the builtin lifecycle
+        if (result == null)
+        {
+            ServiceLifecycleSource source = getService(
+                    "tapestry.ioc.ServiceLifecycleSource",
+                    ServiceLifecycleSource.class);
+            result = source.get(lifecycle);
+        }
 
         if (result == null)
             throw new RuntimeException(IOCMessages.unknownLifecycle(lifecycle));

Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/services/PerThreadServiceLifecycle.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/services/PerThreadServiceLifecycle.java?rev=426656&view=auto
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/services/PerThreadServiceLifecycle.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/services/PerThreadServiceLifecycle.java Fri Jul 28 12:56:00 2006
@@ -0,0 +1,37 @@
+package org.apache.tapestry.internal.ioc.services;
+
+import org.apache.tapestry.ioc.ServiceCreator;
+import org.apache.tapestry.ioc.ServiceLifecycle;
+import org.apache.tapestry.ioc.ServiceResources;
+import org.apache.tapestry.ioc.services.ClassFactory;
+import org.apache.tapestry.ioc.services.ThreadCleanupHub;
+
+/**
+ * Allows a service to exist "per thread" (in each thread). This involves an inner proxy, with a
+ * ThreadLocal whose initial value is derived from a {@link org.apache.tapestry.ioc.ServiceCreator}.
+ * Method invocations are delegated to the per-thread service instance. The proxy also implements
+ * {@link org.apache.tapestry.ioc.services.ThreadCleanupListener} so that it can discard the
+ * per-thread implementation.
+ * <p>
+ * This scheme ensures that, although the service builder method will be invoked many times of the
+ * life of the application, the service decoration process occurs only once.
+ * 
+ * @author Howard M. Lewis Ship
+ */
+public class PerThreadServiceLifecycle implements ServiceLifecycle
+{
+    private final ThreadCleanupHub _threadCleanupHub;
+
+    private final ClassFactory _classFactory;
+
+    public Object createService(ServiceResources resources, ServiceCreator creator)
+    {
+        return null;
+    }
+
+    public boolean getCreateProxy()
+    {
+        return true;
+    }
+
+}

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/ServiceLifecycle.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/ServiceLifecycle.java?rev=426656&r1=426655&r2=426656&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/ServiceLifecycle.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/ServiceLifecycle.java Fri Jul 28 12:56:00 2006
@@ -22,7 +22,11 @@
 public interface ServiceLifecycle
 {
     /**
-     * Returns the same creator, or a new one, that encapsulates the
+     * Returns the same creator, or a new one, that encapsulates the creation of the core service
+     * implementation.
+     * <p>
+     * TODO: Still deciding if ServiceResources needs to be passed in, or just the raw
+     * ServiceCreator
      * 
      * @param resources
      *            source of information about the service to be created, and source of additional
@@ -42,6 +46,9 @@
      * When this is false, the {@link #createService(ServiceResources, ServiceCreator)} will be
      * invoked when the service is first referenced, and is responsible for returning an appropriate
      * service or proxy.
+     * <p>
+     * TODO: Not sure if there's a service type outside of "primitive" that would ever return false,
+     * so this method may go away.
      */
     boolean getCreateProxy();
 }

Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/services/ServiceLifecycleSource.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/services/ServiceLifecycleSource.java?rev=426656&view=auto
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/services/ServiceLifecycleSource.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/services/ServiceLifecycleSource.java Fri Jul 28 12:56:00 2006
@@ -0,0 +1,20 @@
+package org.apache.tapestry.ioc.services;
+
+import org.apache.tapestry.ioc.ServiceLifecycle;
+
+/**
+ * Provides access to user defined lifecycles (beyond the two built-in lifecycles: "singleton" and
+ * "primitive"). The user defined lifecycles are contributed into the service's configuration.
+ * 
+ * @author Howard M. Lewis Ship
+ */
+public interface ServiceLifecycleSource
+{
+    /**
+     * Used to locate a configuration lifecycle, by name.
+     * 
+     * @param lifecycleName
+     * @return the named lifecycle, or null if the name is not found
+     */
+    ServiceLifecycle get(String lifecycleName);
+}

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/services/TapestryIOCModule.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/services/TapestryIOCModule.java?rev=426656&r1=426655&r2=426656&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/services/TapestryIOCModule.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/services/TapestryIOCModule.java Fri Jul 28 12:56:00 2006
@@ -14,13 +14,17 @@
 
 package org.apache.tapestry.ioc.services;
 
+import java.util.Map;
+
 import org.apache.commons.logging.Log;
 import org.apache.tapestry.internal.ioc.services.ClassFactoryImpl;
 import org.apache.tapestry.internal.ioc.services.LoggingDecoratorImpl;
 import org.apache.tapestry.internal.ioc.services.ThreadCleanupHubImpl;
+import org.apache.tapestry.ioc.ServiceLifecycle;
 import org.apache.tapestry.ioc.annotations.Id;
 import org.apache.tapestry.ioc.annotations.InjectService;
 import org.apache.tapestry.ioc.annotations.Lifecycle;
+import org.apache.tapestry.ioc.annotations.Private;
 
 /**
  * Defines the base set of services for the Tapestry IOC container.
@@ -56,5 +60,23 @@
     ClassFactory classFactory)
     {
         return new LoggingDecoratorImpl(classFactory);
+    }
+
+    /**
+     * Provides access to additional service lifecycles. Two lifecycles are builtin ("singleton" and
+     * "primitive") but additional ones are accessed via this service (and its mapped
+     * configuration).
+     */
+    public ServiceLifecycleSource buildServiceLifecycleSource(
+            final Map<String, ServiceLifecycle> configuration)
+    {
+        return new ServiceLifecycleSource()
+        {
+            public ServiceLifecycle get(String lifecycleName)
+            {
+                return configuration.get(lifecycleName);
+            }
+
+        };
     }
 }

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=426656&r1=426655&r2=426656&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 Fri Jul 28 12:56:00 2006
@@ -66,4 +66,5 @@
 contribution-duplicate-key=Service contribution (to service ''{0}'', by {1}) conflicts with \
   existing contribution (by {2}) and has been ignored.
 generic-type-not-supported=Generic type ''{0}'' is not supported. Only simple parameterized lists are \
-  supported.
\ No newline at end of file
+  supported.
+error-building-service=Error building service proxy for service ''{0}'' (at {1}): {2}
\ No newline at end of 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=426656&r1=426655&r2=426656&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 Fri Jul 28 12:56:00 2006
@@ -36,8 +36,13 @@
 {
     private Registry buildRegistry()
     {
+        return buildRegistry(TapestryIOCModule.class, FredModule.class, BarneyModule.class);
+    }
+
+    private Registry buildRegistry(Class... moduleClasses)
+    {
         RegistryBuilder builder = new RegistryBuilder();
-        builder.add(TapestryIOCModule.class, FredModule.class, BarneyModule.class);
+        builder.add(moduleClasses);
 
         return builder.build();
     }
@@ -161,5 +166,25 @@
         List<String> names = service.getNames();
 
         assertEquals(names, Arrays.asList("Omega", "PrivateUnorderedNames"));
+    }
+
+    @Test
+    public void unknown_lifecycle()
+    {
+        Registry r = buildRegistry(TapestryIOCModule.class, UnknownLifecycleModule.class);
+
+        try
+        {
+            r.getService("ioc.test.UnknownLifecycle", Runnable.class);
+            unreachable();
+        }
+        catch (Exception ex)
+        {
+            assertEquals(
+                    ex.getMessage(),
+                    "Error building service proxy for service 'ioc.test.UnknownLifecycle' "
+                            + "(at org.apache.tapestry.ioc.UnknownLifecycleModule.buildUnknownLifecycle()): "
+                            + "Unknown service lifecycle 'magic'.");
+        }
     }
 }

Added: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/ioc/UnknownLifecycleModule.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/ioc/UnknownLifecycleModule.java?rev=426656&view=auto
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/ioc/UnknownLifecycleModule.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/ioc/UnknownLifecycleModule.java Fri Jul 28 12:56:00 2006
@@ -0,0 +1,17 @@
+package org.apache.tapestry.ioc;
+
+import org.apache.tapestry.ioc.annotations.Id;
+import org.apache.tapestry.ioc.annotations.Lifecycle;
+
+/**
+ * @author Howard M. Lewis Ship
+ */
+@Id("ioc.test")
+public class UnknownLifecycleModule
+{
+    @Lifecycle("magic")
+    public Runnable buildUnknownLifecycle()
+    {
+        return null;
+    }
+}