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