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 2007/10/28 00:29:32 UTC

svn commit: r589228 - in /tapestry/tapestry5/trunk: tapestry-core/src/main/java/org/apache/tapestry/internal/test/ tapestry-ioc/src/main/java/org/apache/tapestry/ioc/ tapestry-ioc/src/main/java/org/apache/tapestry/ioc/internal/ tapestry-ioc/src/main/ja...

Author: hlship
Date: Sat Oct 27 15:29:27 2007
New Revision: 589228

URL: http://svn.apache.org/viewvc?rev=589228&view=rev
Log:
TAPESTRY-1860: Extend ObjectLocator to create a proxied, autobuilt service

Added:
    tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry/ioc/CountingGreeterImpl.java
Modified:
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/test/InternalBaseTestCase.java
    tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry/ioc/ObjectLocator.java
    tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry/ioc/internal/IOCInternalTestCase.java
    tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry/ioc/internal/ModuleImpl.java
    tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry/ioc/internal/ObjectLocatorImpl.java
    tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry/ioc/internal/RegistryImpl.java
    tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry/ioc/internal/RegistryWrapper.java
    tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry/ioc/services/ClassFabUtils.java
    tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry/ioc/IntegrationTest.java

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/test/InternalBaseTestCase.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/test/InternalBaseTestCase.java?rev=589228&r1=589227&r2=589228&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/test/InternalBaseTestCase.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/test/InternalBaseTestCase.java Sat Oct 27 15:29:27 2007
@@ -156,6 +156,11 @@
         return _registry.autobuild(clazz);
     }
 
