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);
+ }
+ }
}