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/02/11 00:43:28 UTC
svn commit: r505796 [1/2] - in /tapestry/tapestry5/tapestry-ioc/trunk/src:
main/java/org/apache/tapestry/ioc/
main/java/org/apache/tapestry/ioc/internal/
main/java/org/apache/tapestry/ioc/internal/services/
main/java/org/apache/tapestry/ioc/internal/ut...
Author: hlship
Date: Sat Feb 10 15:43:27 2007
New Revision: 505796
URL: http://svn.apache.org/viewvc?view=rev&rev=505796
Log:
Add a Stack utility class for efficiently managing a stack.
Add a CaseInsensitiveMap implementation, a case-insensitive (but case-maintaining) implementation of Map (which requires that keys be strings).
Modify a number of key maps throughout the module to be case insensitive (for module ids, service ids, etc.).
Add documentation describing the use of case-insensitivity.
Added:
tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/util/CaseInsensitiveMap.java
tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/util/Stack.java
tapestry/tapestry5/tapestry-ioc/trunk/src/site/apt/case.apt
tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/util/CaseInsensitiveMapTest.java
tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/util/StackTest.java
Modified:
tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/RegistryBuilder.java
tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/internal/DefaultModuleDefImpl.java
tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/internal/GlobPatternMatcher.java
tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/internal/ModuleImpl.java
tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/internal/RegistryImpl.java
tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/internal/services/AbstractFab.java
tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/internal/services/ClassPropertyAdapterImpl.java
tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/internal/services/MasterObjectProvider.java
tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/internal/util/CollectionFactory.java
tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/internal/util/MessagesImpl.java
tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/internal/util/Orderer.java
tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/services/ClassPropertyAdapter.java
tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/services/MethodIterator.java
tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/util/AbstractMessages.java
tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/util/UtilMessages.java
tapestry/tapestry5/tapestry-ioc/trunk/src/main/resources/org/apache/tapestry/ioc/util/UtilStrings.properties
tapestry/tapestry5/tapestry-ioc/trunk/src/site/apt/provider.apt
tapestry/tapestry5/tapestry-ioc/trunk/src/site/site.xml
tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/IntegrationTest.java
tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/internal/GlobPatternMatcherTest.java
tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/internal/services/MasterObjectProviderTest.java
tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/internal/services/PropertyAccessImplTest.java
tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/internal/util/MessagesImplTest.java
tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/internal/util/OrdererTest.java
Modified: tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/RegistryBuilder.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/RegistryBuilder.java?view=diff&rev=505796&r1=505795&r2=505796
==============================================================================
--- tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/RegistryBuilder.java (original)
+++ tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/RegistryBuilder.java Sat Feb 10 15:43:27 2007
@@ -14,6 +14,10 @@
package org.apache.tapestry.ioc;
+import static org.apache.tapestry.ioc.internal.util.CollectionFactory.newCaseInsensitiveMap;
+import static org.apache.tapestry.ioc.internal.util.CollectionFactory.newList;
+import static org.apache.tapestry.ioc.internal.util.CollectionFactory.newMap;
+
import java.lang.reflect.AnnotatedElement;
import java.util.Arrays;
import java.util.List;
@@ -29,9 +33,6 @@
import org.apache.tapestry.ioc.internal.util.OneShotLock;
import org.apache.tapestry.ioc.services.TapestryIOCModule;
-import static org.apache.tapestry.ioc.internal.util.CollectionFactory.newList;
-import static org.apache.tapestry.ioc.internal.util.CollectionFactory.newMap;
-
/**
* Used to construct the IoC {@link org.apache.tapestry.ioc.Registry}. This class is <em>not</em>
* threadsafe. The Registry, once created, <em>is</em> threadsafe.
@@ -41,7 +42,7 @@
private final OneShotLock _lock = new OneShotLock();
/** Module defs, keyed on module id. */
- final Map<String, ModuleDef> _modules = newMap();
+ final Map<String, ModuleDef> _modules = newCaseInsensitiveMap();
/**
* Service implementation overrides, keyed on service id. Service implementations are most
@@ -49,7 +50,7 @@
* have to stop at a certain "bounary" services by provide stub/ mock objects as their
* implementations.
*/
- private final Map<String, Object> _serviceOverrides = newMap();
+ private final Map<String, Object> _serviceOverrides = newCaseInsensitiveMap();
private final ClassLoader _classLoader;
Modified: tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/internal/DefaultModuleDefImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/internal/DefaultModuleDefImpl.java?view=diff&rev=505796&r1=505795&r2=505796
==============================================================================
--- tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/internal/DefaultModuleDefImpl.java (original)
+++ tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/internal/DefaultModuleDefImpl.java Sat Feb 10 15:43:27 2007
@@ -21,6 +21,7 @@
import static org.apache.tapestry.ioc.internal.IOCMessages.buildMethodConflict;
import static org.apache.tapestry.ioc.internal.IOCMessages.buildMethodWrongReturnType;
import static org.apache.tapestry.ioc.internal.IOCMessages.decoratorMethodWrongReturnType;
+import static org.apache.tapestry.ioc.internal.util.CollectionFactory.newCaseInsensitiveMap;
import static org.apache.tapestry.ioc.internal.util.CollectionFactory.newMap;
import static org.apache.tapestry.ioc.internal.util.CollectionFactory.newSet;
@@ -49,6 +50,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.internal.util.CollectionFactory;
/**
* Starting from the Class for a module builder, identifies all the services (service builder
@@ -73,10 +75,10 @@
private final Log _log;
/** Keyed on fully qualified service id. */
- private final Map<String, ServiceDef> _serviceDefs = newMap();
+ private final Map<String, ServiceDef> _serviceDefs = newCaseInsensitiveMap();
/** Keyed on fully qualified decorator id. */
- private final Map<String, DecoratorDef> _decoratorDefs = newMap();
+ private final Map<String, DecoratorDef> _decoratorDefs = newCaseInsensitiveMap();
private final Set<ContributionDef> _contributionDefs = newSet();
Modified: tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/internal/GlobPatternMatcher.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/internal/GlobPatternMatcher.java?view=diff&rev=505796&r1=505795&r2=505796
==============================================================================
--- tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/internal/GlobPatternMatcher.java (original)
+++ tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/internal/GlobPatternMatcher.java Sat Feb 10 15:43:27 2007
@@ -75,19 +75,24 @@
case EXACT:
- return input.equals(_substring);
+ return input.equalsIgnoreCase(_substring);
case INFIX:
- return input.contains(_substring);
+ return input.toLowerCase().contains(_substring.toLowerCase());
case PREFIX:
- return input.startsWith(_substring);
+ return input.regionMatches(true, 0, _substring, 0, _substring.length());
default:
- return input.endsWith(_substring);
+ return input.regionMatches(
+ true,
+ input.length() - _substring.length(),
+ _substring,
+ 0,
+ _substring.length());
}
}
}
Modified: tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/internal/ModuleImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/internal/ModuleImpl.java?view=diff&rev=505796&r1=505795&r2=505796
==============================================================================
--- tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/internal/ModuleImpl.java (original)
+++ tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/internal/ModuleImpl.java Sat Feb 10 15:43:27 2007
@@ -12,456 +12,449 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package org.apache.tapestry.ioc.internal;
-
-import static java.lang.String.format;
+package org.apache.tapestry.ioc.internal;
+
+import static java.lang.String.format;
+import static org.apache.tapestry.ioc.internal.util.CollectionFactory.newCaseInsensitiveMap;
import static org.apache.tapestry.ioc.internal.util.CollectionFactory.newList;
import static org.apache.tapestry.ioc.internal.util.CollectionFactory.newMap;
import static org.apache.tapestry.ioc.internal.util.CollectionFactory.newSet;
import static org.apache.tapestry.ioc.internal.util.Defense.notBlank;
import static org.apache.tapestry.ioc.internal.util.Defense.notNull;
-
-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;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import org.apache.commons.logging.Log;
-import org.apache.tapestry.ioc.ObjectCreator;
-import org.apache.tapestry.ioc.ServiceBuilderResources;
-import org.apache.tapestry.ioc.ServiceDecorator;
-import org.apache.tapestry.ioc.ServiceLifecycle;
-import org.apache.tapestry.ioc.ServiceLocator;
-import org.apache.tapestry.ioc.ServiceResources;
-import org.apache.tapestry.ioc.def.ContributionDef;
-import org.apache.tapestry.ioc.def.DecoratorDef;
-import org.apache.tapestry.ioc.def.ModuleDef;
-import org.apache.tapestry.ioc.def.ServiceDef;
+
+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;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.commons.logging.Log;
+import org.apache.tapestry.ioc.ObjectCreator;
+import org.apache.tapestry.ioc.ServiceBuilderResources;
+import org.apache.tapestry.ioc.ServiceDecorator;
+import org.apache.tapestry.ioc.ServiceLifecycle;
+import org.apache.tapestry.ioc.ServiceLocator;
+import org.apache.tapestry.ioc.ServiceResources;
+import org.apache.tapestry.ioc.def.ContributionDef;
+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.internal.util.InternalUtils;
-import org.apache.tapestry.ioc.services.ClassFab;
-import org.apache.tapestry.ioc.services.MethodSignature;
-import org.apache.tapestry.ioc.services.RegistryShutdownListener;
+import org.apache.tapestry.ioc.services.ClassFab;
+import org.apache.tapestry.ioc.services.MethodSignature;
+import org.apache.tapestry.ioc.services.RegistryShutdownListener;
import org.apache.tapestry.ioc.util.BodyBuilder;
-
-/**
- *
- */
-public class ModuleImpl implements Module
-{
- private final InternalRegistry _registry;
-
- private final ModuleDef _moduleDef;
-
- private final Log _log;
-
- private Object _moduleBuilder;
-
- private final static String INTERNAL_MODULE_ID = "tapestry.ioc";
-
- // Set to true when invoking the module constructor. Used to
- // detect endless loops caused by irresponsible dependencies into
- // the constructor.
-
- private boolean _insideConstructor;
-
- public ModuleImpl(InternalRegistry registry, ModuleDef moduleDef, Log log)
- {
- _registry = registry;
- _moduleDef = moduleDef;
- _log = log;
- }
-
- /** Keyed on fully qualified service id; values are instantiated services (proxies). */
- private final Map<String, Object> _services = newMap();
-
- public <T> T getService(String serviceId, Class<T> serviceInterface, Module module)
- {
- notBlank(serviceId, "serviceId");
- notNull(serviceInterface, "serviceInterface");
- // module may be null.
-
- ServiceDef def = _moduleDef.getServiceDef(serviceId);
-
- if (def == null)
- throw new IllegalArgumentException(IOCMessages.missingService(serviceId));
-
- if (notVisible(def, module))
- throw new RuntimeException(IOCMessages.serviceIsPrivate(serviceId));
-
- Object service = findOrCreate(def);
-
- try
- {
- return serviceInterface.cast(service);
- }
- catch (ClassCastException ex)
- {
- // This may be overkill: I don't know how this could happen
- // given that the return type of the method determines
- // the service interface.
-
- throw new RuntimeException(IOCMessages.serviceWrongInterface(serviceId, def
- .getServiceInterface(), serviceInterface));
- }
- }
-
- public Set<DecoratorDef> findMatchingDecoratorDefs(ServiceDef serviceDef)
- {
- Set<DecoratorDef> result = newSet();
-
- for (DecoratorDef def : _moduleDef.getDecoratorDefs())
- {
- if (def.matches(serviceDef))
- result.add(def);
- }
-
- return result;
- }
-
- private boolean notVisible(ServiceDef def, Module module)
- {
- return def.isPrivate() && this != module;
- }
-
- public List<ServiceDecorator> findDecoratorsForService(String serviceId)
- {
- ServiceDef sd = _moduleDef.getServiceDef(serviceId);
-
- return _registry.findDecoratorsForService(sd);
- }
-
- public Collection<String> findServiceIdsForInterface(Class serviceInterface, Module module)
- {
- notNull(serviceInterface, "serviceInterface");
-
- Collection<String> result = newList();
-
- for (String id : _moduleDef.getServiceIds())
- {
- ServiceDef def = _moduleDef.getServiceDef(id);
-
- if (def.getServiceInterface() != serviceInterface)
- continue;
-
- if (notVisible(def, module))
- continue;
-
- result.add(id);
- }
-
- return result;
- }
-
- // Why synchronized here? Two reasons. First, with some lifecycle models (or perhaps in some
- // scenarios using interceptors), we may try to acquire the write lock a second time and the
- // @Concurrent.Write annotation doesn't currently support that. Second, I'm concerned about
- // multiple threads building services simultaneously, and getting into a thread deadlock. Of
- // course, this isn't a solution for that ... we may need a global mutex to handle that specific
- // case! Alternately, I've thought about creating a "service creation" thread at startup and
- // queuing service creation requests to that thread, and blocking the local thread.
-
- private synchronized Object findOrCreate(ServiceDef def)
- {
- String key = def.getServiceId();
-
- Object result = _services.get(key);
-
- if (result == null)
- {
- result = create(def);
- _services.put(key, result);
- }
-
- return result;
- }
-
- public void eagerLoadServices()
- {
- for (String id : _moduleDef.getServiceIds())
- {
- ServiceDef def = _moduleDef.getServiceDef(id);
-
- if (!def.isEagerLoad())
- continue;
-
- // The proxy implements the service interface, and RegistryShutdownListener, and (for
- // eager load services), EagerLoadServiceProxy
-
- EagerLoadServiceProxy proxy = (EagerLoadServiceProxy) findOrCreate(def);
-
- proxy.eagerLoadService();
- }
- }
-
- /**
- * Creates the service and updates the cache of created services. Method is called from
- * synchronized block.
- */
- private Object create(ServiceDef def)
- {
- String serviceId = def.getServiceId();
-
- Log log = _registry.getLog(serviceId);
-
- if (log.isDebugEnabled())
- log.debug(IOCMessages.creatingService(serviceId));
-
- try
- {
- ServiceLifecycle lifecycle = _registry.getServiceLifecycle(def.getServiceLifeycle());
-
- ServiceBuilderResources 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).
-
- ObjectCreator creator = def.createServiceCreator(resources);
-
- creator = new LifecycleWrappedServiceCreator(lifecycle, resources, creator);
-
- // Don't allow the tapestry.ioc services to be decorated.
-
- if (!getModuleId().equals(INTERNAL_MODULE_ID))
- creator = new InterceptorStackBuilder(this, serviceId, creator);
-
- // Add a wrapper that makes sure that it only gets created once.
-
- creator = new OneShotServiceCreator(def, creator);
-
- Object service = createProxy(resources, creator, def.isEagerLoad());
-
- _services.put(serviceId, service);
-
- return service;
- }
- catch (Exception ex)
- {
- throw new RuntimeException(IOCMessages.errorBuildingService(serviceId, def, ex), ex);
- }
- }
-
- public synchronized Object getModuleBuilder()
- {
- if (_moduleBuilder == null)
- _moduleBuilder = instantiateModuleBuilder();
-
- return _moduleBuilder;
- }
-
- private Object instantiateModuleBuilder()
- {
- Class builderClass = _moduleDef.getBuilderClass();
-
- Constructor[] constructors = builderClass.getConstructors();
-
- if (constructors.length == 0)
- throw new RuntimeException(IOCMessages.noPublicConstructors(
- _moduleDef.getModuleId(),
- builderClass));
-
- if (constructors.length > 1)
- {
- // Sort the constructors ascending by number of parameters (descending); this is really
- // just to allow the test suite to work properly across different JVMs (which will
- // often order the constructors differently).
-
- Comparator<Constructor> comparator = new Comparator<Constructor>()
- {
- public int compare(Constructor c1, Constructor c2)
- {
- return c2.getParameterTypes().length - c1.getParameterTypes().length;
- }
- };
-
- Arrays.sort(constructors, comparator);
-
- _log.warn(IOCMessages.tooManyPublicConstructors(
- _moduleDef.getModuleId(),
- builderClass,
- constructors[0]));
- }
-
- Constructor constructor = constructors[0];
-
- if (_insideConstructor)
- throw new RuntimeException(IOCMessages.recursiveModuleConstructor(_moduleDef
- .getModuleId(), builderClass, constructor));
-
- ServiceLocator locator = new ServiceLocatorImpl(_registry, this);
- Map<Class, Object> parameterDefaults = newMap();
-
- parameterDefaults.put(Log.class, _log);
- parameterDefaults.put(String.class, _moduleDef.getModuleId());
- parameterDefaults.put(ServiceLocator.class, locator);
-
- Throwable fail = null;
-
- try
- {
- _insideConstructor = true;
-
- Object[] parameterValues = InternalUtils.calculateParameters(
- locator,
- parameterDefaults,
- constructor.getParameterTypes(),
- constructor.getParameterAnnotations());
-
- return constructor.newInstance(parameterValues);
- }
- catch (InvocationTargetException ex)
- {
- fail = ex.getTargetException();
- }
- catch (Exception ex)
- {
- fail = ex;
- }
- finally
- {
- _insideConstructor = false;
- }
-
- throw new RuntimeException(IOCMessages.instantiateBuilderError(builderClass, _moduleDef
- .getModuleId(), fail), fail);
- }
-
- private Object createProxy(ServiceResources resources, ObjectCreator creator, boolean eagerLoad)
- {
- String serviceId = resources.getServiceId();
- Class serviceInterface = resources.getServiceInterface();
-
- String toString = format("<Proxy for %s(%s)>", serviceId, serviceInterface.getName());
-
- RegistryShutdownListener proxy = createProxyInstance(
- creator,
- serviceId,
- serviceInterface,
- eagerLoad,
- toString);
-
- _registry.addRegistryShutdownListener(proxy);
-
- return proxy;
- }
-
- private RegistryShutdownListener createProxyInstance(ObjectCreator creator, String serviceId,
- Class serviceInterface, boolean eagerLoad, String description)
- {
- Class proxyClass = createProxyClass(serviceId, serviceInterface, eagerLoad, description);
-
- try
- {
- return (RegistryShutdownListener) 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, boolean eagerLoad,
- String proxyDescription)
- {
- ClassFab cf = _registry.newClass(serviceInterface);
-
- cf.addField("_creator", ObjectCreator.class);
- cf.addField("_delegate", serviceInterface);
- cf.addField("_shutdown", boolean.class);
-
- cf.addConstructor(new Class[]
- { ObjectCreator.class }, null, "_creator = $1;");
-
- addDelegateGetter(cf, serviceInterface, serviceId);
-
- addShutdownListenerMethod(cf);
-
- cf.proxyMethodsToDelegate(serviceInterface, "_delegate()", proxyDescription);
-
- // For eager load services, add an eagerLoadService() method that calls _delegate(), to
- // force the creation of the service.
-
- if (eagerLoad)
- {
- cf.addInterface(EagerLoadServiceProxy.class);
-
- cf.addMethod(Modifier.PUBLIC, new MethodSignature(void.class, "eagerLoadService", null,
- null), "_delegate();");
- }
-
- return cf.createClass();
- }
-
- private void addDelegateGetter(ClassFab cf, Class serviceInterface, String serviceId)
- {
- BodyBuilder builder = new BodyBuilder();
- builder.begin();
-
- // Check to see if the registry has shutdown. The registryShutdown() method
- // throws IllegalStateException.
-
- builder.addln("if (_shutdown) %s.registryShutdown(\"%s\");", IOCProxyUtilities.class
- .getName(), serviceId);
-
- // We can release the creator after invoking it, we only create the service once.
-
- builder.addln("if (_delegate == null)");
- builder.begin();
- builder.addln("_delegate = (%s) _creator.createObject();", serviceInterface.getName());
- builder.addln("_creator = null;");
- builder.end();
-
- builder.addln("return _delegate;");
- builder.end();
-
- MethodSignature sig = new MethodSignature(serviceInterface, "_delegate", null, null);
-
- // Here's the rub, this _delegate() method has to be synchronized. But after the first
- // time through (when we create the service), the time inside the method is infintesmal.
- // Let's hope that they aren't lying when they say that synchronized is now super cheap!
-
- cf.addMethod(Modifier.PRIVATE | Modifier.SYNCHRONIZED, sig, builder.toString());
- }
-
- /**
- * All proxies implement {@link RegistryShutdownListener}. When the registry shuts down, the
- * proxy sets a flag that ultimately converts method invocations to
- * {@link IllegalStateException}s, and discards its delegate and creator.
- */
- private void addShutdownListenerMethod(ClassFab cf)
- {
- cf.addInterface(RegistryShutdownListener.class);
-
- MethodSignature sig = new MethodSignature(void.class, "registryDidShutdown", null, null);
-
- cf.addMethod(
- Modifier.PUBLIC | Modifier.SYNCHRONIZED,
- sig,
- "{ _shutdown = true; _delegate = null; _creator = null; }");
- }
-
- public String getModuleId()
- {
- return _moduleDef.getModuleId();
- }
-
- public Set<ContributionDef> getContributorDefsForService(String serviceId)
- {
- Set<ContributionDef> result = newSet();
-
- for (ContributionDef def : _moduleDef.getContributionDefs())
- {
- if (def.getServiceId().equals(serviceId))
- result.add(def);
- }
-
- return result;
- }
-
-}
+
+/**
+ *
+ */
+public class ModuleImpl implements Module
+{
+ private final InternalRegistry _registry;
+
+ private final ModuleDef _moduleDef;
+
+ private final Log _log;
+
+ private Object _moduleBuilder;
+
+ private final static String INTERNAL_MODULE_ID = "tapestry.ioc";
+
+ // Set to true when invoking the module constructor. Used to
+ // detect endless loops caused by irresponsible dependencies into
+ // the constructor.
+
+ private boolean _insideConstructor;
+
+ public ModuleImpl(InternalRegistry registry, ModuleDef moduleDef, Log log)
+ {
+ _registry = registry;
+ _moduleDef = moduleDef;
+ _log = log;
+ }
+
+ /** Keyed on fully qualified service id; values are instantiated services (proxies). */
+ private final Map<String, Object> _services = newCaseInsensitiveMap();
+
+ public <T> T getService(String serviceId, Class<T> serviceInterface, Module module)
+ {
+ notBlank(serviceId, "serviceId");
+ notNull(serviceInterface, "serviceInterface");
+ // module may be null.
+
+ ServiceDef def = _moduleDef.getServiceDef(serviceId);
+
+ if (def == null) throw new IllegalArgumentException(IOCMessages.missingService(serviceId));
+
+ if (notVisible(def, module))
+ throw new RuntimeException(IOCMessages.serviceIsPrivate(serviceId));
+
+ Object service = findOrCreate(def);
+
+ try
+ {
+ return serviceInterface.cast(service);
+ }
+ catch (ClassCastException ex)
+ {
+ // This may be overkill: I don't know how this could happen
+ // given that the return type of the method determines
+ // the service interface.
+
+ throw new RuntimeException(IOCMessages.serviceWrongInterface(serviceId, def
+ .getServiceInterface(), serviceInterface));
+ }
+ }
+
+ public Set<DecoratorDef> findMatchingDecoratorDefs(ServiceDef serviceDef)
+ {
+ Set<DecoratorDef> result = newSet();
+
+ for (DecoratorDef def : _moduleDef.getDecoratorDefs())
+ {
+ if (def.matches(serviceDef)) result.add(def);
+ }
+
+ return result;
+ }
+
+ private boolean notVisible(ServiceDef def, Module module)
+ {
+ return def.isPrivate() && this != module;
+ }
+
+ public List<ServiceDecorator> findDecoratorsForService(String serviceId)
+ {
+ ServiceDef sd = _moduleDef.getServiceDef(serviceId);
+
+ return _registry.findDecoratorsForService(sd);
+ }
+
+ public Collection<String> findServiceIdsForInterface(Class serviceInterface, Module module)
+ {
+ notNull(serviceInterface, "serviceInterface");
+
+ Collection<String> result = newList();
+
+ for (String id : _moduleDef.getServiceIds())
+ {
+ ServiceDef def = _moduleDef.getServiceDef(id);
+
+ if (def.getServiceInterface() != serviceInterface) continue;
+
+ if (notVisible(def, module)) continue;
+
+ result.add(id);
+ }
+
+ return result;
+ }
+
+ // Why synchronized here? Two reasons. First, with some lifecycle models (or perhaps in some
+ // scenarios using interceptors), we may try to acquire the write lock a second time and the
+ // @Concurrent.Write annotation doesn't currently support that. Second, I'm concerned about
+ // multiple threads building services simultaneously, and getting into a thread deadlock. Of
+ // course, this isn't a solution for that ... we may need a global mutex to handle that specific
+ // case! Alternately, I've thought about creating a "service creation" thread at startup and
+ // queuing service creation requests to that thread, and blocking the local thread.
+
+ private synchronized Object findOrCreate(ServiceDef def)
+ {
+ String key = def.getServiceId();
+
+ Object result = _services.get(key);
+
+ if (result == null)
+ {
+ result = create(def);
+ _services.put(key, result);
+ }
+
+ return result;
+ }
+
+ public void eagerLoadServices()
+ {
+ for (String id : _moduleDef.getServiceIds())
+ {
+ ServiceDef def = _moduleDef.getServiceDef(id);
+
+ if (!def.isEagerLoad()) continue;
+
+ // The proxy implements the service interface, and RegistryShutdownListener, and (for
+ // eager load services), EagerLoadServiceProxy
+
+ EagerLoadServiceProxy proxy = (EagerLoadServiceProxy) findOrCreate(def);
+
+ proxy.eagerLoadService();
+ }
+ }
+
+ /**
+ * Creates the service and updates the cache of created services. Method is called from
+ * synchronized block.
+ */
+ private Object create(ServiceDef def)
+ {
+ String serviceId = def.getServiceId();
+
+ Log log = _registry.getLog(serviceId);
+
+ if (log.isDebugEnabled()) log.debug(IOCMessages.creatingService(serviceId));
+
+ try
+ {
+ ServiceLifecycle lifecycle = _registry.getServiceLifecycle(def.getServiceLifeycle());
+
+ ServiceBuilderResources 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).
+
+ ObjectCreator creator = def.createServiceCreator(resources);
+
+ creator = new LifecycleWrappedServiceCreator(lifecycle, resources, creator);
+
+ // Don't allow the tapestry.ioc services to be decorated.
+
+ if (!getModuleId().equals(INTERNAL_MODULE_ID))
+ creator = new InterceptorStackBuilder(this, serviceId, creator);
+
+ // Add a wrapper that makes sure that it only gets created once.
+
+ creator = new OneShotServiceCreator(def, creator);
+
+ Object service = createProxy(resources, creator, def.isEagerLoad());
+
+ _services.put(serviceId, service);
+
+ return service;
+ }
+ catch (Exception ex)
+ {
+ throw new RuntimeException(IOCMessages.errorBuildingService(serviceId, def, ex), ex);
+ }
+ }
+
+ public synchronized Object getModuleBuilder()
+ {
+ if (_moduleBuilder == null) _moduleBuilder = instantiateModuleBuilder();
+
+ return _moduleBuilder;
+ }
+
+ private Object instantiateModuleBuilder()
+ {
+ Class builderClass = _moduleDef.getBuilderClass();
+
+ Constructor[] constructors = builderClass.getConstructors();
+
+ if (constructors.length == 0)
+ throw new RuntimeException(IOCMessages.noPublicConstructors(
+ _moduleDef.getModuleId(),
+ builderClass));
+
+ if (constructors.length > 1)
+ {
+ // Sort the constructors ascending by number of parameters (descending); this is really
+ // just to allow the test suite to work properly across different JVMs (which will
+ // often order the constructors differently).
+
+ Comparator<Constructor> comparator = new Comparator<Constructor>()
+ {
+ public int compare(Constructor c1, Constructor c2)
+ {
+ return c2.getParameterTypes().length - c1.getParameterTypes().length;
+ }
+ };
+
+ Arrays.sort(constructors, comparator);
+
+ _log.warn(IOCMessages.tooManyPublicConstructors(
+ _moduleDef.getModuleId(),
+ builderClass,
+ constructors[0]));
+ }
+
+ Constructor constructor = constructors[0];
+
+ if (_insideConstructor)
+ throw new RuntimeException(IOCMessages.recursiveModuleConstructor(_moduleDef
+ .getModuleId(), builderClass, constructor));
+
+ ServiceLocator locator = new ServiceLocatorImpl(_registry, this);
+ Map<Class, Object> parameterDefaults = newMap();
+
+ parameterDefaults.put(Log.class, _log);
+ parameterDefaults.put(String.class, _moduleDef.getModuleId());
+ parameterDefaults.put(ServiceLocator.class, locator);
+
+ Throwable fail = null;
+
+ try
+ {
+ _insideConstructor = true;
+
+ Object[] parameterValues = InternalUtils.calculateParameters(
+ locator,
+ parameterDefaults,
+ constructor.getParameterTypes(),
+ constructor.getParameterAnnotations());
+
+ return constructor.newInstance(parameterValues);
+ }
+ catch (InvocationTargetException ex)
+ {
+ fail = ex.getTargetException();
+ }
+ catch (Exception ex)
+ {
+ fail = ex;
+ }
+ finally
+ {
+ _insideConstructor = false;
+ }
+
+ throw new RuntimeException(IOCMessages.instantiateBuilderError(builderClass, _moduleDef
+ .getModuleId(), fail), fail);
+ }
+
+ private Object createProxy(ServiceResources resources, ObjectCreator creator, boolean eagerLoad)
+ {
+ String serviceId = resources.getServiceId();
+ Class serviceInterface = resources.getServiceInterface();
+
+ String toString = format("<Proxy for %s(%s)>", serviceId, serviceInterface.getName());
+
+ RegistryShutdownListener proxy = createProxyInstance(
+ creator,
+ serviceId,
+ serviceInterface,
+ eagerLoad,
+ toString);
+
+ _registry.addRegistryShutdownListener(proxy);
+
+ return proxy;
+ }
+
+ private RegistryShutdownListener createProxyInstance(ObjectCreator creator, String serviceId,
+ Class serviceInterface, boolean eagerLoad, String description)
+ {
+ Class proxyClass = createProxyClass(serviceId, serviceInterface, eagerLoad, description);
+
+ try
+ {
+ return (RegistryShutdownListener) 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, boolean eagerLoad,
+ String proxyDescription)
+ {
+ ClassFab cf = _registry.newClass(serviceInterface);
+
+ cf.addField("_creator", ObjectCreator.class);
+ cf.addField("_delegate", serviceInterface);
+ cf.addField("_shutdown", boolean.class);
+
+ cf.addConstructor(new Class[]
+ { ObjectCreator.class }, null, "_creator = $1;");
+
+ addDelegateGetter(cf, serviceInterface, serviceId);
+
+ addShutdownListenerMethod(cf);
+
+ cf.proxyMethodsToDelegate(serviceInterface, "_delegate()", proxyDescription);
+
+ // For eager load services, add an eagerLoadService() method that calls _delegate(), to
+ // force the creation of the service.
+
+ if (eagerLoad)
+ {
+ cf.addInterface(EagerLoadServiceProxy.class);
+
+ cf.addMethod(Modifier.PUBLIC, new MethodSignature(void.class, "eagerLoadService", null,
+ null), "_delegate();");
+ }
+
+ return cf.createClass();
+ }
+
+ private void addDelegateGetter(ClassFab cf, Class serviceInterface, String serviceId)
+ {
+ BodyBuilder builder = new BodyBuilder();
+ builder.begin();
+
+ // Check to see if the registry has shutdown. The registryShutdown() method
+ // throws IllegalStateException.
+
+ builder.addln("if (_shutdown) %s.registryShutdown(\"%s\");", IOCProxyUtilities.class
+ .getName(), serviceId);
+
+ // We can release the creator after invoking it, we only create the service once.
+
+ builder.addln("if (_delegate == null)");
+ builder.begin();
+ builder.addln("_delegate = (%s) _creator.createObject();", serviceInterface.getName());
+ builder.addln("_creator = null;");
+ builder.end();
+
+ builder.addln("return _delegate;");
+ builder.end();
+
+ MethodSignature sig = new MethodSignature(serviceInterface, "_delegate", null, null);
+
+ // Here's the rub, this _delegate() method has to be synchronized. But after the first
+ // time through (when we create the service), the time inside the method is infintesmal.
+ // Let's hope that they aren't lying when they say that synchronized is now super cheap!
+
+ cf.addMethod(Modifier.PRIVATE | Modifier.SYNCHRONIZED, sig, builder.toString());
+ }
+
+ /**
+ * All proxies implement {@link RegistryShutdownListener}. When the registry shuts down, the
+ * proxy sets a flag that ultimately converts method invocations to
+ * {@link IllegalStateException}s, and discards its delegate and creator.
+ */
+ private void addShutdownListenerMethod(ClassFab cf)
+ {
+ cf.addInterface(RegistryShutdownListener.class);
+
+ MethodSignature sig = new MethodSignature(void.class, "registryDidShutdown", null, null);
+
+ cf.addMethod(
+ Modifier.PUBLIC | Modifier.SYNCHRONIZED,
+ sig,
+ "{ _shutdown = true; _delegate = null; _creator = null; }");
+ }
+
+ public String getModuleId()
+ {
+ return _moduleDef.getModuleId();
+ }
+
+ public Set<ContributionDef> getContributorDefsForService(String serviceId)
+ {
+ Set<ContributionDef> result = newSet();
+
+ for (ContributionDef def : _moduleDef.getContributionDefs())
+ {
+ if (def.getServiceId().equals(serviceId)) result.add(def);
+ }
+
+ return result;
+ }
+
+}
Modified: tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/internal/RegistryImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/internal/RegistryImpl.java?view=diff&rev=505796&r1=505795&r2=505796
==============================================================================
--- tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/internal/RegistryImpl.java (original)
+++ tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/internal/RegistryImpl.java Sat Feb 10 15:43:27 2007
@@ -14,6 +14,7 @@
package org.apache.tapestry.ioc.internal;
+import static org.apache.tapestry.ioc.internal.util.CollectionFactory.newCaseInsensitiveMap;
import static org.apache.tapestry.ioc.internal.util.CollectionFactory.newList;
import static org.apache.tapestry.ioc.internal.util.CollectionFactory.newMap;
@@ -75,18 +76,18 @@
private final OneShotLock _lock = new OneShotLock();
- private final Map<String, Object> _builtinServices = newMap();
+ private final Map<String, Object> _builtinServices = newCaseInsensitiveMap();
- private final Map<String, Class> _builtinTypes = newMap();
+ private final Map<String, Class> _builtinTypes = newCaseInsensitiveMap();
private final RegistryShutdownHubImpl _registryShutdownHub;
private final LogSource _logSource;
/** Keyed on module id. */
- private final Map<String, Module> _modules = newMap();
+ private final Map<String, Module> _modules = newCaseInsensitiveMap();
- private final Map<String, ServiceLifecycle> _lifecycles = newMap();
+ private final Map<String, ServiceLifecycle> _lifecycles = newCaseInsensitiveMap();
/**
* Service implementation overrides, keyed on service id. Service implementations are most
Modified: tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/internal/services/AbstractFab.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/internal/services/AbstractFab.java?view=diff&rev=505796&r1=505795&r2=505796
==============================================================================
--- tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/internal/services/AbstractFab.java (original)
+++ tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/internal/services/AbstractFab.java Sat Feb 10 15:43:27 2007
@@ -59,8 +59,7 @@
try
{
for (CtClass existing : _ctClass.getInterfaces())
- if (existing == ctInterfaceClass)
- return;
+ if (existing == ctInterfaceClass) return;
}
catch (Exception ex)
{
@@ -72,8 +71,7 @@
protected CtClass[] convertClasses(Class[] inputClasses)
{
- if (inputClasses == null || inputClasses.length == 0)
- return null;
+ if (inputClasses == null || inputClasses.length == 0) return null;
int count = inputClasses.length;
CtClass[] result = new CtClass[count];
@@ -105,8 +103,7 @@
{
_lock.lock();
- if (_log.isDebugEnabled())
- _log.debug(String.format("Creating class from %s", this));
+ if (_log.isDebugEnabled()) _log.debug(String.format("Creating class from %s", this));
return _source.createClass(_ctClass);
}
Modified: tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/internal/services/ClassPropertyAdapterImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/internal/services/ClassPropertyAdapterImpl.java?view=diff&rev=505796&r1=505795&r2=505796
==============================================================================
--- tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/internal/services/ClassPropertyAdapterImpl.java (original)
+++ tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/internal/services/ClassPropertyAdapterImpl.java Sat Feb 10 15:43:27 2007
@@ -14,7 +14,7 @@
package org.apache.tapestry.ioc.internal.services;
-import static org.apache.tapestry.ioc.internal.util.CollectionFactory.newMap;
+import static org.apache.tapestry.ioc.internal.util.CollectionFactory.newCaseInsensitiveMap;
import java.beans.PropertyDescriptor;
import java.util.List;
@@ -26,7 +26,7 @@
public class ClassPropertyAdapterImpl implements ClassPropertyAdapter
{
- private final Map<String, PropertyAdapter> _adapters = newMap();
+ private final Map<String, PropertyAdapter> _adapters = newCaseInsensitiveMap();
private final Class _beanType;
Modified: tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/internal/services/MasterObjectProvider.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/internal/services/MasterObjectProvider.java?view=diff&rev=505796&r1=505795&r2=505796
==============================================================================
--- tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/internal/services/MasterObjectProvider.java (original)
+++ tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/internal/services/MasterObjectProvider.java Sat Feb 10 15:43:27 2007
@@ -18,6 +18,7 @@
import org.apache.tapestry.ioc.ObjectProvider;
import org.apache.tapestry.ioc.ServiceLocator;
+import org.apache.tapestry.ioc.internal.util.CollectionFactory;
import org.apache.tapestry.ioc.services.SymbolSource;
import org.apache.tapestry.ioc.services.TypeCoercer;
@@ -37,7 +38,8 @@
public MasterObjectProvider(Map<String, ObjectProvider> configuration,
SymbolSource symbolSource, TypeCoercer typeCoercer)
{
- _configuration = configuration;
+ _configuration = CollectionFactory.newCaseInsensitiveMap(configuration);
+
_symbolSource = symbolSource;
_typeCoercer = typeCoercer;
}
Modified: tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/internal/util/CollectionFactory.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/internal/util/CollectionFactory.java?view=diff&rev=505796&r1=505795&r2=505796
==============================================================================
--- tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/internal/util/CollectionFactory.java (original)
+++ tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/internal/util/CollectionFactory.java Sat Feb 10 15:43:27 2007
@@ -26,6 +26,9 @@
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
+import org.apache.tapestry.ioc.util.CaseInsensitiveMap;
+import org.apache.tapestry.ioc.util.Stack;
+
/**
* Static factory methods to ease the creation of new collection types (when using generics). Most
* of these method leverage the compiler's ability to match generic types by return value. Typical
@@ -119,5 +122,20 @@
public static <T> List<T> newThreadSafeList()
{
return new CopyOnWriteArrayList<T>();
+ }
+
+ public static <T> Stack<T> newStack()
+ {
+ return new Stack<T>();
+ }
+
+ public static <V> Map<String, V> newCaseInsensitiveMap()
+ {
+ return new CaseInsensitiveMap<V>();
+ }
+
+ public static <V> Map<String, V> newCaseInsensitiveMap(Map<String, ? extends V> map)
+ {
+ return new CaseInsensitiveMap<V>(map);
}
}
Modified: tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/internal/util/MessagesImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/internal/util/MessagesImpl.java?view=diff&rev=505796&r1=505795&r2=505796
==============================================================================
--- tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/internal/util/MessagesImpl.java (original)
+++ tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/internal/util/MessagesImpl.java Sat Feb 10 15:43:27 2007
@@ -14,7 +14,7 @@
package org.apache.tapestry.ioc.internal.util;
-import static org.apache.tapestry.ioc.internal.util.CollectionFactory.newMap;
+import static org.apache.tapestry.ioc.internal.util.CollectionFactory.newCaseInsensitiveMap;
import java.util.Enumeration;
import java.util.Locale;
@@ -30,7 +30,7 @@
*/
public class MessagesImpl extends AbstractMessages
{
- private final Map<String, String> _properties = newMap();
+ private final Map<String, String> _properties = newCaseInsensitiveMap();
/**
* Finds the messages for a given Messages utility class. Strings the trailing "Messages" and
Modified: tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/internal/util/Orderer.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/internal/util/Orderer.java?view=diff&rev=505796&r1=505795&r2=505796
==============================================================================
--- tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/internal/util/Orderer.java (original)
+++ tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/internal/util/Orderer.java Sat Feb 10 15:43:27 2007
@@ -14,8 +14,8 @@
package org.apache.tapestry.ioc.internal.util;
+import static org.apache.tapestry.ioc.internal.util.CollectionFactory.newCaseInsensitiveMap;
import static org.apache.tapestry.ioc.internal.util.CollectionFactory.newList;
-import static org.apache.tapestry.ioc.internal.util.CollectionFactory.newMap;
import java.util.Collection;
import java.util.List;
@@ -40,9 +40,9 @@
private final List<Orderable> _orderables = newList();
- private final Map<String, Orderable<T>> _orderablesById = newMap();
+ private final Map<String, Orderable<T>> _orderablesById = newCaseInsensitiveMap();
- private final Map<String, DependencyNode<T>> _dependencyNodesById = newMap();
+ private final Map<String, DependencyNode<T>> _dependencyNodesById = newCaseInsensitiveMap();
// Special node that is always dead last: all other nodes are a dependency
// of the trailer.
@@ -136,8 +136,7 @@
// Nulls are placeholders that are skipped.
- if (target != null)
- result.add(target);
+ if (target != null) result.add(target);
}
return result;
@@ -192,8 +191,7 @@
if ("after".equals(type))
linker = _after;
- else if ("before".equals(type))
- linker = _before;
+ else if ("before".equals(type)) linker = _before;
if (linker == null)
{
@@ -228,11 +226,9 @@
for (String id : _dependencyNodesById.keySet())
{
- if (sourceId.equals(id))
- continue;
+ if (sourceId.equals(id)) continue;
- if (matcher.matches(id))
- result.add(_dependencyNodesById.get(id));
+ if (matcher.matches(id)) result.add(_dependencyNodesById.get(id));
}
return result;
Modified: tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/services/ClassPropertyAdapter.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/services/ClassPropertyAdapter.java?view=diff&rev=505796&r1=505795&r2=505796
==============================================================================
--- tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/services/ClassPropertyAdapter.java (original)
+++ tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/services/ClassPropertyAdapter.java Sat Feb 10 15:43:27 2007
@@ -17,9 +17,11 @@
import java.util.List;
/**
- * Organizes all {@link org.apache.tapestry.ioc.services.PropertyAdapter}s for a particular class. *
+ * Organizes all {@link org.apache.tapestry.ioc.services.PropertyAdapter}s for a particular class.
* <p>
* Only provides access to <em>simple</em> properties. Indexed properties are ignored.
+ * <p>
+ * When acessing properties by name, the case of the name is ignored.
*/
public interface ClassPropertyAdapter
{
@@ -31,12 +33,19 @@
/**
* Returns the property adapter with the given name, or null if no such adapter exists.
+ *
+ * @param name
+ * of the property (case is ignored)
*/
PropertyAdapter getPropertyAdapter(String name);
/**
* Reads the value of a property.
*
+ * @param instance
+ * the object to read a value from
+ * @param propertyName
+ * the name of the property to read (case is ignored)
* @throws UnsupportedOperationException
* if the property is write only
* @throws IllegalArgumentException
@@ -45,8 +54,12 @@
Object get(Object instance, String propertyName);
/**
- * Updates the value of a property. *
+ * Updates the value of a property.
*
+ * @param instance
+ * the object to update
+ * @param propertyName
+ * the name of the property to update (case is ignored)
* @throws UnsupportedOperationException
* if the property is read only
* @throws IllegalArgumentException
Modified: tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/services/MethodIterator.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/services/MethodIterator.java?view=diff&rev=505796&r1=505795&r2=505796
==============================================================================
--- tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/services/MethodIterator.java (original)
+++ tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/services/MethodIterator.java Sat Feb 10 15:43:27 2007
@@ -28,7 +28,6 @@
* method from multiple interfaces and with slightly different signatures (due to the fact that
* declared thrown exceptions can vary slightly for the "same" method).
*
- * @author Howard Lewis Ship
* @see org.apache.tapestry.ioc.services.MethodSignature#isOverridingSignatureOf(MethodSignature)
*/
public class MethodIterator
@@ -54,7 +53,6 @@
_count = _signatures.size();
}
- /** @since 1.1 */
private void processMethod(Method m, Map<String, MethodSignature> map)
{
_toString |= ClassFabUtils.isToString(m);
@@ -64,8 +62,7 @@
MethodSignature existing = map.get(uid);
- if (existing == null || sig.isOverridingSignatureOf(existing))
- map.put(uid, sig);
+ if (existing == null || sig.isOverridingSignatureOf(existing)) map.put(uid, sig);
}
public boolean hasNext()
@@ -84,8 +81,7 @@
*/
public MethodSignature next()
{
- if (_index >= _count)
- throw new NoSuchElementException();
+ if (_index >= _count) throw new NoSuchElementException();
return _signatures.get(_index++);
}
Modified: tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/util/AbstractMessages.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/util/AbstractMessages.java?view=diff&rev=505796&r1=505795&r2=505796
==============================================================================
--- tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/util/AbstractMessages.java (original)
+++ tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/util/AbstractMessages.java Sat Feb 10 15:43:27 2007
@@ -14,12 +14,14 @@
package org.apache.tapestry.ioc.util;
-import static org.apache.tapestry.ioc.internal.util.CollectionFactory.newThreadSafeMap;
+import static org.apache.tapestry.ioc.internal.util.CollectionFactory.newCaseInsensitiveMap;
import java.util.Map;
import org.apache.tapestry.ioc.MessageFormatter;
import org.apache.tapestry.ioc.Messages;
+import org.apache.tapestry.ioc.internal.util.ConcurrentBarrier;
+import org.apache.tapestry.ioc.internal.util.Invokable;
import org.apache.tapestry.ioc.internal.util.MessageFormatterImpl;
/**
@@ -28,15 +30,17 @@
*/
public abstract class AbstractMessages implements Messages
{
+ private final ConcurrentBarrier _barrier = new ConcurrentBarrier();
+
/** String key to MF instance. */
- private Map<String, MessageFormatter> _cache = newThreadSafeMap();
+ private final Map<String, MessageFormatter> _cache = newCaseInsensitiveMap();
/**
* Invoked to provide the value for a particular key. This may be invoked multiple times even
- * for the same key.
+ * for the same key. The implementation should <em>ignore the case of the key</em>.
*
* @param key
- * the key to obtain a value for
+ * the key to obtain a value for (case insensitive)
* @return the value for the key, or null if this instance can not provide the value
*/
protected abstract String valueForKey(String key);
@@ -53,17 +57,29 @@
return String.format("[[missing key: %s]]", key);
}
- public MessageFormatter getFormatter(String key)
+ public MessageFormatter getFormatter(final String key)
{
- MessageFormatter result = _cache.get(key);
+ MessageFormatter result = _barrier.withRead(new Invokable<MessageFormatter>()
+ {
+ public MessageFormatter invoke()
+ {
+ return _cache.get(key);
+ }
+ });
+
+ if (result != null) return result;
+
+ final MessageFormatter newFormatter = buildMessageFormatter(key);
- if (result == null)
+ _barrier.withWrite(new Runnable()
{
- result = buildMessageFormatter(key);
- _cache.put(key, result);
- }
+ public void run()
+ {
+ _cache.put(key, newFormatter);
+ };
+ });
- return result;
+ return newFormatter;
}
private MessageFormatter buildMessageFormatter(String key)
Added: tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/util/CaseInsensitiveMap.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/util/CaseInsensitiveMap.java?view=auto&rev=505796
==============================================================================
--- tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/util/CaseInsensitiveMap.java (added)
+++ tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/util/CaseInsensitiveMap.java Sat Feb 10 15:43:27 2007
@@ -0,0 +1,479 @@
+// 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.util;
+
+import java.util.AbstractMap;
+import java.util.AbstractSet;
+import java.util.ConcurrentModificationException;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.Set;
+
+/**
+ * An mapped collection where the keys are always strings and access to values is case-insensitive.
+ * The case of keys in the map is <em>maintained</em>, but on any access to a key (directly or
+ * indirectly), all key comparisons are performed in a case-insensitive manner. The map
+ * implementation is intended to support a reasonably finite number (dozens or hundreds, not
+ * thousands or millions of key/value pairs. Unlike HashMap, it is based on a sorted list of entries
+ * rather than hash bucket. It is also geared towards a largely static map, one that is created and
+ * then used without modification.
+ *
+ * @param <V>
+ * the type of value stored
+ */
+public class CaseInsensitiveMap<V> extends AbstractMap<String, V> implements Map<String, V>
+{
+ private static final int NULL_HASH = Integer.MIN_VALUE;
+
+ private static final int DEFAULT_SIZE = 20;
+
+ private static class CIMEntry<V> implements Map.Entry<String, V>
+ {
+ private String _key;
+
+ private final int _hashCode;
+
+ V _value;
+
+ public CIMEntry(final String key, final int hashCode, V value)
+ {
+ _key = key;
+ _hashCode = hashCode;
+ _value = value;
+ }
+
+ public String getKey()
+ {
+ return _key;
+ }
+
+ public V getValue()
+ {
+ return _value;
+ }
+
+ public V setValue(V value)
+ {
+ V result = _value;
+
+ _value = value;
+
+ return result;
+ }
+
+ /**
+ * Returns true if both keys are null, or if the provided key is the same as, or
+ * case-insensitively equal to, the entrie's key.
+ *
+ * @param key
+ * to compare against
+ * @return true if equal
+ */
+ boolean matches(String key)
+ {
+ return key == _key || (key != null && key.equalsIgnoreCase(_key));
+ }
+
+ boolean valueMatches(Object value)
+ {
+ return value == _value || (value != null && value.equals(_value));
+ }
+ }
+
+ private class EntrySetIterator implements Iterator
+ {
+ int _expectedModCount = _modCount;
+
+ int _index;
+
+ int _current = -1;
+
+ public boolean hasNext()
+ {
+ return _index < _size;
+ }
+
+ public Object next()
+ {
+ check();
+
+ if (_index >= _size) throw new NoSuchElementException();
+
+ _current = _index++;
+
+ return _entries[_current];
+ }
+
+ public void remove()
+ {
+ check();
+
+ if (_current < 0) throw new NoSuchElementException();
+
+ _cursor = _current;
+ removeAtCursor();
+
+ _expectedModCount = _modCount;
+ }
+
+ private void check()
+ {
+ if (_expectedModCount != _modCount) throw new ConcurrentModificationException();
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ private class EntrySet extends AbstractSet
+ {
+ @Override
+ public Iterator iterator()
+ {
+ return new EntrySetIterator();
+ }
+
+ @Override
+ public int size()
+ {
+ return _size;
+ }
+
+ @Override
+ public void clear()
+ {
+ CaseInsensitiveMap.this.clear();
+ }
+
+ @Override
+ public boolean contains(Object o)
+ {
+ if (!(o instanceof Map.Entry)) return false;
+
+ Map.Entry e = (Map.Entry) o;
+
+ select(e.getKey());
+
+ if (!_found) return false;
+
+ return _entries[_cursor].valueMatches(e.getValue());
+ }
+
+ @Override
+ public boolean remove(Object o)
+ {
+ if (!(o instanceof Map.Entry)) return false;
+
+ Map.Entry e = (Map.Entry) o;
+
+ select(e.getKey());
+
+ if (!_found) return false;
+
+ if (!_entries[_cursor].valueMatches(e.getValue())) return false;
+
+ removeAtCursor();
+
+ return true;
+ }
+
+ }
+
+ // The list of entries. This is kept sorted by hash code. In some cases, there may be different
+ // keys with the same hash code in adjacent indexes.
+ private CIMEntry<V>[] _entries;
+
+ private int _size = 0;
+
+ // Used by iterators to check for concurrent modifications
+
+ private transient int _modCount = 0;
+
+ private transient Set<Map.Entry<String, V>> _entrySet;
+
+ private transient int _cursor;
+
+ private transient boolean _found;
+
+ public CaseInsensitiveMap()
+ {
+ this(DEFAULT_SIZE);
+ }
+
+ @SuppressWarnings("unchecked")
+ public CaseInsensitiveMap(int size)
+ {
+ _entries = new CIMEntry[Math.max(size, 3)];
+ }
+
+ public CaseInsensitiveMap(Map<String, ? extends V> map)
+ {
+ this(map.size());
+
+ for (Map.Entry<String, ? extends V> entry : map.entrySet())
+ {
+ put(entry.getKey(), entry.getValue());
+ }
+ }
+
+ @Override
+ public void clear()
+ {
+ for (int i = 0; i < _size; i++)
+ _entries[i] = null;
+
+ _size = 0;
+ _modCount++;
+ }
+
+ @Override
+ public boolean isEmpty()
+ {
+ return _size == 0;
+ }
+
+ @Override
+ public int size()
+ {
+ return _size;
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public V put(String key, V value)
+ {
+ int hashCode = caseInsenitiveHashCode(key);
+
+ select(key, hashCode);
+
+ if (_found)
+ {
+ CIMEntry<V> e = _entries[_cursor];
+
+ V result = e._value;
+
+ // Not a structural change, so no change to _modCount
+
+ // Update the key (to maintain case). By definition, the hash code
+ // will not change.
+
+ e._key = key;
+ e._value = value;
+
+ return result;
+ }
+
+ // Not found, we're going to add it.
+
+ int newSize = _size + 1;
+
+ if (newSize == _entries.length)
+ {
+ // Time to expand!
+
+ int newCapacity = (_size * 3) / 2 + 1;
+
+ CIMEntry<V>[] newEntries = new CIMEntry[newCapacity];
+
+ System.arraycopy(_entries, 0, newEntries, 0, _cursor);
+
+ System.arraycopy(_entries, _cursor, newEntries, _cursor + 1, _size - _cursor);
+
+ _entries = newEntries;
+ }
+ else
+ {
+ // Open up a space for the new entry
+
+ System.arraycopy(_entries, _cursor, _entries, _cursor + 1, _size - _cursor);
+ }
+
+ CIMEntry<V> newEntry = new CIMEntry<V>(key, hashCode, value);
+ _entries[_cursor] = newEntry;
+
+ _size++;
+
+ // This is definately a structural change
+
+ _modCount++;
+
+ return null;
+ }
+
+ @Override
+ public boolean containsKey(Object key)
+ {
+ select(key);
+
+ return _found;
+ }
+
+ @Override
+ public V get(Object key)
+ {
+ select(key);
+
+ if (_found) return _entries[_cursor]._value;
+
+ return null;
+ }
+
+ @Override
+ public V remove(Object key)
+ {
+ select(key);
+
+ if (!_found) return null;
+
+ V result = _entries[_cursor]._value;
+
+ removeAtCursor();
+
+ return result;
+ }
+
+ private void removeAtCursor()
+ {
+ // Remove the entry by shifting everything else down.
+
+ System.arraycopy(_entries, _cursor + 1, _entries, _cursor, _size - _cursor - 1);
+
+ // We shifted down, leaving one (now duplicate) entry behind.
+
+ _entries[--_size] = null;
+
+ // A structural change for sure
+
+ _modCount++;
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public Set<Map.Entry<String, V>> entrySet()
+ {
+ if (_entrySet == null) _entrySet = new EntrySet();
+
+ return _entrySet;
+ }
+
+ private void select(Object key)
+ {
+ if (key == null || key instanceof String)
+ {
+ String keyString = (String) key;
+ select(keyString, caseInsenitiveHashCode(keyString));
+ }
+ else
+ {
+ _found = false;
+ }
+ }
+
+ /**
+ * Searches the elements for the index of the indicated key and (case insensitive) hash code.
+ * Sets the _cursor and _found attributes.
+ */
+ private void select(String key, int hashCode)
+ {
+
+ int low = 0;
+ int high = _size - 1;
+
+ _cursor = 0;
+ _found = false;
+
+ if (_size == 0) return;
+
+ while (low <= high)
+ {
+ _cursor = (low + high) >> 1;
+
+ CIMEntry e = _entries[_cursor];
+
+ if (e._hashCode < hashCode)
+ {
+ low = _cursor + 1;
+ continue;
+ }
+
+ if (e._hashCode > hashCode)
+ {
+ high = _cursor - 1;
+ continue;
+ }
+
+ tuneCursor(key, hashCode);
+ return;
+ }
+
+ _cursor = low;
+ }
+
+ /**
+ * find() has located a matching hashCode, but there's an outlying possibility that multiple
+ * keys share the same hashCode. Backup the cursor until we get to locate the initial hashCode
+ * match, then march forward until the key is located, or the hashCode stops matching.
+ *
+ * @param key
+ * @param hashCode
+ */
+ private void tuneCursor(String key, int hashCode)
+ {
+ while (_cursor > 0)
+ {
+ if (_entries[_cursor - 1]._hashCode != hashCode) break;
+
+ _cursor--;
+ }
+
+ while (true)
+ {
+ if (_entries[_cursor].matches(key))
+ {
+ _found = true;
+ return;
+ }
+
+ // Advance to the next entry.
+
+ _cursor++;
+
+ // If out of entries,
+ if (_cursor >= _size || _entries[_cursor]._hashCode != hashCode) return;
+ }
+ }
+
+ static int caseInsenitiveHashCode(String input)
+ {
+ if (input == null) return NULL_HASH;
+
+ int length = input.length();
+ int hash = 0;
+
+ // This should end up more or less equal to input.toLowerCase().hashCode(), unless String
+ // changes its implementation. Let's hope this is reasonably fast.
+
+ for (int i = 0; i < length; i++)
+ {
+ int ch = input.charAt(i);
+
+ int caselessCh = Character.toLowerCase(ch);
+
+ hash = 31 * hash + caselessCh;
+ }
+
+ return hash;
+ }
+
+}
Added: tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/util/Stack.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/util/Stack.java?view=auto&rev=505796
==============================================================================
--- tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/util/Stack.java (added)
+++ tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/util/Stack.java Sat Feb 10 15:43:27 2007
@@ -0,0 +1,125 @@
+// 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.util;
+
+import org.apache.tapestry.ioc.internal.util.CollectionFactory;
+
+/**
+ * A simple, streamlined implementation of {@link java.util.Stack}. The implementation is
+ * <em>not</em> threadsafe.
+ *
+ * @param <E>
+ * the type of elements stored in the map
+ * @see CollectionFactory#newStack()
+ */
+public class Stack<E>
+{
+ private static final int DEFAULT_ARRAY_SIZE = 20;
+
+ private Object[] _items;
+
+ private int _index = -1;
+
+ public Stack()
+ {
+ _items = new Object[DEFAULT_ARRAY_SIZE];
+ }
+
+ /** Returns true if the stack is empty. */
+ public boolean isEmpty()
+ {
+ return _index < 0;
+ }
+
+ /** Pushes a new item onto the stack. */
+ public void push(E item)
+ {
+ _index++;
+
+ if (_index == _items.length)
+ {
+ int newCapacity = (_items.length * 3) / 2 + 1;
+ Object[] newItems = new Object[newCapacity];
+ System.arraycopy(_items, 0, newItems, 0, _items.length);
+
+ _items = newItems;
+ }
+
+ _items[_index] = item;
+ }
+
+ /**
+ * Pops the top element off the stack and returns it.
+ *
+ * @return the top element of the stack
+ * @throws IllegalStateException
+ * if the stack is empty
+ */
+ @SuppressWarnings("unchecked")
+ public E pop()
+ {
+ checkIfEmpty();
+
+ Object result = _items[_index];
+
+ _items[_index] = null;
+
+ _index--;
+
+ return (E) result;
+ }
+
+ private void checkIfEmpty()
+ {
+ if (_index < 0) throw new IllegalStateException(UtilMessages.stackIsEmpty());
+ }
+
+ /**
+ * Returns the top element of the stack without affecting the stack.
+ *
+ * @return top element on the stack
+ * @throws IllegalStateException
+ * if the stack is empty
+ */
+ @SuppressWarnings("unchecked")
+ public E peek()
+ {
+ checkIfEmpty();
+
+ return (E) _items[_index];
+ }
+
+ /**
+ * Describes the stack, listing the element in order of depth (top element first).
+ *
+ * @return string description of the stack
+ */
+ @Override
+ public String toString()
+ {
+ StringBuilder builder = new StringBuilder("Stack[");
+
+ for (int i = _index; i >= 0; i--)
+ {
+ if (i != _index) builder.append(", ");
+
+ builder.append(String.valueOf(_items[i]));
+ }
+
+ builder.append("]");
+
+ return builder.toString();
+ }
+}
Modified: tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/util/UtilMessages.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/util/UtilMessages.java?view=diff&rev=505796&r1=505795&r2=505796
==============================================================================
--- tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/util/UtilMessages.java (original)
+++ tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/util/UtilMessages.java Sat Feb 10 15:43:27 2007
@@ -36,4 +36,9 @@
adapterType.getName(),
catalog);
}
+
+ static String stackIsEmpty()
+ {
+ return MESSAGES.get("stack-is-empty");
+ }
}
Modified: tapestry/tapestry5/tapestry-ioc/trunk/src/main/resources/org/apache/tapestry/ioc/util/UtilStrings.properties
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-ioc/trunk/src/main/resources/org/apache/tapestry/ioc/util/UtilStrings.properties?view=diff&rev=505796&r1=505795&r2=505796
==============================================================================
--- tapestry/tapestry5/tapestry-ioc/trunk/src/main/resources/org/apache/tapestry/ioc/util/UtilStrings.properties (original)
+++ tapestry/tapestry5/tapestry-ioc/trunk/src/main/resources/org/apache/tapestry/ioc/util/UtilStrings.properties Sat Feb 10 15:43:27 2007
@@ -13,4 +13,4 @@
# limitations under the License.
no-strategy-adapter=No adapter from type %s to type %s is available (registered types are %s).
-
+stack-is-empty=Stack is empty.
Added: tapestry/tapestry5/tapestry-ioc/trunk/src/site/apt/case.apt
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-ioc/trunk/src/site/apt/case.apt?view=auto&rev=505796
==============================================================================
--- tapestry/tapestry5/tapestry-ioc/trunk/src/site/apt/case.apt (added)
+++ tapestry/tapestry5/tapestry-ioc/trunk/src/site/apt/case.apt Sat Feb 10 15:43:27 2007
@@ -0,0 +1,27 @@
+ ----
+ Case Insensitivity
+ ----
+
+Case Insensitivity
+
+ Ever get frustrated because you typed the right thing with the wrong case and your system blew up? We do.
+
+ Tapestry IOC attempts to be case insensitive for all the main constructs:
+
+ * Module ids.
+
+ * Service ids.
+
+ * Object provider prefixes.
+
+ * Message keys.
+
+ []
+
+ Thus, <<<getService("foo.bar.Baz", Baz.class)>>> is preferred, but <<<getService("FOO.BAR.BAZ", Baz.class)>>> (or any variation thereof) will work just exactly as well. This also extends to other naming conventions,
+ such as <<<contributeFoo>>> methods. It also applies to values inside annotations.
+
+ Just case is ignored --
+ other punctuation, as well as whitespace, must exactly match.
+
+ Under the covers, this is supported by the {{{../apidocs/org/apache/tapestry/ioc/CaseInsensitiveMap.html}CaseInsensitiveMap}} class.
\ No newline at end of file
Modified: tapestry/tapestry5/tapestry-ioc/trunk/src/site/apt/provider.apt
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-ioc/trunk/src/site/apt/provider.apt?view=diff&rev=505796&r1=505795&r2=505796
==============================================================================
--- tapestry/tapestry5/tapestry-ioc/trunk/src/site/apt/provider.apt (original)
+++ tapestry/tapestry5/tapestry-ioc/trunk/src/site/apt/provider.apt Sat Feb 10 15:43:27 2007
@@ -28,8 +28,8 @@
* infrastructure provider
- The tapestry module provides the
- {{{..tapestry-core/guide/infrastructure.html}infrastructure}} object provider, which exists
+ The tapestry module (provided by the {{{http://tapestry.apache.org/tapestry5/tapestry-core/}tapestry-core library}}) provides the
+ {{{http://tapestry.apache.org/tapestry5/tapestry-core/guide/infrastructure.html}infrastructure}} object provider, which exists
to provide shorter names for injecting services and to support overrides.
* default provider
Modified: tapestry/tapestry5/tapestry-ioc/trunk/src/site/site.xml
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-ioc/trunk/src/site/site.xml?view=diff&rev=505796&r1=505795&r2=505796
==============================================================================
--- tapestry/tapestry5/tapestry-ioc/trunk/src/site/site.xml (original)
+++ tapestry/tapestry5/tapestry-ioc/trunk/src/site/site.xml Sat Feb 10 15:43:27 2007
@@ -54,6 +54,7 @@
<item name="Services" href="service.html"/>
<item name="Decorators" href="decorator.html"/>
<item name="Configuration" href="configuration.html"/>
+ <item name="Case Insensitivity" href="case.html"/>
<item name="Symbols" href="symbols.html"/>
<item name="Starting the Registry" href="run.html"/>
<item name="Object Providers" href="provider.html"/>
Modified: tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/IntegrationTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/IntegrationTest.java?view=diff&rev=505796&r1=505795&r2=505796
==============================================================================
--- tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/IntegrationTest.java (original)
+++ tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/IntegrationTest.java Sat Feb 10 15:43:27 2007
@@ -416,4 +416,14 @@
assertEquals(holder.getValue(), 42);
}
+
+ @Test
+ public void access_to_services_ignores_case()
+ {
+ Registry r = buildRegistry(FredModule.class);
+
+ Runnable fred = r.getService("fred.Fred", Runnable.class);
+
+ assertSame(r.getService("FRED.FRED", Runnable.class), fred);
+ }
}
Modified: tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/internal/GlobPatternMatcherTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/internal/GlobPatternMatcherTest.java?view=diff&rev=505796&r1=505795&r2=505796
==============================================================================
--- tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/internal/GlobPatternMatcherTest.java (original)
+++ tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/internal/GlobPatternMatcherTest.java Sat Feb 10 15:43:27 2007
@@ -33,6 +33,7 @@
public void glob_match_exact()
{
assertTrue(globMatch("fred", "fred"));
+ assertTrue(globMatch("fred", "FRED"));
assertFalse(globMatch("xfred", "fred"));
assertFalse(globMatch("fredx", "fred"));
assertFalse(globMatch("fred", "xfred"));
@@ -50,6 +51,7 @@
public void glob_match_prefix()
{
assertTrue(globMatch("fred.Barney", "*Barney"));
+ assertTrue(globMatch("fred.Barney", "*BARNEY"));
assertFalse(globMatch("fred.Barneyx", "*Barney"));
assertFalse(globMatch("fred.Barney", "*Barneyx"));
assertFalse(globMatch("fred.Barney", "*xBarney"));
@@ -59,6 +61,7 @@
public void glob_match_suffix()
{
assertTrue(globMatch("fred.Barney", "fred*"));
+ assertTrue(globMatch("fred.Barney", "FRED*"));
assertFalse(globMatch("xfred.Barney", "fred*"));
assertFalse(globMatch("fred.Barney", "fredx*"));
assertFalse(globMatch("fred.Barney", "xfred*"));
@@ -68,8 +71,10 @@
public void glob_match_infix()
{
assertTrue(globMatch("fred.Barney", "*d.B*"));
+ assertTrue(globMatch("fred.Barney", "*D.B*"));
assertTrue(globMatch("fred.Barney", "*Barney*"));
assertTrue(globMatch("fred.Barney", "*fred*"));
+ assertTrue(globMatch("fred.Barney", "*FRED*"));
assertFalse(globMatch("fred.Barney", "*flint*"));
}
Modified: tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/internal/services/MasterObjectProviderTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/internal/services/MasterObjectProviderTest.java?view=diff&rev=505796&r1=505795&r2=505796
==============================================================================
--- tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/internal/services/MasterObjectProviderTest.java (original)
+++ tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/internal/services/MasterObjectProviderTest.java Sat Feb 10 15:43:27 2007
@@ -55,6 +55,28 @@
}
@Test
+ public void successful_lookup_case_insensitive()
+ {
+ ObjectProvider provider = newObjectProvider();
+ ServiceLocator locator = newServiceLocator();
+ Runnable r = newRunnable();
+ SymbolSource source = newSymbolSource();
+
+ train_expandSymbols(source, "PREFIX:expression");
+ train_provide(provider, "expression", Runnable.class, locator, r);
+
+ replay();
+
+ ObjectProvider master = new MasterObjectProvider(newMap("prefix", provider), source, null);
+
+ Runnable actual = master.provide("PREFIX:expression", Runnable.class, locator);
+
+ assertSame(actual, r);
+
+ verify();
+ }
+
+ @Test
public void symbols_are_expanded()
{
ObjectProvider provider = newObjectProvider();
Modified: tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/internal/services/PropertyAccessImplTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/internal/services/PropertyAccessImplTest.java?view=diff&rev=505796&r1=505795&r2=505796
==============================================================================
--- tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/internal/services/PropertyAccessImplTest.java (original)
+++ tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/internal/services/PropertyAccessImplTest.java Sat Feb 10 15:43:27 2007
@@ -165,6 +165,18 @@
}
@Test
+ public void property_name_case_is_ignored_on_read()
+ {
+ Bean b = new Bean();
+
+ int value = _random.nextInt();
+
+ b.setValue(value);
+
+ assertEquals(_access.get(b, "VALUE"), value);
+ }
+
+ @Test
public void simple_write_access()
{
Bean b = new Bean();
@@ -174,6 +186,18 @@
_access.set(b, "value", value);
assertEquals(b.getValue(), value);
+ }
+
+ @Test
+ public void property_name_case_is_ignored_on_write()
+ {
+ Bean b = new Bean();
+
+ int value = _random.nextInt();
+
+ _access.set(b, "VALUE", value);
+
+ assertEquals(b.getValue(), value);
}
@Test
Modified: tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/internal/util/MessagesImplTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/internal/util/MessagesImplTest.java?view=diff&rev=505796&r1=505795&r2=505796
==============================================================================
--- tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/internal/util/MessagesImplTest.java (original)
+++ tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/internal/util/MessagesImplTest.java Sat Feb 10 15:43:27 2007
@@ -31,11 +31,25 @@
}
@Test
+ public void contains_key_is_case_insensitive()
+ {
+ assertTrue(_messages.contains("No-Args"));
+ assertFalse(_messages.contains("Xyzzyx"));
+ }
+
+ @Test
public void get_message_from_catalog()
{
assertEquals(_messages.get("no-args"), "No arguments.");
assertEquals(_messages.get("something-failed"), "Something failed: %s");
}
+
+ @Test
+ public void get_message_from_catalog_is_case_insensitive()
+ {
+ assertEquals(_messages.get("No-args"), "No arguments.");
+ assertEquals(_messages.get("Something-Failed"), "Something failed: %s");
+ }
@Test
public void get_unknown_message_from_catalog()
@@ -50,6 +64,12 @@
}
@Test
+ public void format_message_is_case_insensitive()
+ {
+ assertEquals(_messages.format("Result", "good"), "The result is 'good'.");
+ }
+
+ @Test
public void get_formatter()
{
MessageFormatter mf = _messages.getFormatter("result");
@@ -61,7 +81,8 @@
public void formatters_are_cached()
{
MessageFormatter mf1 = _messages.getFormatter("result");
- MessageFormatter mf2 = _messages.getFormatter("result");
+ // Throw in a case-insensitive check:
+ MessageFormatter mf2 = _messages.getFormatter("Result");
assertSame(mf2, mf1);
}