+    public <T> T proxy(Class<T> interfaceClass, Class<? extends T> implementationClass)
+    {
+        return _registry.proxy(interfaceClass, implementationClass);
+    }
+
     public final void shutdown()
     {
         throw new UnsupportedOperationException("No registry shutdown until @AfterSuite.");

Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry/ioc/ObjectLocator.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry/ioc/ObjectLocator.java?rev=589228&r1=589227&r2=589228&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry/ioc/ObjectLocator.java (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry/ioc/ObjectLocator.java Sat Oct 27 15:29:27 2007
@@ -14,6 +14,8 @@
 
 package org.apache.tapestry.ioc;
 
+import org.apache.tapestry.services.MasterObjectProvider;
+
 /**
  * Defines an object which can provide access to services defined within a
  * {@link org.apache.tapestry.ioc.Registry}, or to objects or object instances available by other
@@ -87,4 +89,20 @@
      *             if the autobuild fails
      */
     <T> T autobuild(Class<T> clazz);
+
+    /**
+     * Creates a proxy. The proxy will defer invocation of {@link #autobuild(Class)} until
+     * just-in-time (that is, first method invocation). In a limited number of cases, it is
+     * necessary to use such a proxy to prevent service construction cycles, particularily when
+     * contributing (directly or indirectly) to the {@link MasterObjectProvider} (which is itself at
+     * the heart of autobuilding).
+     * 
+     * @param <T>
+     * @param interfaceClass
+     *            the interface implemented by the proxy
+     * @param implementationClass
+     *            a concrete class that implements the interface
+     * @return a proxy
+     */
+    <T> T proxy(Class<T> interfaceClass, Class<? extends T> implementationClass);
 }

Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry/ioc/internal/IOCInternalTestCase.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry/ioc/internal/IOCInternalTestCase.java?rev=589228&r1=589227&r2=589228&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry/ioc/internal/IOCInternalTestCase.java (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry/ioc/internal/IOCInternalTestCase.java Sat Oct 27 15:29:27 2007
@@ -73,6 +73,12 @@
         _registry.performRegistryStartup();
     }
 
+    public <T> T proxy(Class<T> interfaceClass, Class<? extends T> implementationClass)
+    {
+        return _registry.proxy(interfaceClass, implementationClass);
+    }
+
+    
     @BeforeSuite
     public final void setup_registry()
     {

Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry/ioc/internal/ModuleImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry/ioc/internal/ModuleImpl.java?rev=589228&r1=589227&r2=589228&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry/ioc/internal/ModuleImpl.java (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry/ioc/internal/ModuleImpl.java Sat Oct 27 15:29:27 2007
@@ -24,7 +24,6 @@
 
 import java.lang.reflect.Constructor;
 import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Modifier;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Comparator;
@@ -44,8 +43,8 @@
 import org.apache.tapestry.ioc.internal.services.JustInTimeObjectCreator;
 import org.apache.tapestry.ioc.internal.util.InternalUtils;
 import org.apache.tapestry.ioc.services.ClassFab;
+import org.apache.tapestry.ioc.services.ClassFabUtils;
 import org.apache.tapestry.ioc.services.ClassFactory;
-import org.apache.tapestry.ioc.services.MethodSignature;
 import org.apache.tapestry.ioc.services.Status;
 import org.apache.tapestry.ioc.services.TapestryIOCModule;
 import org.slf4j.Logger;
@@ -366,43 +365,9 @@
     private Object createProxyInstance(ObjectCreator creator, String serviceId,
             Class serviceInterface, String description)
     {
-        Class proxyClass = createProxyClass(serviceId, serviceInterface, description);
-
-        try
-        {
-            return proxyClass.getConstructors()[0].newInstance(creator);
-        }
-        catch (Exception ex)
-        {
-            // This should never happen, so we won't go to a lot of trouble
-            // reporting it.
-            throw new RuntimeException(ex.getMessage(), ex);
-        }
-    }
-
-    private Class createProxyClass(String serviceId, Class serviceInterface, String proxyDescription)
-    {
         ClassFab cf = _registry.newClass(serviceInterface);
 
-        cf.addField("_creator", Modifier.PRIVATE | Modifier.FINAL, ObjectCreator.class);
-
-        cf.addConstructor(new Class[]
-        { ObjectCreator.class }, null, "_creator = $1;");
-
-        addDelegateGetter(cf, serviceInterface, serviceId);
-
-        cf.proxyMethodsToDelegate(serviceInterface, "_delegate()", proxyDescription);
-
-        return cf.createClass();
-    }
-
-    private void addDelegateGetter(ClassFab cf, Class serviceInterface, String serviceId)
-    {
-        String body = format("return (%s) _creator.createObject();", serviceInterface.getName());
-
-        MethodSignature sig = new MethodSignature(serviceInterface, "_delegate", null, null);
-
-        cf.addMethod(Modifier.PRIVATE, sig, body);
+        return ClassFabUtils.createObjectCreatorProxy(cf, serviceInterface, creator, description);
     }
 
     public Set<ContributionDef> getContributorDefsForService(String serviceId)

Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry/ioc/internal/ObjectLocatorImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry/ioc/internal/ObjectLocatorImpl.java?rev=589228&r1=589227&r2=589228&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry/ioc/internal/ObjectLocatorImpl.java (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry/ioc/internal/ObjectLocatorImpl.java Sat Oct 27 15:29:27 2007
@@ -65,4 +65,9 @@
         return _registry.autobuild(clazz);
     }
 
+    public <T> T proxy(Class<T> interfaceClass, Class<? extends T> implementationClass)
+    {
+        return _registry.proxy(interfaceClass, implementationClass);
+    }
+
 }

Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry/ioc/internal/RegistryImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry/ioc/internal/RegistryImpl.java?rev=589228&r1=589227&r2=589228&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry/ioc/internal/RegistryImpl.java (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry/ioc/internal/RegistryImpl.java Sat Oct 27 15:29:27 2007
@@ -51,11 +51,12 @@
 import org.apache.tapestry.ioc.internal.util.OneShotLock;
 import org.apache.tapestry.ioc.internal.util.Orderer;
 import org.apache.tapestry.ioc.services.ClassFab;
+import org.apache.tapestry.ioc.services.ClassFabUtils;
 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.ServiceActivityScoreboard;
+import org.apache.tapestry.ioc.services.ServiceLifecycleSource;
 import org.apache.tapestry.ioc.services.Status;
 import org.apache.tapestry.ioc.services.SymbolSource;
 import org.apache.tapestry.ioc.services.TapestryIOCModule;
@@ -788,4 +789,39 @@
                 failure);
     }
 
+    public <T> T proxy(Class<T> interfaceClass, final Class<? extends T> implementationClass)
+    {
+        notNull(interfaceClass, "interfaceClass");
+        notNull(implementationClass, "implementationClass");
+
+        // TODO: Check really an interface
+        // TODO: Check impl class extends interfaceClass and is concrete
+
+        final ObjectCreator autobuildCreator = new ObjectCreator()
+        {
+            public Object createObject()
+            {
+                return autobuild(implementationClass);
+            }
+        };
+
+        ObjectCreator justInTime = new ObjectCreator()
+        {
+            private Object _delegate;
+
+            public synchronized Object createObject()
+            {
+                if (_delegate == null) _delegate = autobuildCreator.createObject();
+
+                return _delegate;
+            }
+        };
+
+        ClassFab cf = _classFactory.newClass(interfaceClass);
+
+        String description = String.format("<Autobuild proxy %s(%s)>", implementationClass
+                .getName(), interfaceClass.getName());
+
+        return ClassFabUtils.createObjectCreatorProxy(cf, interfaceClass, justInTime, description);
+    }
 }

Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry/ioc/internal/RegistryWrapper.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry/ioc/internal/RegistryWrapper.java?rev=589228&r1=589227&r2=589228&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry/ioc/internal/RegistryWrapper.java (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry/ioc/internal/RegistryWrapper.java Sat Oct 27 15:29:27 2007
@@ -68,4 +68,9 @@
         _registry.performRegistryStartup();
     }
 
