You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tapestry.apache.org by hl...@apache.org on 2006/08/12 20:24:19 UTC

svn commit: r431064 [2/2] - 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/internal/pageload/...

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=431064&r1=431063&r2=431064&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 Sat Aug 12 11:24:17 2006
@@ -68,6 +68,11 @@
   If we used fully qualified service ids, such as "org.examples.myapps.jobs.JobScheduler",
   then we can access services from some other module entirely.
   
+  If you find yourself injecting the same dependencies into multiple service builder 
+  (or service decorator) methods, you can 
+  {{{module.html#Caching Services}cache dependency injections}} in your module, by defining
+  a constructor.  This reduces duplication in your module.
+  
 Injecting Dependencies with @Inject
 
   A second approach to injection uses the more general purpose
@@ -143,20 +148,14 @@
   to those services.  Because the dispatch occurs <inside> the proxy, you can treat the service
   as a global, like any other.
   
-  You will see that your service builder method is invoked more than once.
+  You will see that your service builder method is invoked more than once.  It is invoked in each
+  thread where the perthread service is used.
   
   At the end of the request, the  Registry's cleanupThread() method is invoked; it will discard
-  any perthread service implementations for the current thread.  Generally, this is integrated
-  into the main service loop of the web application's servlet.
-  
-  Similar techniques can be used whenever multiple threads are in use, such as processing of
-  messages from a JMS (Java Messaging System) queue, or when using any sort of thread pool.
-  The important thing is to invoke the cleanupThread() method, to discard any request/thread
-  specific information, before processing the next request, message, transaction, or
-  what have you.  
+  any perthread service implementations for the current thread.
   
   <<Caution:>> A common technique in Tapestry IoC is to have a service builder method
-  registry a core service implementation as an event listener with some event hub service.
+  register a core service implementation as an event listener with some event hub service.
   With non-singleton objects, this can cause a number of problems; the event hub will
   hold a reference to the per-thread instance, even after that per-thread instance has been
   cleaned up (discarded by the inner proxy). Simply put, this is a pattern to avoid. For
@@ -254,13 +253,15 @@
 *-------------------------------+-----------------------------------------------------------------------------------------+
 | 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}} |
 *-------------------------------+-----------------------------------------------------------------------------------------+
 
   
 Mutually Dependant Services
 
-  One of the benefits of Tapestry IoC's proxy-based approach to just-in-time instantitation 
+  One of the benefits of Tapestry IoC's proxy-based approach to just-in-time instantiation 
   is the automatic support for mutually dependent services.  For example, suppose that
   the Indexer and the FileSystem needed to talk directly to each other.  Normally, this
   would cause a "chicken-and-the-egg" problem: which one to create first?

Added: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/ExtraPublicConstructorsModule.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/ExtraPublicConstructorsModule.java?rev=431064&view=auto
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/ExtraPublicConstructorsModule.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/ExtraPublicConstructorsModule.java Sat Aug 12 11:24:17 2006
@@ -0,0 +1,45 @@
+// 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;
+
+import org.apache.tapestry.ioc.annotations.Id;
+import org.apache.tapestry.ioc.annotations.InjectService;
+import org.apache.tapestry.ioc.services.ClassFactory;
+
+/**
+ * Used by {@link org.apache.tapestry.internal.ioc.ModuleImplTest}.
+ * 
+ * @author Howard M. Lewis Ship
+ */
+@Id("extra.public")
+public class ExtraPublicConstructorsModule
+{
+
+    public ExtraPublicConstructorsModule()
+    {
+
+    }
+
+    /**
+     * Should be the first constructor, the one that gets invoked. I'm worried that different
+     * compilers or JVMs will order the constructors differently.
+     */
+
+    public ExtraPublicConstructorsModule(@InjectService("tapestry.ioc.ClassFactory")
+    ClassFactory factory)
+    {
+
+    }
+}

Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/InterceptorStackBuilderTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/InterceptorStackBuilderTest.java?rev=431064&r1=431063&r2=431064&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/InterceptorStackBuilderTest.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/InterceptorStackBuilderTest.java Sat Aug 12 11:24:17 2006
@@ -18,7 +18,7 @@
 
 import org.apache.tapestry.internal.annotations.SuppressNullCheck;
 import org.apache.tapestry.internal.test.InternalBaseTestCase;
-import org.apache.tapestry.ioc.ServiceCreator;
+import org.apache.tapestry.ioc.ObjectCreator;
 import org.apache.tapestry.ioc.ServiceDecorator;
 import org.testng.annotations.Test;
 
@@ -36,7 +36,7 @@
     @Test
     public void no_decorators()
     {
-        ServiceCreator core = newServiceCreator();
+        ObjectCreator core = newServiceCreator();
         Module module = newModule();
         Object coreObject = new Object();
         List<ServiceDecorator> decorators = newList();
@@ -47,9 +47,9 @@
 
         replay();
 
-        ServiceCreator isb = new InterceptorStackBuilder(module, SERVICE_ID, core);
+        ObjectCreator isb = new InterceptorStackBuilder(module, SERVICE_ID, core);
 
-        Object intercepted = isb.createService();
+        Object intercepted = isb.createObject();
 
         assertSame(intercepted, coreObject);
 
@@ -59,7 +59,7 @@
     @Test
     public void decorator_returns_null_interceptor()
     {
-        ServiceCreator core = newServiceCreator();
+        ObjectCreator core = newServiceCreator();
         Module module = newModule();
         Object coreObject = new Object();
         ServiceDecorator decorator = newServiceDecorator();
@@ -74,9 +74,9 @@
 
         replay();
 
-        ServiceCreator isb = new InterceptorStackBuilder(module, SERVICE_ID, core);
+        ObjectCreator isb = new InterceptorStackBuilder(module, SERVICE_ID, core);
 
-        Object intercepted = isb.createService();
+        Object intercepted = isb.createObject();
 
         assertSame(intercepted, coreObject);
 
@@ -86,7 +86,7 @@
     @Test
     public void decorator_orderering()
     {
-        ServiceCreator core = newServiceCreator();
+        ObjectCreator core = newServiceCreator();
         Module module = newModule();
         Object coreObject = new Object();
         Object interceptor1 = new Object();
@@ -107,9 +107,9 @@
 
         replay();
 
-        ServiceCreator isb = new InterceptorStackBuilder(module, SERVICE_ID, core);
+        ObjectCreator isb = new InterceptorStackBuilder(module, SERVICE_ID, core);
 
-        Object intercepted = isb.createService();
+        Object intercepted = isb.createObject();
 
         assertSame(intercepted, interceptor1);
 

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=431064&r1=431063&r2=431064&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 Sat Aug 12 11:24:17 2006
@@ -29,6 +29,8 @@
 import org.apache.tapestry.ioc.services.ClassFactory;
 import org.testng.annotations.Test;
 
+import static org.easymock.EasyMock.contains;
+
 /**
  * @author Howard M. Lewis Ship
  */
@@ -43,7 +45,7 @@
 
         ModuleDef moduleDef = new DefaultModuleDefImpl(ModuleImplTestModule.class, log);
 
-        Module module = new ModuleImpl(registry, moduleDef);
+        Module module = new ModuleImpl(registry, moduleDef, log);
 
         trainGetLog(registry, "ioc.test.Upcase", log);
 
@@ -83,7 +85,7 @@
 
         ModuleDef moduleDef = new DefaultModuleDefImpl(ModuleImplTestModule.class, log);
 
-        Module module = new ModuleImpl(registry, moduleDef);
+        Module module = new ModuleImpl(registry, moduleDef, log);
 
         trainGetLog(registry, "ioc.test.PrivateUpcase", log);
 
@@ -117,7 +119,7 @@
 
         ModuleDef moduleDef = new DefaultModuleDefImpl(ModuleImplTestModule.class, log);
 
-        Module module = new ModuleImpl(registry, moduleDef);
+        Module module = new ModuleImpl(registry, moduleDef, log);
 
         replay();
 
@@ -144,7 +146,7 @@
 
         ModuleDef moduleDef = new DefaultModuleDefImpl(ModuleImplTestModule.class, log);
 
-        Module module = new ModuleImpl(registry, moduleDef);
+        Module module = new ModuleImpl(registry, moduleDef, log);
 
         replay();
 
@@ -170,6 +172,7 @@
         DecoratorDef def1 = newDecoratorDef();
         DecoratorDef def2 = newDecoratorDef();
         Set<DecoratorDef> rawDefs = newMock(Set.class);
+        Log log = newLog();
 
         ModuleDef moduleDef = newModuleDef();
 
@@ -184,7 +187,7 @@
 
         replay();
 
-        Module module = new ModuleImpl(registry, moduleDef);
+        Module module = new ModuleImpl(registry, moduleDef, log);
 
         Set<DecoratorDef> defs = module.findMatchingDecoratorDefs(serviceDef);
 
@@ -198,15 +201,64 @@
     public void get_module_id()
     {
         InternalRegistry registry = newInternalRegistry();
+        Log log = newLog();
         ModuleDef def = newModuleDef();
 
         trainGetModuleId(def, "foo.bar");
 
         replay();
 
-        Module module = new ModuleImpl(registry, def);
+        Module module = new ModuleImpl(registry, def, log);
 
         assertEquals(module.getModuleId(), "foo.bar");
+
+        verify();
+    }
+
+    @Test
+    public void no_public_constructor_on_module_builder_class()
+    {
+        InternalRegistry registry = newInternalRegistry();
+        Log log = newLog();
+        ModuleDef def = new DefaultModuleDefImpl(PrivateConstructorModule.class, log);
+
+        replay();
+
+        Module module = new ModuleImpl(registry, def, log);
+
+        try
+        {
+            module.getModuleBuilder();
+            unreachable();
+        }
+        catch (RuntimeException ex)
+        {
+            assertEquals(
+                    ex.getMessage(),
+                    "Module builder for module 'private' (class org.apache.tapestry.internal.ioc.PrivateConstructorModule) "
+                            + "does not contain any public constructors.");
+        }
+
+        verify();
+
+    }
+
+    @Test
+    public void too_many_public_constructors_on_module_builder_class()
+    {
+        InternalRegistry registry = newInternalRegistry();
+        Log log = newLog();
+        ModuleDef def = new DefaultModuleDefImpl(ExtraPublicConstructorsModule.class, log);
+        ClassFactory factory = newMock(ClassFactory.class);
+        Module module = new ModuleImpl(registry, def, log);
+
+        log.warn(contains("contains more than one public constructor"));
+
+        trainGetService(registry, "tapestry.ioc.ClassFactory", ClassFactory.class, module, factory);
+
+        replay();
+
+        assertTrue(module.getModuleBuilder() instanceof ExtraPublicConstructorsModule);
 
         verify();
     }

Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/OneShortServiceCreatorTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/OneShortServiceCreatorTest.java?rev=431064&r1=431063&r2=431064&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/OneShortServiceCreatorTest.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/OneShortServiceCreatorTest.java Sat Aug 12 11:24:17 2006
@@ -17,7 +17,7 @@
 import java.lang.reflect.Method;
 
 import org.apache.tapestry.internal.test.InternalBaseTestCase;
-import org.apache.tapestry.ioc.ServiceCreator;
+import org.apache.tapestry.ioc.ObjectCreator;
 import org.apache.tapestry.ioc.def.ServiceDef;
 import org.testng.annotations.Test;
 
@@ -31,7 +31,7 @@
     {
         Method method = getClass().getMethod("buildMyService");
 
-        ServiceCreator delegate = newServiceCreator();
+        ObjectCreator delegate = newServiceCreator();
         Object service = new Object();
 
         ServiceDef def = new ServiceDefImpl("foo.Bar", "singleton", method, false);
@@ -40,13 +40,13 @@
 
         replay();
 
-        ServiceCreator oneShot = new OneShotServiceCreator(def, delegate);
+        ObjectCreator oneShot = new OneShotServiceCreator(def, delegate);
 
-        assertSame(oneShot.createService(), service);
+        assertSame(oneShot.createObject(), service);
 
         try
         {
-            oneShot.createService();
+            oneShot.createObject();
             unreachable();
         }
         catch (IllegalStateException ex)

Added: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/PrivateConstructorModule.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/PrivateConstructorModule.java?rev=431064&view=auto
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/PrivateConstructorModule.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/PrivateConstructorModule.java Sat Aug 12 11:24:17 2006
@@ -0,0 +1,30 @@
+// 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;
+
+import org.apache.tapestry.ioc.annotations.Id;
+
+/**
+ * Used by {@link org.apache.tapestry.internal.ioc.ModuleImplTest}.
+ * 
+ * @author Howard M. Lewis Ship
+ */
+@Id("private")
+public class PrivateConstructorModule
+{
+    private PrivateConstructorModule()
+    {
+    }
+}

Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/ServiceBuilderMethodInvokerTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/ServiceBuilderMethodInvokerTest.java?rev=431064&r1=431063&r2=431064&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/ServiceBuilderMethodInvokerTest.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/ServiceBuilderMethodInvokerTest.java Sat Aug 12 11:24:17 2006
@@ -22,8 +22,8 @@
 
 import org.apache.commons.logging.Log;
 import org.apache.tapestry.internal.test.InternalBaseTestCase;
-import org.apache.tapestry.ioc.ServiceCreator;
-import org.apache.tapestry.ioc.ServiceCreatorResources;
+import org.apache.tapestry.ioc.ObjectCreator;
+import org.apache.tapestry.ioc.ServiceBuilderResources;
 import org.apache.tapestry.ioc.ServiceResources;
 import org.apache.tapestry.ioc.annotations.InjectService;
 import org.testng.Assert;
@@ -55,27 +55,28 @@
     @Test
     public void noargs_method()
     {
-        ServiceCreatorResources resources = newServiceCreatorResources();
+        ServiceBuilderResources resources = newServiceCreatorResources();
         Log log = newLog();
         _fie = newFieService();
 
         trainForConstructor(resources, log);
 
+        trainGetModuleBuilder(resources, this);
+
         trainIsDebugEnabled(log, false);
 
         replay();
 
-        ServiceCreator sc = new ServiceBuilderMethodInvoker(findMethod("build_noargs"), this,
-                resources);
+        ObjectCreator sc = new ServiceBuilderMethodInvoker(findMethod("build_noargs"), resources);
 
-        Object actual = sc.createService();
+        Object actual = sc.createObject();
 
         assertSame(actual, _fie);
 
         verify();
     }
 
-    private void trainForConstructor(ServiceCreatorResources resources, Log log)
+    private void trainForConstructor(ServiceBuilderResources resources, Log log)
     {
         trainGetServiceId(resources, SERVICE_ID);
 
@@ -88,7 +89,7 @@
     public void method_with_args()
     {
         Method method = findMethod("build_args");
-        ServiceCreatorResources resources = newServiceCreatorResources();
+        ServiceBuilderResources resources = newServiceCreatorResources();
 
         Log log = newLog();
 
@@ -101,15 +102,17 @@
 
         trainForConstructor(resources, log);
 
+        trainGetModuleBuilder(resources, this);
+
         trainIsDebugEnabled(log, true);
 
         log.debug(IOCMessages.invokingMethod(method));
 
         replay();
 
-        ServiceCreator sc = new ServiceBuilderMethodInvoker(method, this, resources);
+        ObjectCreator sc = new ServiceBuilderMethodInvoker(method, resources);
 
-        Object actual = sc.createService();
+        Object actual = sc.createObject();
 
         assertSame(actual, _fie);
 
@@ -119,7 +122,7 @@
     @Test
     public void injected_service_method()
     {
-        ServiceCreatorResources resources = newServiceCreatorResources();
+        ServiceBuilderResources resources = newServiceCreatorResources();
         Log log = newLog();
 
         _fie = newFieService();
@@ -127,16 +130,17 @@
 
         trainForConstructor(resources, log);
 
+        trainGetModuleBuilder(resources, this);
+
         trainIsDebugEnabled(log, false);
 
         trainGetService(resources, "Foe", FoeService.class, _expectedFoe);
 
         replay();
 
-        ServiceCreator sc = new ServiceBuilderMethodInvoker(findMethod("build_injected"), this,
-                resources);
+        ObjectCreator sc = new ServiceBuilderMethodInvoker(findMethod("build_injected"), resources);
 
-        Object actual = sc.createService();
+        Object actual = sc.createObject();
 
         assertSame(actual, _fie);
 
@@ -146,7 +150,7 @@
     @Test
     public void injected_ordered_collection()
     {
-        ServiceCreatorResources resources = newServiceCreatorResources();
+        ServiceBuilderResources resources = newServiceCreatorResources();
         Log log = newLog();
 
         _fie = newFieService();
@@ -154,6 +158,8 @@
 
         trainForConstructor(resources, log);
 
+        trainGetModuleBuilder(resources, this);
+
         trainIsDebugEnabled(log, false);
 
         resources.getOrderedConfiguration(Runnable.class);
@@ -161,10 +167,10 @@
 
         replay();
 
-        ServiceCreator sc = new ServiceBuilderMethodInvoker(
-                findMethod("buildWithOrderedConfiguration"), this, resources);
+        ObjectCreator sc = new ServiceBuilderMethodInvoker(
+                findMethod("buildWithOrderedConfiguration"), resources);
 
-        Object actual = sc.createService();
+        Object actual = sc.createObject();
 
         assertSame(actual, _fie);
 
@@ -175,7 +181,7 @@
     @Test
     public void injected_unordered_collection()
     {
-        ServiceCreatorResources resources = newServiceCreatorResources();
+        ServiceBuilderResources resources = newServiceCreatorResources();
         Log log = newLog();
 
         _fie = newFieService();
@@ -183,6 +189,8 @@
 
         trainForConstructor(resources, log);
 
+        trainGetModuleBuilder(resources, this);
+
         trainIsDebugEnabled(log, false);
 
         resources.getUnorderedConfiguration(Runnable.class);
@@ -190,10 +198,10 @@
 
         replay();
 
-        ServiceCreator sc = new ServiceBuilderMethodInvoker(
-                findMethod("buildWithUnorderedConfiguration"), this, resources);
+        ObjectCreator sc = new ServiceBuilderMethodInvoker(
+                findMethod("buildWithUnorderedConfiguration"), resources);
 
-        Object actual = sc.createService();
+        Object actual = sc.createObject();
 
         assertSame(actual, _fie);
 
@@ -222,23 +230,24 @@
     @Test
     public void builder_method_returns_null()
     {
-        ServiceCreatorResources resources = newServiceCreatorResources();
+        ServiceBuilderResources resources = newServiceCreatorResources();
         Log log = newLog();
 
         _fie = null;
 
         trainForConstructor(resources, log);
 
+        trainGetModuleBuilder(resources, this);
+
         trainIsDebugEnabled(log, false);
 
         replay();
 
-        ServiceCreator sc = new ServiceBuilderMethodInvoker(findMethod("build_noargs"), this,
-                resources);
+        ObjectCreator sc = new ServiceBuilderMethodInvoker(findMethod("build_noargs"), resources);
 
         try
         {
-            sc.createService();
+            sc.createObject();
             unreachable();
         }
         catch (RuntimeException ex)
@@ -253,23 +262,24 @@
     @Test
     public void builder_method_failed()
     {
-        ServiceCreatorResources resources = newServiceCreatorResources();
+        ServiceBuilderResources resources = newServiceCreatorResources();
         Log log = newLog();
 
         _fie = null;
 
         trainForConstructor(resources, log);
 
+        trainGetModuleBuilder(resources, this);
+
         trainIsDebugEnabled(log, false);
 
         replay();
 
-        ServiceCreator sc = new ServiceBuilderMethodInvoker(findMethod("build_fail"), this,
-                resources);
+        ObjectCreator sc = new ServiceBuilderMethodInvoker(findMethod("build_fail"), resources);
 
         try
         {
-            sc.createService();
+            sc.createObject();
             unreachable();
         }
         catch (RuntimeException ex)
@@ -291,7 +301,7 @@
     {
         Method method = findMethod("build_auto");
 
-        ServiceCreatorResources resources = newServiceCreatorResources();
+        ServiceBuilderResources resources = newServiceCreatorResources();
         Log log = newLog();
 
         _fie = newFieService();
@@ -299,19 +309,28 @@
 
         trainForConstructor(resources, log);
 
+        trainGetModuleBuilder(resources, this);
+
         trainIsDebugEnabled(log, false);
 
         trainGetService(resources, FoeService.class, _expectedFoe);
 
         replay();
 
-        ServiceCreator sc = new ServiceBuilderMethodInvoker(method, this, resources);
+        ObjectCreator sc = new ServiceBuilderMethodInvoker(method, resources);
 
-        Object actual = sc.createService();
+        Object actual = sc.createObject();
 
         verify();
 
         assertSame(actual, _fie);
+    }
+
+    protected final void trainGetModuleBuilder(ServiceBuilderResources resources,
+            Object moduleBuilder)
+    {
+        resources.getModuleBuilder();
+        setReturnValue(moduleBuilder);
     }
 
     @Test

Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/SingletonServiceLifecycleTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/SingletonServiceLifecycleTest.java?rev=431064&r1=431063&r2=431064&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/SingletonServiceLifecycleTest.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/SingletonServiceLifecycleTest.java Sat Aug 12 11:24:17 2006
@@ -15,7 +15,7 @@
 package org.apache.tapestry.internal.ioc;
 
 import org.apache.tapestry.internal.test.InternalBaseTestCase;
-import org.apache.tapestry.ioc.ServiceCreator;
+import org.apache.tapestry.ioc.ObjectCreator;
 import org.apache.tapestry.ioc.ServiceLifecycle;
 import org.apache.tapestry.ioc.ServiceResources;
 import org.testng.annotations.Test;
@@ -29,7 +29,7 @@
     public void test()
     {
         ServiceResources resources = newServiceResources();
-        ServiceCreator creator = newServiceCreator();
+        ObjectCreator creator = newServiceCreator();
         Object expected = new Object();
 
         trainCreateService(creator, expected);

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=431064&r1=431063&r2=431064&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 Sat Aug 12 11:24:17 2006
@@ -181,12 +181,18 @@
     @Test
     public void simple_perthread() throws Exception
     {
-        Registry r = buildRegistry(PerThreadModule.class);
+        final Registry r = buildRegistry(PerThreadModule.class);
 
         final StringHolder holder = r.getService(StringHolder.class);
 
+        // Something about some of the other tests causes this one to fail
+        // unless we start with cleanupThread(), there must be a loose ThreadLocal
+        // hanging around causing problems.
+
+        r.cleanupThread();
+
         holder.setValue("fred");
-        assertEquals(holder.getValue(), "fred");
+        assertEquals(holder.getValue(), "fred", holder.toString());
 
         Runnable runnable = new Runnable()
         {
@@ -196,6 +202,8 @@
 
                 holder.setValue("barney");
                 assertEquals(holder.getValue(), "barney");
+
+                r.cleanupThread();
             }
         };
 
@@ -205,6 +213,8 @@
         t.join();
 
         assertEquals(holder.getValue(), "fred");
+
+        r.cleanupThread();
     }
 
     @Test
@@ -237,5 +247,28 @@
         // an @Inject.
 
         assertEquals(st.transform("fred"), "FRED");
+    }
+
+    @Test
+    public void recursive_module_construction_is_caught()
+    {
+        Registry r = buildRegistry(RecursiveConstructorModule.class);
+
+        try
+        {
+            Runnable runnable = r.getService("recursive.Runnable", Runnable.class);
+
+            // We can get the proxy, but invoking a method causes
+            // the module to be instantiated ... but that also invokes a method on
+            // the proxy.
+
+            runnable.run();
+
+            unreachable();
+        }
+        catch (RuntimeException ex)
+        {
+            assertTrue(ex.getMessage().contains("has failed due to recursion"));
+        }
     }
 }

Added: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/ioc/RecursiveConstructorModule.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/ioc/RecursiveConstructorModule.java?rev=431064&view=auto
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/ioc/RecursiveConstructorModule.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/ioc/RecursiveConstructorModule.java Sat Aug 12 11:24:17 2006
@@ -0,0 +1,47 @@
+// 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;
+
+import org.apache.tapestry.ioc.annotations.Id;
+import org.apache.tapestry.ioc.annotations.InjectService;
+
+/**
+ * Used by {@link org.apache.tapestry.ioc.IntegrationTest}.
+ * 
+ * @author Howard M. Lewis Ship
+ */
+@Id("recursive")
+public class RecursiveConstructorModule
+{
+
+    public RecursiveConstructorModule(@InjectService("Runnable")
+    Runnable r)
+    {
+        // Invoking a method on the service proxy is going to cause a recursive attempt to
+        // instantiate the module. Hilarity ensues.
+
+        r.run();
+    }
+
+    public Runnable buildRunnable()
+    {
+        return new Runnable()
+        {
+            public void run()
+            {
+            }
+        };
+    }
+}