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 2008/08/11 18:42:56 UTC
svn commit: r684803 - in /tapestry/tapestry5/trunk:
quickstart/src/main/resources/archetype-resources/src/main/java/services/
src/site/apt/
tapestry-annotations/src/main/java/org/apache/tapestry5/ioc/annotations/
tapestry-core/src/main/java/org/apache/...
Author: hlship
Date: Mon Aug 11 09:42:47 2008
New Revision: 684803
URL: http://svn.apache.org/viewvc?rev=684803&view=rev
Log:
TAPESTRY-1867: Support a special marker interface @Local to select just services defined within the same module
Added:
tapestry/tapestry5/trunk/tapestry-annotations/src/main/java/org/apache/tapestry5/ioc/annotations/Local.java
tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/LocalModule.java
Removed:
tapestry/tapestry5/trunk/tapestry-tutorial1/src/main/java/org/apache/tapestry5/tutorial/services/Local.java
Modified:
tapestry/tapestry5/trunk/quickstart/src/main/resources/archetype-resources/src/main/java/services/AppModule.java
tapestry/tapestry5/trunk/src/site/apt/index.apt
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/test/TestableRequestImpl.java
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TapestryModule.java
tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/IOCMessages.java
tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/InternalRegistry.java
tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ObjectLocatorImpl.java
tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/RegistryImpl.java
tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalUtils.java
tapestry/tapestry5/trunk/tapestry-ioc/src/main/resources/org/apache/tapestry5/ioc/internal/IOCStrings.properties
tapestry/tapestry5/trunk/tapestry-ioc/src/site/apt/service.apt
tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/IntegrationTest.java
tapestry/tapestry5/trunk/tapestry-tutorial1/src/main/java/org/apache/tapestry5/tutorial/entities/Address.java
tapestry/tapestry5/trunk/tapestry-tutorial1/src/main/java/org/apache/tapestry5/tutorial/services/AppModule.java
tapestry/tapestry5/trunk/tapestry-tutorial1/src/site/apt/forms2.apt
Modified: tapestry/tapestry5/trunk/quickstart/src/main/resources/archetype-resources/src/main/java/services/AppModule.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/quickstart/src/main/resources/archetype-resources/src/main/java/services/AppModule.java?rev=684803&r1=684802&r2=684803&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/quickstart/src/main/resources/archetype-resources/src/main/java/services/AppModule.java (original)
+++ tapestry/tapestry5/trunk/quickstart/src/main/resources/archetype-resources/src/main/java/services/AppModule.java Mon Aug 11 09:42:47 2008
@@ -6,7 +6,7 @@
import org.apache.tapestry5.ioc.MappedConfiguration;
import org.apache.tapestry5.ioc.OrderedConfiguration;
import org.apache.tapestry5.ioc.ServiceBinder;
-import org.apache.tapestry5.ioc.annotations.InjectService;
+import org.apache.tapestry5.ioc.annotations.Local;
import org.apache.tapestry5.services.Request;
import org.apache.tapestry5.services.RequestFilter;
import org.apache.tapestry5.services.RequestHandler;
@@ -52,7 +52,7 @@
* This is a service definition, the service will be named "TimingFilter". The interface,
* RequestFilter, is used within the RequestHandler service pipeline, which is built from the
* RequestHandler service configuration. Tapestry IoC is responsible for passing in an
- * appropriate Log instance. Requests for static resources are handled at a higher level, so
+ * appropriate Logger instance. Requests for static resources are handled at a higher level, so
* this filter will only be invoked for Tapestry related requests.
*
* <p>
@@ -96,10 +96,12 @@
/**
* This is a contribution to the RequestHandler service configuration. This is how we extend
* Tapestry using the timing filter. A common use for this kind of filter is transaction
- * management or security.
+ * management or security. The @Local annotation selects the desired service by type, but only
+ * from the same module. Without @Local, there would be an error due to the other service(s)
+ * that implement RequestFilter (defined in other modules).
*/
public void contributeRequestHandler(OrderedConfiguration<RequestFilter> configuration,
- @InjectService("TimingFilter")
+ @Local
RequestFilter filter)
{
// Each contribution to an ordered configuration has a name, When necessary, you may
Modified: tapestry/tapestry5/trunk/src/site/apt/index.apt
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/src/site/apt/index.apt?rev=684803&r1=684802&r2=684803&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/src/site/apt/index.apt (original)
+++ tapestry/tapestry5/trunk/src/site/apt/index.apt Mon Aug 11 09:42:47 2008
@@ -36,7 +36,7 @@
Tapestry is, of course, an open-source project, with all the work coming from unpaid volunteers. That being said, our rough timeline is as follows:
- * 5.0 Release Candidate in Q1 2008
+ * 5.0 Release Candidate in Q1 2008 ((<Ooops!)>
* 5.0 Final Release shortly thereafter
@@ -84,6 +84,9 @@
New And Of Note
+ * The new {{{apidocs/org/apache/tapestry5/ioc/annotations/Local.html}@Local}}
+ annotation makes it easier to reference services within the same module when injecting.
+
* Most general documentation has been moved from the tapestry-core module up to the project level.
* Work has started on a {{{cookbook}Tapestry Cookbook}}, showing how to tackle common scenarios.
Added: tapestry/tapestry5/trunk/tapestry-annotations/src/main/java/org/apache/tapestry5/ioc/annotations/Local.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-annotations/src/main/java/org/apache/tapestry5/ioc/annotations/Local.java?rev=684803&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-annotations/src/main/java/org/apache/tapestry5/ioc/annotations/Local.java (added)
+++ tapestry/tapestry5/trunk/tapestry-annotations/src/main/java/org/apache/tapestry5/ioc/annotations/Local.java Mon Aug 11 09:42:47 2008
@@ -0,0 +1,29 @@
+// Copyright 2008 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.tapestry5.ioc.annotations;
+
+import java.lang.annotation.*;
+
+
+/**
+ * A special marker annotation which limits the search for possible services to just the <em>same</em> module containing
+ * the service being injected. Other marker annotations may also be applied.
+ */
+@Target({ElementType.PARAMETER, ElementType.FIELD})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface Local
+{
+}
Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/test/TestableRequestImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/test/TestableRequestImpl.java?rev=684803&r1=684802&r2=684803&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/test/TestableRequestImpl.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/test/TestableRequestImpl.java Mon Aug 11 09:42:47 2008
@@ -16,6 +16,7 @@
import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
import org.apache.tapestry5.ioc.internal.util.InternalUtils;
+import org.apache.tapestry5.ioc.annotations.Inject;
import org.apache.tapestry5.services.Session;
import java.util.List;
@@ -32,6 +33,7 @@
private Session session;
+ @Inject
public TestableRequestImpl()
{
this("/foo");
Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TapestryModule.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TapestryModule.java?rev=684803&r1=684802&r2=684803&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TapestryModule.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TapestryModule.java Mon Aug 11 09:42:47 2008
@@ -194,15 +194,15 @@
// ========================================================================
- public static Alias build(Logger logger,
+ public static Alias buildAlias(Logger logger,
- @Inject @Symbol(InternalConstants.TAPESTRY_ALIAS_MODE_SYMBOL)
- String mode,
+ @Inject @Symbol(InternalConstants.TAPESTRY_ALIAS_MODE_SYMBOL)
+ String mode,
- @InjectService("AliasOverrides")
- AliasManager overridesManager,
+ @InjectService("AliasOverrides")
+ AliasManager overridesManager,
- Collection<AliasContribution> configuration)
+ Collection<AliasContribution> configuration)
{
AliasManager manager = new AliasManagerImpl(logger, configuration);
@@ -515,7 +515,7 @@
*/
public static void contributeMasterObjectProvider(OrderedConfiguration<ObjectProvider> configuration,
- @InjectService("Alias")
+ @Local
final Alias alias,
@InjectService("AssetObjectProvider")
@@ -523,7 +523,10 @@
{
// There's a nasty web of dependencies related to Alias; this wrapper class lets us
// defer instantiating the Alias service implementation just long enough to defuse those
- // dependencies.
+ // dependencies. The @Local annotation prevents a recursive call through the
+ // MasterObjectProvider to resolve the Alias service itself; that is MasterObjectProvider
+ // gets built using this proxy, then the proxy will trigger the construction of AliasImpl
+ // (which itself needs MasterObjectProvider to resolve some dependencies).
ObjectProvider wrapper = new ObjectProvider()
{
@@ -533,7 +536,7 @@
}
};
- configuration.add("Alias", wrapper, "after:Value");
+ configuration.add("Alias", wrapper, "after:Value,Symbol");
configuration.add("Asset", assetObjectProvider, "before:Alias");
Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/IOCMessages.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/IOCMessages.java?rev=684803&r1=684802&r2=684803&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/IOCMessages.java (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/IOCMessages.java Mon Aug 11 09:42:47 2008
@@ -1,4 +1,4 @@
-// Copyright 2006, 2007 The Apache Software Foundation
+// Copyright 2006, 2007, 2008 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.
@@ -17,6 +17,7 @@
import org.apache.tapestry5.ioc.Messages;
import org.apache.tapestry5.ioc.def.ContributionDef;
import org.apache.tapestry5.ioc.def.ServiceDef;
+import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
import org.apache.tapestry5.ioc.internal.util.InternalUtils;
import static org.apache.tapestry5.ioc.internal.util.InternalUtils.asString;
import org.apache.tapestry5.ioc.internal.util.MessagesImpl;
@@ -279,17 +280,32 @@
return MESSAGES.format("autobuild-constructor-error", constructorDescription, cause);
}
- static String noServicesMatchMarker(Class objectType, Class marker)
+ private static String toJavaClassNames(List<Class> classes)
{
- return MESSAGES.format("no-services-match-marker", ClassFabUtils
- .toJavaClassName(objectType), ClassFabUtils.toJavaClassName(marker));
+ List<String> names = CollectionFactory.newList();
+
+ for (Class<?> clazz : classes)
+ {
+ names.add(ClassFabUtils.toJavaClassName(clazz));
+ }
+
+ return InternalUtils.joinSorted(names);
+ }
+
+ static String noServicesMatchMarker(Class objectType, List<Class> markers)
+ {
+ return MESSAGES.format("no-services-match-marker",
+ ClassFabUtils.toJavaClassName(objectType),
+ toJavaClassNames(markers));
}
- static String manyServicesMatchMarker(Class objectType, Class marker, Collection<ServiceDef> matchingServices)
+ static String manyServicesMatchMarker(Class objectType, List<Class> markers,
+ Collection<ServiceDef> matchingServices)
{
- return MESSAGES.format("many-services-match-marker", ClassFabUtils
- .toJavaClassName(objectType), ClassFabUtils.toJavaClassName(marker), InternalUtils
- .joinSorted(matchingServices));
+ return MESSAGES.format("many-services-match-marker",
+ ClassFabUtils.toJavaClassName(objectType),
+ toJavaClassNames(markers),
+ InternalUtils.joinSorted(matchingServices));
}
static String overlappingServiceProxyProviders()
Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/InternalRegistry.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/InternalRegistry.java?rev=684803&r1=684802&r2=684803&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/InternalRegistry.java (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/InternalRegistry.java Mon Aug 11 09:42:47 2008
@@ -1,4 +1,4 @@
-// Copyright 2006, 2007 The Apache Software Foundation
+// Copyright 2006, 2007, 2008 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.
@@ -14,6 +14,7 @@
package org.apache.tapestry5.ioc.internal;
+import org.apache.tapestry5.ioc.AnnotationProvider;
import org.apache.tapestry5.ioc.Registry;
import org.apache.tapestry5.ioc.ServiceDecorator;
import org.apache.tapestry5.ioc.ServiceLifecycle;
@@ -32,6 +33,17 @@
public interface InternalRegistry extends Registry, RegistryShutdownHub
{
/**
+ * As with {@link org.apache.tapestry5.ioc.Registry#getObject(Class, org.apache.tapestry5.ioc.AnnotationProvider)},
+ * but handles the {@link org.apache.tapestry5.ioc.annotations.Local} annotation.
+ *
+ * @param objectType type of object o be injected
+ * @param annotationProvider access to annotations at point of injection
+ * @param localModule module to limit services to, if Local annotaton present
+ * @return the service or object
+ */
+ <T> T getObject(Class<T> objectType, AnnotationProvider annotationProvider, Module localModule);
+
+ /**
* Returns a service lifecycle by service scope name.
*
* @param scope the name of the service scope (case insensitive)
@@ -84,7 +96,8 @@
Class<V> valueType);
/**
- * Convieience for creating a new {@link ClassFab} instance using a {@link org.apache.tapestry5.ioc.services.ClassFactory}.
+ * Convieience for creating a new {@link org.apache.tapestry5.ioc.services.ClassFab} instance using a {@link
+ * org.apache.tapestry5.ioc.services.ClassFactory}.
*
* @param serviceInterface the interface to be implemented by the provided class
*/
Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ObjectLocatorImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ObjectLocatorImpl.java?rev=684803&r1=684802&r2=684803&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ObjectLocatorImpl.java (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ObjectLocatorImpl.java Mon Aug 11 09:42:47 2008
@@ -1,4 +1,4 @@
-// Copyright 2006, 2007 The Apache Software Foundation
+// Copyright 2006, 2007, 2008 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.
@@ -46,7 +46,7 @@
public <T> T getObject(Class<T> objectType, AnnotationProvider annotationProvider)
{
- return registry.getObject(objectType, annotationProvider);
+ return registry.getObject(objectType, annotationProvider, module);
}
protected InternalRegistry getRegistry()
Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/RegistryImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/RegistryImpl.java?rev=684803&r1=684802&r2=684803&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/RegistryImpl.java (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/RegistryImpl.java Mon Aug 11 09:42:47 2008
@@ -15,6 +15,7 @@
package org.apache.tapestry5.ioc.internal;
import org.apache.tapestry5.ioc.*;
+import org.apache.tapestry5.ioc.annotations.Local;
import org.apache.tapestry5.ioc.def.ContributionDef;
import org.apache.tapestry5.ioc.def.DecoratorDef;
import org.apache.tapestry5.ioc.def.ModuleDef;
@@ -84,13 +85,15 @@
private SymbolSource symbolSource;
- private final List<Module> modules = CollectionFactory.newList();
+ private final Map<Module, Set<ServiceDef>> moduleToServiceDefs = CollectionFactory.newMap();
/**
* From marker type to a list of marked service instances.
*/
private final Map<Class, List<ServiceDef>> markerToServiceDef = CollectionFactory.newMap();
+ private final Set<ServiceDef> allServiceDefs = CollectionFactory.newSet();
+
public static final class OrderedConfigurationToOrdererAdaptor<T> implements OrderedConfiguration<T>
{
@@ -122,25 +125,17 @@
tracker = scoreboardAndTracker;
- addBuiltin(SERVICE_ACTIVITY_SCOREBOARD_SERVICE_ID, ServiceActivityScoreboard.class, scoreboardAndTracker);
-
- addBuiltin(LOGGER_SOURCE_SERVICE_ID, LoggerSource.class, this.loggerSource);
-
this.classFactory = classFactory;
- addBuiltin(CLASS_FACTORY_SERVICE_ID, ClassFactory.class, this.classFactory);
-
Logger logger = loggerForBuiltinService(PERTHREAD_MANAGER_SERVICE_ID);
perthreadManager = new PerthreadManagerImpl(logger);
- addBuiltin(PERTHREAD_MANAGER_SERVICE_ID, PerthreadManager.class, perthreadManager);
logger = loggerForBuiltinService(REGISTRY_SHUTDOWN_HUB_SERVICE_ID);
registryShutdownHub = new RegistryShutdownHubImpl(logger);
- addBuiltin(REGISTRY_SHUTDOWN_HUB_SERVICE_ID, RegistryShutdownHub.class, registryShutdownHub);
lifecycles.put("singleton", new SingletonServiceLifecycle());
@@ -158,12 +153,15 @@
Module module = new ModuleImpl(this, tracker, def, classFactory, logger);
- modules.add(module);
+ Set<ServiceDef> moduleServiceDefs = CollectionFactory.newSet();
for (String serviceId : def.getServiceIds())
{
ServiceDef serviceDef = module.getServiceDef(serviceId);
+ moduleServiceDefs.add(serviceDef);
+ allServiceDefs.add(serviceDef);
+
Module existing = serviceIdToModule.get(serviceId);
if (existing != null) throw new RuntimeException(IOCMessages.serviceIdConflict(serviceId, existing
@@ -178,8 +176,16 @@
InternalUtils.addToMapList(markerToServiceDef, marker, serviceDef);
}
+
+ moduleToServiceDefs.put(module, moduleServiceDefs);
}
+ addBuiltin(SERVICE_ACTIVITY_SCOREBOARD_SERVICE_ID, ServiceActivityScoreboard.class, scoreboardAndTracker);
+ addBuiltin(LOGGER_SOURCE_SERVICE_ID, LoggerSource.class, this.loggerSource);
+ addBuiltin(CLASS_FACTORY_SERVICE_ID, ClassFactory.class, this.classFactory);
+ addBuiltin(PERTHREAD_MANAGER_SERVICE_ID, PerthreadManager.class, perthreadManager);
+ addBuiltin(REGISTRY_SHUTDOWN_HUB_SERVICE_ID, RegistryShutdownHub.class, registryShutdownHub);
+
scoreboardAndTracker.startup();
SerializationSupport.setProvider(this);
@@ -196,7 +202,7 @@
List<EagerLoadServiceProxy> proxies = CollectionFactory.newList();
- for (Module m : modules)
+ for (Module m : moduleToServiceDefs.keySet())
m.collectEagerLoadServices(proxies);
// TAPESTRY-2267: Gather up all the proxies before instantiating any of them.
@@ -265,7 +271,10 @@
};
for (Class marker : serviceDef.getMarkers())
+ {
InternalUtils.addToMapList(markerToServiceDef, marker, serviceDef);
+ allServiceDefs.add(serviceDef);
+ }
tracker.define(serviceDef, Status.BUILTIN);
}
@@ -342,9 +351,7 @@
}
};
- Collection<Module> modules = this.modules;
-
- for (Module m : modules)
+ for (Module m : moduleToServiceDefs.keySet())
addToUnorderedConfiguration(configuration, objectType, serviceDef, m);
return result;
@@ -362,9 +369,7 @@
OrderedConfiguration<T> configuration = new OrderedConfigurationToOrdererAdaptor<T>(orderer);
- Collection<Module> modules = this.modules;
-
- for (Module m : modules)
+ for (Module m : moduleToServiceDefs.keySet())
addToOrderedConfiguration(configuration, objectType, serviceDef, m);
// An ugly hack ... perhaps we should introduce a new builtin service so that this can be
@@ -376,7 +381,7 @@
{
public <T> T provide(Class<T> objectType, AnnotationProvider annotationProvider, ObjectLocator locator)
{
- return findServiceByMarkerAndType(objectType, annotationProvider);
+ return findServiceByMarkerAndType(objectType, annotationProvider, null);
}
};
@@ -403,9 +408,7 @@
}
};
- Collection<Module> modules = this.modules;
-
- for (Module m : modules)
+ for (Module m : moduleToServiceDefs.keySet())
addToMappedConfiguration(configuration, keyToContribution, keyType, objectType, serviceDef, m);
return result;
@@ -535,7 +538,7 @@
{
List<String> result = CollectionFactory.newList();
- for (Module module : modules)
+ for (Module module : moduleToServiceDefs.keySet())
result.addAll(module.findServiceIdsForInterface(serviceInterface));
for (Map.Entry<String, Object> entry : builtinServices.entrySet())
@@ -575,7 +578,7 @@
Orderer<ServiceDecorator> orderer = new Orderer<ServiceDecorator>(logger);
- for (Module module : modules)
+ for (Module module : moduleToServiceDefs.keySet())
{
Set<DecoratorDef> decorators = module.findMatchingDecoratorDefs(serviceDef);
@@ -601,7 +604,8 @@
return classFactory.newClass(serviceInterface);
}
- private <T> T getObject(Class<T> objectType, AnnotationProvider annotationProvider, ObjectLocator locator)
+ private <T> T getObject(Class<T> objectType, AnnotationProvider annotationProvider, ObjectLocator locator,
+ Module localModule)
{
lock.check();
@@ -612,7 +616,7 @@
// to inject into a contribution method that contributes to MasterObjectProvider.
// We also force a contribution into MasterObjectProvider to accomplish the same thing.
- T result = findServiceByMarkerAndType(objectType, annotationProvider);
+ T result = findServiceByMarkerAndType(objectType, annotationProvider, localModule);
if (result != null) return result;
@@ -622,58 +626,111 @@
return masterProvider.provide(objectType, effectiveProvider, locator, true);
}
+ private Collection<ServiceDef> filterByType(Class<?> objectType, Collection<ServiceDef> serviceDefs)
+ {
+ Collection<ServiceDef> result = CollectionFactory.newSet();
+
+ for (ServiceDef sd : serviceDefs)
+ {
+ if (objectType.isAssignableFrom(sd.getServiceInterface()))
+ {
+ result.add(sd);
+ }
+ }
+
+ return result;
+ }
+
@SuppressWarnings("unchecked")
- private <T> T findServiceByMarkerAndType(Class<T> objectType, AnnotationProvider provider)
+ private <T> T findServiceByMarkerAndType(Class<T> objectType, AnnotationProvider provider, Module localModule)
{
if (provider == null) return null;
+ boolean localOnly = localModule != null && provider.getAnnotation(Local.class) != null;
+
+
+ Set<ServiceDef> matches = CollectionFactory.newSet();
+
+ matches.addAll(filterByType(objectType, localOnly
+ ? moduleToServiceDefs.get(localModule)
+ : allServiceDefs
+ ));
+
+ List<Class> markers = CollectionFactory.newList();
+
+ if (localOnly) markers.add(Local.class);
+
for (Class marker : markerToServiceDef.keySet())
{
if (provider.getAnnotation(marker) == null) continue;
- List<ServiceDef> matches = CollectionFactory.newList();
+ markers.add(marker);
- for (ServiceDef def : markerToServiceDef.get(marker))
- {
- if (objectType.isAssignableFrom(def.getServiceInterface())) matches.add(def);
- }
+ matches = intersection(matches, markerToServiceDef.get(marker));
+ }
- switch (matches.size())
- {
+ // If didn't see @Local or any recognized marker annotation, then don't try to filter that way.
+ // Continue on, eventually to the MasterObjectProvider service.
+
+ if (markers.isEmpty()) return null;
+
+ switch (matches.size())
+ {
- case 1:
+ case 1:
- ServiceDef def = matches.get(0);
+ ServiceDef def = matches.iterator().next();
- return getService(def.getServiceId(), objectType);
+ return getService(def.getServiceId(), objectType);
- case 0:
+ case 0:
- // It's no accident that the user put the marker annotation at the injection
- // point, since it matches a known marker annotation, it better be there for
- // a reason. So if we don't get a match, we have to assume the user expected
- // one, and that is an error.
+ // It's no accident that the user put the marker annotation at the injection
+ // point, since it matches a known marker annotation, it better be there for
+ // a reason. So if we don't get a match, we have to assume the user expected
+ // one, and that is an error.
- // This doesn't help when the user places an annotation they *think* is a marker
- // but isn't really a marker (because no service is marked by the annotation).
+ // This doesn't help when the user places an annotation they *think* is a marker
+ // but isn't really a marker (because no service is marked by the annotation).
- throw new RuntimeException(IOCMessages
- .noServicesMatchMarker(objectType, marker));
+ throw new RuntimeException(IOCMessages.noServicesMatchMarker(objectType, markers));
- default:
- throw new RuntimeException(IOCMessages.manyServicesMatchMarker(objectType, marker, matches));
- }
+ default:
+ throw new RuntimeException(IOCMessages.manyServicesMatchMarker(objectType, markers, matches));
+ }
+ }
+
+ /**
+ * Filters the set into a new set, containing only elements shared between the set and the filter collection.
+ *
+ * @param set to be filtered
+ * @param filter values to keep from the set
+ * @return a new set containing only the shared values
+ */
+ private static <T> Set<T> intersection(Set<T> set, Collection<T> filter)
+ {
+ if (set.isEmpty()) return Collections.emptySet();
+ Set<T> result = CollectionFactory.newSet();
+
+ for (T elem : filter)
+ {
+ if (set.contains(elem)) result.add(elem);
}
- return null;
+ return result;
}
+
public <T> T getObject(Class<T> objectType, AnnotationProvider annotationProvider)
{
- lock.check();
+ return getObject(objectType, annotationProvider, this, null);
+ }
- return getObject(objectType, annotationProvider, this);
+
+ public <T> T getObject(Class<T> objectType, AnnotationProvider annotationProvider, Module localModule)
+ {
+ return getObject(objectType, annotationProvider, this, localModule);
}
public void addRegistryShutdownListener(RegistryShutdownListener listener)
Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalUtils.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalUtils.java?rev=684803&r1=684802&r2=684803&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalUtils.java (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalUtils.java Mon Aug 11 09:42:47 2008
@@ -194,7 +194,7 @@
}
// In the absence of @InjectService, try some autowiring. First, does the
- // parameter type match on of the resources (the parameter defaults)?
+ // parameter type match one of the resources (the parameter defaults)?
if (provider.getAnnotation(Inject.class) == null)
{
Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/main/resources/org/apache/tapestry5/ioc/internal/IOCStrings.properties
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/resources/org/apache/tapestry5/ioc/internal/IOCStrings.properties?rev=684803&r1=684802&r2=684803&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/main/resources/org/apache/tapestry5/ioc/internal/IOCStrings.properties (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/main/resources/org/apache/tapestry5/ioc/internal/IOCStrings.properties Mon Aug 11 09:42:47 2008
@@ -1,4 +1,4 @@
-# Copyright 2006, 2007 The Apache Software Foundation
+# Copyright 2006, 2007, 2008 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.
@@ -29,8 +29,8 @@
no-service-matches-type=No service implements the interface %s.
many-service-matches=Service interface %s is matched by %d services: %s. \
Automatic dependency resolution requires that exactly one service implement the interface.
-no-services-match-marker=Unable to locate any service assignable to type %s with marker annotation %s.
-many-services-match-marker=Unable to locate a single service assignable to type %s with marker annotation %s. \
+no-services-match-marker=Unable to locate any service assignable to type %s with marker annotation(s) %s.
+many-services-match-marker=Unable to locate a single service assignable to type %s with marker annotation(s) %s. \
All of the following services match: %s.
unknown-scope=Unknown service scope '%s'.
decorator-method-needs-delegate-parameter=Decorator methods must a parameter for the service delegate \
Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/site/apt/service.apt
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/site/apt/service.apt?rev=684803&r1=684802&r2=684803&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/site/apt/service.apt (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/site/apt/service.apt Mon Aug 11 09:42:47 2008
@@ -310,6 +310,18 @@
The @Marker annotation may also be placed on an implementation class, which means that you may omit
the call to withMarker() inside the bind() method.
+ Finally, the point of injection may have multiple marker annotations; only services that are marked
+ with <all> those markers will be considered for injection. Each marker annotation creates an increasingly narrow
+ subset from the set of all possible services (compatible with the indicated dependency type).
+
+Local Dependencies
+
+ A special marker interface,
+ {{{../apidocs/org/apache/tapestry5/ioc/annotations/Local.html}@Local}},
+ indicates a dependency that should only be resolved using services from within <the same module>.
+
+ @Local can also be combined with other marker annotations.
+
Injecting Dependencies for Autobuilt Services
With autobuilt services, there's no service builder method in which to specify injections.
Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/IntegrationTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/IntegrationTest.java?rev=684803&r1=684802&r2=684803&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/IntegrationTest.java (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/IntegrationTest.java Mon Aug 11 09:42:47 2008
@@ -685,7 +685,7 @@
catch (RuntimeException ex)
{
assertMessageContains(ex, "Error invoking service builder method",
- "Unable to locate a single service assignable to type org.apache.tapestry5.ioc.Greeter with marker annotation org.apache.tapestry5.ioc.RedMarker",
+ "Unable to locate a single service assignable to type org.apache.tapestry5.ioc.Greeter with marker annotation(s) org.apache.tapestry5.ioc.RedMarker",
"org.apache.tapestry5.ioc.GreeterModule.buildRedGreeter1()",
"org.apache.tapestry5.ioc.GreeterModule.buildRedGreeter2()");
}
@@ -708,7 +708,7 @@
catch (RuntimeException ex)
{
assertMessageContains(ex, "Error invoking service builder method",
- " Unable to locate any service assignable to type org.apache.tapestry5.ioc.Greeter with marker annotation org.apache.tapestry5.ioc.YellowMarker.");
+ " Unable to locate any service assignable to type org.apache.tapestry5.ioc.Greeter with marker annotation(s) org.apache.tapestry5.ioc.YellowMarker.");
}
r.shutdown();
@@ -889,4 +889,18 @@
);
}
}
+
+ @Test
+ public void local_annotation()
+ {
+ Registry r = buildRegistry(GreeterModule.class, LocalModule.class);
+
+ StringHolder g = r.getService("LocalGreeterHolder", StringHolder.class);
+
+ // Comes from the @Local DrawlGreeter, even though there are many other Greeter services available.
+
+ assertEquals(g.getValue(), "Hello, y'all!");
+
+ r.shutdown();
+ }
}
Added: tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/LocalModule.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/LocalModule.java?rev=684803&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/LocalModule.java (added)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/LocalModule.java Mon Aug 11 09:42:47 2008
@@ -0,0 +1,46 @@
+// Copyright 2008 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.tapestry5.ioc;
+
+import org.apache.tapestry5.ioc.annotations.Local;
+
+public class LocalModule
+{
+ public Greeter buildDrawlGreeter()
+ {
+ return new Greeter()
+ {
+ public String getGreeting()
+ {
+ return "Hello, y'all!";
+ }
+ };
+ }
+
+ public StringHolder buildLocalGreeterHolder(final @Local Greeter greeter)
+ {
+ return new StringHolder()
+ {
+ public void setValue(String value)
+ {
+ }
+
+ public String getValue()
+ {
+ return greeter.getGreeting();
+ }
+ };
+ }
+}
Modified: tapestry/tapestry5/trunk/tapestry-tutorial1/src/main/java/org/apache/tapestry5/tutorial/entities/Address.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-tutorial1/src/main/java/org/apache/tapestry5/tutorial/entities/Address.java?rev=684803&r1=684802&r2=684803&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-tutorial1/src/main/java/org/apache/tapestry5/tutorial/entities/Address.java (original)
+++ tapestry/tapestry5/trunk/tapestry-tutorial1/src/main/java/org/apache/tapestry5/tutorial/entities/Address.java Mon Aug 11 09:42:47 2008
@@ -28,29 +28,34 @@
{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
+ @NonVisual
private Long id;
private Honorific honorific;
+ @Validate("required")
private String firstName;
+ @Validate("required")
private String lastName;
private String street1;
private String street2;
+ @Validate("required")
private String city;
+ @Validate("required")
private String state;
+ @Validate("required,regexp")
private String zip;
private String email;
private String phone;
- @NonVisual
public Long getId()
{
return id;
@@ -66,7 +71,6 @@
return honorific;
}
- @Validate("required")
public String getFirstName()
{
return firstName;
@@ -77,7 +81,6 @@
return lastName;
}
- @Validate("required")
public String getStreet1()
{
return street1;
@@ -88,19 +91,16 @@
return street2;
}
- @Validate("required")
public String getCity()
{
return city;
}
- @Validate("required")
public String getState()
{
return state;
}
- @Validate("required,regexp")
public String getZip()
{
return zip;
Modified: tapestry/tapestry5/trunk/tapestry-tutorial1/src/main/java/org/apache/tapestry5/tutorial/services/AppModule.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-tutorial1/src/main/java/org/apache/tapestry5/tutorial/services/AppModule.java?rev=684803&r1=684802&r2=684803&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-tutorial1/src/main/java/org/apache/tapestry5/tutorial/services/AppModule.java (original)
+++ tapestry/tapestry5/trunk/tapestry-tutorial1/src/main/java/org/apache/tapestry5/tutorial/services/AppModule.java Mon Aug 11 09:42:47 2008
@@ -1,4 +1,4 @@
-// Copyright 2007 The Apache Software Foundation
+// Copyright 2007, 2008 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.
@@ -17,7 +17,7 @@
import org.apache.tapestry5.SymbolConstants;
import org.apache.tapestry5.ioc.MappedConfiguration;
import org.apache.tapestry5.ioc.OrderedConfiguration;
-import org.apache.tapestry5.ioc.annotations.Marker;
+import org.apache.tapestry5.ioc.annotations.Local;
import org.apache.tapestry5.services.Request;
import org.apache.tapestry5.services.RequestFilter;
import org.apache.tapestry5.services.RequestHandler;
@@ -30,7 +30,6 @@
* This module is automatically included as part of the Tapestry IoC Registry, it's a good place to configure and extend
* Tapestry, or to place your own services.
*/
-@Marker(Local.class)
public class AppModule
{
public static void contributeApplicationDefaults(
Modified: tapestry/tapestry5/trunk/tapestry-tutorial1/src/site/apt/forms2.apt
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-tutorial1/src/site/apt/forms2.apt?rev=684803&r1=684802&r2=684803&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-tutorial1/src/site/apt/forms2.apt (original)
+++ tapestry/tapestry5/trunk/tapestry-tutorial1/src/site/apt/forms2.apt Mon Aug 11 09:42:47 2008
@@ -78,7 +78,10 @@
</dependencies>
----
- The tapestry-hibernate library includes, as transitive dependencies, Hibernate and tapestry-core.
+ The tapestry-hibernate library includes, as transitive dependencies, Hibernate and tapestry-core. This means
+ that you can simply replace "tapestry-core" with "tapestry-hibernate" inside the \<artifactId\> element.
+
+ Since Hibernate can work with so many different databases, we must explicitly add in the correct driver.
* Hibernate Configuration
@@ -119,9 +122,7 @@
For an entity class to be used with Hibernate, some Hibernate annotations must be added to the class.
- Below is the updated Address class, with the Hibernate annotations (as well as the Tapestry ones). Hibernate
- annotations can be applied to fields or to accessor methods, but the Tapestry annotations we use below
- are for methods only.
+ Below is the updated Address class, with the Hibernate annotations (as well as the Tapestry ones).
<<src/main/java/org/apache/tapestry5/tutorial/entities/Address.java:>>
@@ -142,29 +143,34 @@
{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
+ @NonVisual
private Long id;
private Honorific honorific;
+ @Validate("required")
private String firstName;
+ @Validate("required")
private String lastName;
private String street1;
private String street2;
+ @Validate("required")
private String city;
+ @Validate("required")
private String state;
+ @Validate("required,regexp")
private String zip;
private String email;
private String phone;
- @NonVisual
public Long getId()
{
return id;
@@ -180,7 +186,6 @@
return honorific;
}
- @Validate("required")
public String getFirstName()
{
return firstName;
@@ -191,7 +196,6 @@
return lastName;
}
- @Validate("required")
public String getStreet1()
{
return street1;
@@ -202,19 +206,16 @@
return street2;
}
- @Validate("required")
public String getCity()
{
return city;
}
- @Validate("required")
public String getState()
{
return state;
}
- @Validate("required,regexp")
public String getZip()
{
return zip;
@@ -282,6 +283,16 @@
}
----
+ The Tapestry annotations, @NonVisual and @Validate, may be placed on the setter or getter method or on
+ the field (as we have done here). As with the Hibernate annotations, putting the annotation on the field
+ requires that the field name match the corresponding property name.
+
+ [@NonVisual]
+ This annotation indicates a field, such as a primary key, that should not be made visible to the user.
+
+ [@Validate]
+ This annotations identifies the validations associated with a field.
+
Updating the Database
So we have a database up and running, and Hibernate is configured to connect to it. Let's make use of that