+    public <T> T proxy(Class<T> interfaceClass, Class<? extends T> implementationClass)
+    {
+        return _registry.proxy(interfaceClass, implementationClass);
+    }
+
 }

Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry/ioc/services/ClassFabUtils.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry/ioc/services/ClassFabUtils.java?rev=589228&r1=589227&r2=589228&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry/ioc/services/ClassFabUtils.java (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry/ioc/services/ClassFabUtils.java Sat Oct 27 15:29:27 2007
@@ -14,16 +14,20 @@
 
 package org.apache.tapestry.ioc.services;
 
+import static java.lang.String.format;
 import static org.apache.tapestry.ioc.internal.util.CollectionFactory.newMap;
 
 import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
 import java.util.Map;
 
+import org.apache.tapestry.ioc.ObjectCreator;
+
 /**
  * Handy method useful when creating new classes using
  * {@link org.apache.tapestry.ioc.services.ClassFab}.
  */
-public class ClassFabUtils
+public final class ClassFabUtils
 {
     private static long _uid = System.currentTimeMillis();
 
@@ -47,11 +51,7 @@
 
     public static String generateClassName(Class interfaceClass)
     {
-        String name = interfaceClass.getName();
-
-        int dotx = name.lastIndexOf('.');
-
-        return generateClassName(name.substring(dotx + 1));
+        return generateClassName(interfaceClass.getSimpleName());
     }
 
     /**
@@ -200,5 +200,53 @@
         if (type.isArray()) return "[" + getTypeCode(type.getComponentType());
 
         return "L" + type.getName().replace('.', '/') + ";";
+    }
+
+    /**
+     * Creates a proxy for a given service interface around an {@link ObjectCreator} that can
+     * provide (on demand) an object (implementing the service interface) to delegate to. The
+     * ObjectCreator will be invoked on every method invocation ( if it is caching, that should be
+     * internal to its implementation).
+     * 
+     * @param <T>
+     * @param classFab
+     *            used to create the new class
+     * @param serviceInterface
+     *            the interface the proxy will implement
+     * @param creator
+     *            the createor which will provide an instance of the interface
+     * @param description
+     *            description to be returned from the proxy's toString() method
+     * @return the instantiated proxy object
+     */
+    public static <T> T createObjectCreatorProxy(ClassFab classFab, Class<T> serviceInterface,
+            ObjectCreator creator, String description)
+    {
+        classFab.addField("_creator", Modifier.PRIVATE | Modifier.FINAL, ObjectCreator.class);
+
+        classFab.addConstructor(new Class[]
+        { ObjectCreator.class }, null, "_creator = $1;");
+
+        String body = format("return (%s) _creator.createObject();", serviceInterface.getName());
+
+        MethodSignature sig = new MethodSignature(serviceInterface, "_delegate", null, null);
+
+        classFab.addMethod(Modifier.PRIVATE, sig, body);
+
+        classFab.proxyMethodsToDelegate(serviceInterface, "_delegate()", description);
+        Class proxyClass = classFab.createClass();
+
+        try
+        {
+            Object proxy = proxyClass.getConstructors()[0].newInstance(creator);
+
+            return serviceInterface.cast(proxy);
+        }
+        catch (Exception ex)
+        {
+            // This should never happen, so we won't go to a lot of trouble
+            // reporting it.
+            throw new RuntimeException(ex.getMessage(), ex);
+        }
     }
 }

Added: tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry/ioc/CountingGreeterImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry/ioc/CountingGreeterImpl.java?rev=589228&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry/ioc/CountingGreeterImpl.java (added)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry/ioc/CountingGreeterImpl.java Sat Oct 27 15:29:27 2007
@@ -0,0 +1,31 @@
+// Copyright 2007 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;
+
+public class CountingGreeterImpl implements Greeter
+{
+    public static int _instantiationCount;
+
+    public CountingGreeterImpl()
+    {
+        _instantiationCount++;
+    }
+
+    public String getGreeting()
+    {
+        return "Hello";
+    }
+
+}

Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry/ioc/IntegrationTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry/ioc/IntegrationTest.java?rev=589228&r1=589227&r2=589228&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry/ioc/IntegrationTest.java (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry/ioc/IntegrationTest.java Sat Oct 27 15:29:27 2007
@@ -705,4 +705,31 @@
             if (serviceId.equals("BlueGreeter")) assertEquals(a.getStatus(), Status.VIRTUAL);
         }
     }
+
+    @Test
+    public void proxy_autobuild_object()
+    {
+        Registry r = buildRegistry();
+
+        CountingGreeterImpl._instantiationCount = 0;
+
+        Greeter g = r.proxy(Greeter.class, CountingGreeterImpl.class);
+
+        assertEquals(CountingGreeterImpl._instantiationCount, 0);
+
+        assertEquals(
+                g.toString(),
+                "<Autobuild proxy org.apache.tapestry.ioc.CountingGreeterImpl(org.apache.tapestry.ioc.Greeter)>");
+
+        assertEquals(CountingGreeterImpl._instantiationCount, 0);
+
+        // Show that the class is not instantiated until a method is invoked, and that its
+        // only instantiated once.
+
+        for (int i = 0; i < 5; i++)
+        {
+            assertEquals(g.getGreeting(), "Hello");
+            assertEquals(CountingGreeterImpl._instantiationCount, 1);
+        }
+    }
 }