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 2006/07/25 02:16:31 UTC

svn commit: r425234 [1/2] - in /tapestry/tapestry5/tapestry-core/trunk/src: main/java/org/apache/tapestry/internal/ioc/ main/java/org/apache/tapestry/internal/test/ main/java/org/apache/tapestry/ioc/ main/java/org/apache/tapestry/ioc/annotations/ main/...

Author: hlship
Date: Mon Jul 24 17:16:30 2006
New Revision: 425234

URL: http://svn.apache.org/viewvc?rev=425234&view=rev
Log:
Start adding support for configurations and contributions.

Added:
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/ConfigurationType.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/ContributionDefImpl.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/ValidatingConfigurationWrapper.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/Configuration.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/MappedConfiguration.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/OrderedConfiguration.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/annotations/Contribute.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/def/ContributionDef.java
    tapestry/tapestry5/tapestry-core/trunk/src/site/apt/ioc/configuration.apt
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/ConfigurationWithAnnotationOtherModule.java
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/ConfigurationWithContributeAnnotationModule.java
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/ContributionDefImplTest.java
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/MappedConfigurationModule.java
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/NoUsableContributionParameterModule.java
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/OrderedConfigurationModule.java
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/TooManyContributionParametersModule.java
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/ValidatingConfigurationWrapperTest.java
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/util/FindTheParameterizedType.java
Modified:
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/DefaultModuleDefImpl.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/IOCMessages.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/IOCUtilities.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/ServiceBuilderMethodInvoker.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/ServiceDecoratorImpl.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/test/InternalBaseTestCase.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/def/ModuleDef.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/BaseTestCase.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/internal/ioc/IOCStrings.properties
    tapestry/tapestry5/tapestry-core/trunk/src/site/apt/ioc/service.apt
    tapestry/tapestry5/tapestry-core/trunk/src/site/site.xml
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/DefaultModuleDefImplTest.java
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/ModuleImplTest.java
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/ServiceBuilderMethodInvokerTest.java
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/SimpleModuleBuilder.java

Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/ConfigurationType.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/ConfigurationType.java?rev=425234&view=auto
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/ConfigurationType.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/ConfigurationType.java Mon Jul 24 17:16:30 2006
@@ -0,0 +1,30 @@
+// Copyright 2006 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.internal.ioc;
+
+/**
+ * Defines the three types of configurations a service may request.
+ * 
+ * @author Howard M. Lewis Ship
+ */
+public enum ConfigurationType {
+
+    /** @see org.apache.tapestry.ioc.Configuration */
+    UNORDERED,
+    /** @see org.apache.tapestry.ioc.OrderedConfiguration */
+    ORDERED,
+    /** @see org.apache.tapestry.ioc.MappedConfiguration */
+    MAPPED
+}

Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/ContributionDefImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/ContributionDefImpl.java?rev=425234&view=auto
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/ContributionDefImpl.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/ContributionDefImpl.java Mon Jul 24 17:16:30 2006
@@ -0,0 +1,119 @@
+// Copyright 2006 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.internal.ioc;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.Map;
+
+import org.apache.tapestry.internal.util.InternalUtils;
+import org.apache.tapestry.ioc.Configuration;
+import org.apache.tapestry.ioc.MappedConfiguration;
+import org.apache.tapestry.ioc.OrderedConfiguration;
+import org.apache.tapestry.ioc.ServiceLocator;
+import org.apache.tapestry.ioc.def.ContributionDef;
+
+import static org.apache.tapestry.util.CollectionFactory.newMap;
+
+/**
+ * @author Howard M. Lewis Ship
+ */
+public class ContributionDefImpl implements ContributionDef
+{
+    private final String _serviceId;
+
+    private final Method _contributorMethod;
+
+    public ContributionDefImpl(String serviceId, Method contributorMethod)
+    {
+        _serviceId = serviceId;
+        _contributorMethod = contributorMethod;
+    }
+
+    @Override
+    public String toString()
+    {
+        return InternalUtils.asString(_contributorMethod);
+    }
+
+    public String getServiceId()
+    {
+        return _serviceId;
+    }
+
+    public void contribute(Object moduleBuilder, ServiceLocator locator, Configuration configuration)
+    {
+        invokeMethod(moduleBuilder, locator, Configuration.class, configuration);
+    }
+
+    public void contribute(Object moduleBuilder, ServiceLocator locator,
+            OrderedConfiguration configuration)
+    {
+        invokeMethod(moduleBuilder, locator, OrderedConfiguration.class, configuration);
+    }
+
+    public void contribute(Object moduleBuilder, ServiceLocator locator,
+            MappedConfiguration configuration)
+    {
+        invokeMethod(moduleBuilder, locator, MappedConfiguration.class, configuration);
+    }
+
+    private void invokeMethod(Object moduleBuilder, ServiceLocator locator, Class parameterType,
+            Object parameterValue)
+    {
+        Map<Class, Object> parameterDefaults = newMap();
+
+        // The way it works is: the method will take Configuration, OrderedConfiguration or
+        // MappedConfiguration.
+        // So, if the method is for one type and the service is for a different type,
+        // then we'll see an error putting together the parameter.
+
+        parameterDefaults.put(parameterType, parameterValue);
+
+        invokeMethod(moduleBuilder, locator, parameterDefaults);
+    }
+
+    private void invokeMethod(Object moduleBuilder, ServiceLocator locator,
+            Map<Class, Object> parameterDefaults)
+    {
+        // Alas, logging of this will occur elsewhere, since
+        // I don't want to clutter up the parameters by passing
+        // in the Log for the service.
+
+        Throwable fail = null;
+
+        try
+        {
+            Object[] parameters = IOCUtilities.calculateParametersForMethod(
+                    _contributorMethod,
+                    locator,
+                    parameterDefaults);
+
+            _contributorMethod.invoke(moduleBuilder, parameters);
+        }
+        catch (InvocationTargetException ex)
+        {
+            fail = ex;
+        }
+        catch (Exception ex)
+        {
+            fail = ex;
+        }
+
+        if (fail != null)
+            throw new RuntimeException(IOCMessages
+                    .contributionMethodError(_contributorMethod, fail), fail);
+    }
+}

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/DefaultModuleDefImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/DefaultModuleDefImpl.java?rev=425234&r1=425233&r2=425234&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/DefaultModuleDefImpl.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/DefaultModuleDefImpl.java Mon Jul 24 17:16:30 2006
@@ -14,13 +14,6 @@
 
 package org.apache.tapestry.internal.ioc;
 
-import static org.apache.tapestry.internal.ioc.IOCMessages.buildMethodConflict;
-import static org.apache.tapestry.internal.ioc.IOCMessages.buildMethodWrongReturnType;
-import static org.apache.tapestry.internal.ioc.IOCMessages.decoratorMethodWrongReturnType;
-import static org.apache.tapestry.ioc.IOCUtilities.qualifySimpleIdList;
-import static org.apache.tapestry.util.CollectionFactory.newMap;
-import static org.apache.tapestry.util.CollectionFactory.newSet;
-
 import java.lang.annotation.Annotation;
 import java.lang.reflect.AnnotatedElement;
 import java.lang.reflect.Method;
@@ -31,16 +24,32 @@
 
 import org.apache.commons.logging.Log;
 import org.apache.tapestry.annotations.Match;
+import org.apache.tapestry.ioc.Configuration;
 import org.apache.tapestry.ioc.IOCConstants;
+import org.apache.tapestry.ioc.IOCUtilities;
+import org.apache.tapestry.ioc.MappedConfiguration;
+import org.apache.tapestry.ioc.OrderedConfiguration;
 import org.apache.tapestry.ioc.annotations.After;
 import org.apache.tapestry.ioc.annotations.Before;
+import org.apache.tapestry.ioc.annotations.Contribute;
 import org.apache.tapestry.ioc.annotations.Id;
 import org.apache.tapestry.ioc.annotations.Lifecycle;
 import org.apache.tapestry.ioc.annotations.Private;
+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 static org.apache.tapestry.internal.ioc.ConfigurationType.MAPPED;
+import static org.apache.tapestry.internal.ioc.ConfigurationType.ORDERED;
+import static org.apache.tapestry.internal.ioc.ConfigurationType.UNORDERED;
+import static org.apache.tapestry.internal.ioc.IOCMessages.buildMethodConflict;
+import static org.apache.tapestry.internal.ioc.IOCMessages.buildMethodWrongReturnType;
+import static org.apache.tapestry.internal.ioc.IOCMessages.decoratorMethodWrongReturnType;
+import static org.apache.tapestry.ioc.IOCUtilities.qualifySimpleIdList;
+import static org.apache.tapestry.util.CollectionFactory.newMap;
+import static org.apache.tapestry.util.CollectionFactory.newSet;
+
 /**
  * Starting from the Class for a module builder, identifies all the services (service builder
  * methods), decorators (service decorator methods) and (not yet implemented) contributions (service
@@ -56,6 +65,9 @@
     /** The prefix used to identify service decorator methods. */
     private static final String DECORATE_METHOD_NAME_PREFIX = "decorate";
 
+    /** The prefix used to identify service contribution methods. */
+    private static final String CONTRIBUTE_METHOD_NAME_PREFIX = "contribute";
+
     private final Class _builderClass;
 
     private final Log _log;
@@ -66,8 +78,18 @@
     /** Keyed on fully qualified decorator id. */
     private final Map<String, DecoratorDef> _decoratorDefs = newMap();
 
+    private final Set<ContributionDef> _contributionDefs = newSet();
+
     private final String _moduleId;
 
+    private final Map<Class, ConfigurationType> _contributorParameterToConfigurationType = newMap();
+
+    {
+        _contributorParameterToConfigurationType.put(MappedConfiguration.class, MAPPED);
+        _contributorParameterToConfigurationType.put(OrderedConfiguration.class, ORDERED);
+        _contributorParameterToConfigurationType.put(Configuration.class, UNORDERED);
+    }
+
     /**
      * @param builderClass
      *            the class that is responsible for building services, etc.
@@ -166,7 +188,61 @@
                 addDecoratorDef(m);
                 continue;
             }
+
+            if (name.startsWith(CONTRIBUTE_METHOD_NAME_PREFIX))
+            {
+                addContributionDef(m);
+                continue;
+            }
+
+        }
+    }
+
+    private void addContributionDef(Method method)
+    {
+        String serviceId = stripMethodPrefix(method, CONTRIBUTE_METHOD_NAME_PREFIX);
+
+        Class returnType = method.getReturnType();
+        if (!returnType.equals(void.class))
+            _log.warn(IOCMessages.contributionWrongReturnType(method));
+
+        Contribute contribute = method.getAnnotation(Contribute.class);
+        if (contribute != null)
+            serviceId = contribute.value();
+
+        ConfigurationType type = null;
+
+        for (Class parameterType : method.getParameterTypes())
+        {
+            ConfigurationType thisParameter = _contributorParameterToConfigurationType
+                    .get(parameterType);
+
+            if (thisParameter != null)
+            {
+                if (type != null)
+                {
+                    _log.warn(IOCMessages.tooManyContributionParameters(method));
+                    return;
+                }
+
+                type = thisParameter;
+            }
+        }
+
+        if (type == null)
+        {
+            _log.warn(IOCMessages.noContributionParameter(method));
+            return;
         }
+
+        // Any other parameters will be validated and worked out at runtime, when we invoke the
+        // service contribution method.
+
+        String qualifiedId = IOCUtilities.toQualifiedId(_moduleId, serviceId);
+
+        ContributionDef def = new ContributionDefImpl(qualifiedId, method);
+
+        _contributionDefs.add(def);
     }
 
     private void addDecoratorDef(Method method)
@@ -276,4 +352,8 @@
         return newSet(_decoratorDefs.values());
     }
 
+    public Set<ContributionDef> getContributionDefs()
+    {
+        return _contributionDefs;
+    }
 }

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/IOCMessages.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/IOCMessages.java?rev=425234&r1=425233&r2=425234&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/IOCMessages.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/IOCMessages.java Mon Jul 24 17:16:30 2006
@@ -14,16 +14,18 @@
 
 package org.apache.tapestry.internal.ioc;
 
-import static org.apache.tapestry.internal.util.InternalUtils.asString;
-
 import java.lang.reflect.Method;
 import java.util.List;
 
 import org.apache.hivemind.Messages;
 import org.apache.hivemind.impl.MessageFormatter;
 import org.apache.tapestry.internal.annotations.Utility;
+import org.apache.tapestry.ioc.def.ContributionDef;
 import org.apache.tapestry.ioc.def.ServiceDef;
 
+import static org.apache.tapestry.internal.util.InternalUtils.asString;
+import static org.apache.tapestry.ioc.services.ClassFabUtils.getJavaClassName;
+
 /**
  * @author Howard M. Lewis Ship
  */
@@ -164,5 +166,40 @@
     static String recursiveServiceBuild(ServiceDef def)
     {
         return MESSAGES.format("recursive-service-build", def.getServiceId(), def.toString());
+    }
+
+    static String contributionWrongReturnType(Method method)
+    {
+        return MESSAGES.format(
+                "contribution-wrong-return-type",
+                asString(method),
+                getJavaClassName(method.getReturnType()));
+    }
+
+    static String tooManyContributionParameters(Method method)
+    {
+        return MESSAGES.format("too-many-contribution-parameters", asString(method));
+    }
+
+    static String noContributionParameter(Method method)
+    {
+        return MESSAGES.format("no-contribution-parameter", asString(method));
+    }
+
+    static String contributionMethodError(Method method, Throwable cause)
+    {
+        return MESSAGES.format("contribution-method-error", asString(method), cause);
+    }
+
+    static String contributionWasNull(String serviceId, ContributionDef def)
+    {
+        return MESSAGES.format("contribution-was-null", serviceId, def);
+    }
+
+    static String contributionWrongValueType(String serviceId, ContributionDef def,
+            Class actualClass, Class expectedClass)
+    {
+        return MESSAGES.format("contribution-wrong-value-type", new Object[]
+        { serviceId, def, actualClass.getName(), expectedClass.getName() });
     }
 }

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/IOCUtilities.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/IOCUtilities.java?rev=425234&r1=425233&r2=425234&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/IOCUtilities.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/IOCUtilities.java Mon Jul 24 17:16:30 2006
@@ -19,7 +19,7 @@
 import java.util.Map;
 
 import org.apache.tapestry.internal.annotations.Utility;
-import org.apache.tapestry.ioc.ServiceResources;
+import org.apache.tapestry.ioc.ServiceLocator;
 import org.apache.tapestry.ioc.annotations.InjectService;
 
 /**
@@ -53,8 +53,8 @@
     }
 
     @SuppressWarnings("unchecked")
-    public static Object calculateParameterValue(Class parameterType,
-            Annotation[] parameterAnnotations, ServiceResources serviceResources,
+    private static Object calculateParameterValue(Class parameterType,
+            Annotation[] parameterAnnotations, ServiceLocator locator,
             Map<Class, Object> parameterDefaults)
     {
         InjectService is = findAnnotation(parameterAnnotations, InjectService.class);
@@ -63,7 +63,7 @@
         {
             String serviceId = is.value();
 
-            return serviceResources.getService(serviceId, parameterType);
+            return locator.getService(serviceId, parameterType);
         }
 
         // See if we have any "pre-determined" parameter type to object mappings
@@ -73,15 +73,15 @@
         // This will return a non-null value, or throw an exception
 
         if (result == null)
-            result = serviceResources.getService(parameterType);
+            result = locator.getService(parameterType);
 
         // ... so the result is never null
 
         return result;
     }
 
-    public static Object[] calculateParametersForMethod(Method method,
-            ServiceResources serviceResources, Map<Class, Object> parameterDefaults)
+    public static Object[] calculateParametersForMethod(Method method, ServiceLocator locator,
+            Map<Class, Object> parameterDefaults)
     {
         Class[] parameterTypes = method.getParameterTypes();
         Annotation[][] annotations = method.getParameterAnnotations();
@@ -94,7 +94,7 @@
             parameters[i] = calculateParameterValue(
                     parameterTypes[i],
                     annotations[i],
-                    serviceResources,
+                    locator,
                     parameterDefaults);
         }
 

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/ServiceBuilderMethodInvoker.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/ServiceBuilderMethodInvoker.java?rev=425234&r1=425233&r2=425234&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/ServiceBuilderMethodInvoker.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/ServiceBuilderMethodInvoker.java Mon Jul 24 17:16:30 2006
@@ -66,10 +66,6 @@
      */
     public Object createService()
     {
-        Object[] parameters = calculateParametersForMethod(
-                _builderMethod,
-                _resources,
-                _parameterDefaults);
 
         if (_log.isDebugEnabled())
             _log.debug(IOCMessages.invokingMethod(_builderMethod));
@@ -79,6 +75,11 @@
 
         try
         {
+            Object[] parameters = calculateParametersForMethod(
+                    _builderMethod,
+                    _resources,
+                    _parameterDefaults);
+
             result = _builderMethod.invoke(_moduleBuilder, parameters);
         }
         catch (InvocationTargetException ite)

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/ServiceDecoratorImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/ServiceDecoratorImpl.java?rev=425234&r1=425233&r2=425234&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/ServiceDecoratorImpl.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/ServiceDecoratorImpl.java Mon Jul 24 17:16:30 2006
@@ -68,11 +68,6 @@
         Map<Class, Object> parameterDefaults = newMap(_parameterDefaults);
         parameterDefaults.put(Object.class, delegate);
 
-        Object[] parameters = calculateParametersForMethod(
-                _decoratorMethod,
-                _resources,
-                parameterDefaults);
-
         if (_log.isDebugEnabled())
             _log.debug(IOCMessages.invokingMethod(_decoratorMethod));
 
@@ -81,6 +76,11 @@
 
         try
         {
+            Object[] parameters = calculateParametersForMethod(
+                    _decoratorMethod,
+                    _resources,
+                    parameterDefaults);
+
             result = _decoratorMethod.invoke(_moduleBuilder, parameters);
         }
         catch (InvocationTargetException ite)

Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/ValidatingConfigurationWrapper.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/ValidatingConfigurationWrapper.java?rev=425234&view=auto
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/ValidatingConfigurationWrapper.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/ValidatingConfigurationWrapper.java Mon Jul 24 17:16:30 2006
@@ -0,0 +1,68 @@
+// Copyright 2006 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.internal.ioc;
+
+import org.apache.commons.logging.Log;
+import org.apache.tapestry.ioc.Configuration;
+import org.apache.tapestry.ioc.def.ContributionDef;
+
+/**
+ * Performs some validation before delegating to another Configuration.
+ * 
+ * @author Howard M. Lewis Ship
+ */
+public class ValidatingConfigurationWrapper implements Configuration
+{
+    private final String _serviceId;
+
+    private final ContributionDef _contributionDef;
+
+    private final Log _log;
+
+    private final Configuration _delegate;
+
+    private final Class _expectedClass;
+
+    // Need a strategy for determing the right order for this mass of parameters!
+
+    public ValidatingConfigurationWrapper(String serviceId, Log log, Class expectedClass,
+            ContributionDef contributionDef, Configuration delegate)
+    {
+        _serviceId = serviceId;
+        _contributionDef = contributionDef;
+        _log = log;
+        _delegate = delegate;
+        _expectedClass = expectedClass;
+    }
+
+    public void add(Object object)
+    {
+        if (object == null)
+        {
+            _log.warn(IOCMessages.contributionWasNull(_serviceId, _contributionDef));
+            return;
+        }
+
+        if (!_expectedClass.isInstance(object))
+        {
+            _log.warn(IOCMessages.contributionWrongValueType(_serviceId, _contributionDef, object
+                    .getClass(), _expectedClass));
+            return;
+        }
+
+        _delegate.add(object);
+    }
+
+}

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/test/InternalBaseTestCase.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/test/InternalBaseTestCase.java?rev=425234&r1=425233&r2=425234&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/test/InternalBaseTestCase.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/test/InternalBaseTestCase.java Mon Jul 24 17:16:30 2006
@@ -16,13 +16,11 @@
 
 import java.util.List;
 
-import org.apache.commons.logging.Log;
 import org.apache.tapestry.internal.InternalComponentResources;
 import org.apache.tapestry.internal.annotations.SuppressNullCheck;
 import org.apache.tapestry.internal.ioc.InternalRegistry;
 import org.apache.tapestry.internal.ioc.Module;
 import org.apache.tapestry.internal.parser.ComponentTemplate;
-import org.apache.tapestry.ioc.LogSource;
 import org.apache.tapestry.ioc.ServiceDecorator;
 import org.apache.tapestry.ioc.ServiceLifecycle;
 import org.apache.tapestry.ioc.def.ServiceDef;
@@ -76,27 +74,9 @@
         return newMock(Module.class);
     }
 
-    protected final void trainCreateInterceptor(ServiceDecorator decorator, Object coreObject,
-            Object interceptor)
-    {
-        decorator.createInterceptor(coreObject);
-        setReturnValue(interceptor);
-    }
-
-    protected final ServiceDecorator newServiceDecorator()
-    {
-        return newMock(ServiceDecorator.class);
-    }
-
     protected void trainFindDecoratorsForService(InternalRegistry registry)
     {
         registry.findDecoratorsForService(EasyMock.isA(ServiceDef.class));
         setReturnValue(CollectionFactory.newList());
-    }
-
-    protected final void trainGetLog(LogSource source, String serviceId, Log log)
-    {
-        source.getLog(serviceId);
-        setReturnValue(log);
     }
 }

Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/Configuration.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/Configuration.java?rev=425234&view=auto
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/Configuration.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/Configuration.java Mon Jul 24 17:16:30 2006
@@ -0,0 +1,45 @@
+// Copyright 2006 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;
+
+/**
+ * Object passed into a service contributor method that allows the method provide contributed values
+ * to the service's configuration.
+ * <p>
+ * A service can <em>collect</em> contributions in three different ways:
+ * <ul>
+ * <li>As an un-ordered collection of values</li>
+ * <li>As an ordered list of values (where each value has a unique id, pre-requisited and
+ * post-requisites)</li>
+ * <li>As a map of keys and values
+ * </ul>
+ * <p>
+ * This implementation is used for un-ordered configuration data.
+ * <p>
+ * The service defines the <em>type</em> of contribution, in terms of a base class or service
+ * interface. Contributions must be compatible with the type.
+ * 
+ * @author Howard M. Lewis Ship
+ */
+public interface Configuration<T>
+{
+    /**
+     * Adds an object to the service's contribution.
+     * 
+     * @param object
+     *            to add to the service's configuration
+     */
+    void add(T object);
+}

Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/MappedConfiguration.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/MappedConfiguration.java?rev=425234&view=auto
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/MappedConfiguration.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/MappedConfiguration.java Mon Jul 24 17:16:30 2006
@@ -0,0 +1,49 @@
+// Copyright 2006 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;
+
+/**
+ * Object passed into a service contributor method that allows the method provide contributed values
+ * to the service's configuration.
+ * <p>
+ * A service can <em>collect</em> contributions in three different ways:
+ * <ul>
+ * <li>As an un-ordered collection of values</li>
+ * <li>As an ordered list of values (where each value has a unique id, pre-requisited and
+ * post-requisites)</li>
+ * <li>As a map of keys and values
+ * </ul>
+ * <p>
+ * The service defines the <em>type</em> of contribution, in terms of a base class or service
+ * interface. Contributions must be compatible with the type.
+ * 
+ * @author Howard M. Lewis Ship
+ */
+public interface MappedConfiguration<K, V>
+{
+
+    /**
+     * Adds a keyed object to the service's contribution.
+     * 
+     * @param key
+     *            unique id for the value
+     * @param value
+     *            to contribute
+     * @throws IllegalArgumentException
+     *             if key is not unique
+     */
+
+    void add(K key, V value);
+}

Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/OrderedConfiguration.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/OrderedConfiguration.java?rev=425234&view=auto
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/OrderedConfiguration.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/OrderedConfiguration.java Mon Jul 24 17:16:30 2006
@@ -0,0 +1,62 @@
+// Copyright 2006 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;
+
+/**
+ * Object passed into a service contributor method that allows the method provide contributed values
+ * to the service's configuration.
+ * <p>
+ * A service can <em>collect</em> contributions in three different ways:
+ * <ul>
+ * <li>As an un-ordered collection of values</li>
+ * <li>As an ordered list of values (where each value has a unique id, pre-requisited and
+ * post-requisites)</li>
+ * <li>As a map of keys and values
+ * </ul>
+ * <p>
+ * The service defines the <em>type</em> of contribution, in terms of a base class or service
+ * interface. Contributions must be compatible with the type.
+ * 
+ * @author Howard M. Lewis Ship
+ */
+public interface OrderedConfiguration<T>
+{
+    /**
+     * Adds an ordered object to a service's contribution. Each object has an id (which must be
+     * unique). Optionally, pre-requisites (a list of ids that must precede this object) and
+     * post-requisites (ids that must follow) can be provided.
+     * 
+     * @param id
+     *            a unique id for the object; the id will be fully qualified with the contributing
+     *            module's id
+     * @param prerequisites
+     *            comma separated list of ids, or "*", or null (aka "after")
+     * @param postrequisites
+     *            comma separated list of ids, or, "*", or null (aka "before")
+     * @parm object to add to the service's configuration
+     */
+    void add(String id, String prerequisites, String postrequisites, T object);
+
+    /**
+     * Simplified version of {@link #add(String, String, String, T)} that assumes null for the pre-
+     * and post-requisites.
+     * 
+     * @param id
+     *            a unique id for the object; the id will be fully qualified with the contributing
+     *            module's id
+     * @parm object to add to the service's configuration
+     */
+    void add(String id, T object);
+}

Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/annotations/Contribute.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/annotations/Contribute.java?rev=425234&view=auto
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/annotations/Contribute.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/annotations/Contribute.java Mon Jul 24 17:16:30 2006
@@ -0,0 +1,38 @@
+// Copyright 2006 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.annotations;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+/**
+ * Optional (but frequently used) annotation used with service contribution methods. When this
+ * annotation is not used, the name of the method is used to derive the service id that the
+ * configuration contributes to.
+ * 
+ * @author Howard M. Lewis Ship
+ */
+@Target(METHOD)
+@Retention(RUNTIME)
+@Documented
+public @interface Contribute {
+
+    /** The id of the service to which configuration will be contributed. */
+    String value();
+}

Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/def/ContributionDef.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/def/ContributionDef.java?rev=425234&view=auto
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/def/ContributionDef.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/def/ContributionDef.java Mon Jul 24 17:16:30 2006
@@ -0,0 +1,73 @@
+// Copyright 2006 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.def;
+
+import org.apache.tapestry.ioc.Configuration;
+import org.apache.tapestry.ioc.MappedConfiguration;
+import org.apache.tapestry.ioc.OrderedConfiguration;
+import org.apache.tapestry.ioc.ServiceLocator;
+
+/**
+ * Contribution to a service configuration.
+ * 
+ * @author Howard M. Lewis Ship
+ */
+public interface ContributionDef
+{
+    /** Identifies the service contributed to. */
+    String getServiceId();
+
+    /**
+     * Performs the work needed to contribute into the configuration.
+     * 
+     * @param moduleBuilder
+     *            the module builder instance associated with the contribution
+     * @param locator
+     *            allows access to services visible to the module builder instance
+     * @param configuration
+     *            the unordered configuration into which values should be loaded. This instance will
+     *            encapsulate all related error checks (such as passing of nulls or inappropriate
+     *            classes).
+     */
+    void contribute(Object moduleBuilder, ServiceLocator locator, Configuration configuration);
+
+    /**
+     * Performs the work needed to contribute into the configuration.
+     * 
+     * @param moduleBuilder
+     *            the module builder instance associated with the contribution
+     * @param locator
+     *            allows access to services visible to the module builder instance
+     * @param configuration
+     *            the ordered configuration into which values should be loaded. This instance will
+     *            encapsulate all related error checks (such as passing of nulls or inappropriate
+     *            classes).
+     */
+    void contribute(Object moduleBuilder, ServiceLocator locator, OrderedConfiguration configuration);
+
+    /**
+     * Performs the work needed to contribute into the configuration.
+     * 
+     * @param moduleBuilder
+     *            the module builder instance associated with the contribution
+     * @param locator
+     *            allows access to services visible to the module builder instance
+     * @param configuration
+     *            the mapped configuration into which values should be loaded. This instance will
+     *            encapsulate all related error checks (such as passing of null keys or values or
+     *            inappropriate classes, or duplicate keys).
+     */
+    void contribute(Object moduleBuilder, ServiceLocator locator, MappedConfiguration configuration);
+}

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/def/ModuleDef.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/def/ModuleDef.java?rev=425234&r1=425233&r2=425234&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/def/ModuleDef.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/def/ModuleDef.java Mon Jul 24 17:16:30 2006
@@ -42,6 +42,11 @@
     Set<DecoratorDef> getDecoratorDefs();
 
     /**
+     * Returns all the contribution definitions built/provided by this module.
+     */
+    Set<ContributionDef> getContributionDefs();
+
+    /**
      * Returns the module id extracted from the {@link org.apache.tapestry.ioc.annotations.Id}
      * annotation on the module builder class (or calculated from the module builder's package, if
      * the annotation is not present).

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/BaseTestCase.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/BaseTestCase.java?rev=425234&r1=425233&r2=425234&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/BaseTestCase.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/BaseTestCase.java Mon Jul 24 17:16:30 2006
@@ -20,6 +20,7 @@
 import java.io.FileOutputStream;
 import java.io.OutputStream;
 import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
 import java.net.MalformedURLException;
 import java.net.URL;
 import java.net.URLClassLoader;
@@ -30,8 +31,15 @@
 import org.apache.commons.logging.Log;
 import org.apache.hivemind.Resource;
 import org.apache.tapestry.internal.annotations.SuppressNullCheck;
+import org.apache.tapestry.ioc.Configuration;
+import org.apache.tapestry.ioc.LogSource;
+import org.apache.tapestry.ioc.MappedConfiguration;
+import org.apache.tapestry.ioc.OrderedConfiguration;
 import org.apache.tapestry.ioc.ServiceCreator;
+import org.apache.tapestry.ioc.ServiceDecorator;
+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.ServiceDef;
 import org.apache.tapestry.model.MutableComponentModel;
 import org.apache.tapestry.transform.ClassTransformation;
@@ -176,17 +184,17 @@
 
     }
 
-    protected final <T> void trainGetService(ServiceResources resources, String serviceId,
+    protected final <T> void trainGetService(ServiceLocator locator, String serviceId,
             Class<T> serviceInterface, T service)
     {
-        resources.getService(serviceId, serviceInterface);
+        locator.getService(serviceId, serviceInterface);
         setReturnValue(service);
     }
 
-    protected final <T> void trainGetService(ServiceResources resources, Class<T> serviceInterface,
+    protected final <T> void trainGetService(ServiceLocator locator, Class<T> serviceInterface,
             T service)
     {
-        resources.getService(serviceInterface);
+        locator.getService(serviceInterface);
         setReturnValue(service);
     }
 
@@ -211,6 +219,67 @@
     {
         resources.getServiceId();
         setReturnValue(serviceId);
+    }
+
+    protected final void trainCreateInterceptor(ServiceDecorator decorator, Object coreObject, Object interceptor)
+    {
+        decorator.createInterceptor(coreObject);
+        setReturnValue(interceptor);
+    }
+
+    protected final ServiceDecorator newServiceDecorator()
+    {
+        return newMock(ServiceDecorator.class);
+    }
+
+    protected final void trainGetLog(LogSource source, String serviceId, Log log)
+    {
+        source.getLog(serviceId);
+        setReturnValue(log);
+    }
+
+    protected final Method findMethod(Class clazz, String methodName)
+    {
+        for (Method method : clazz.getMethods())
+        {
+            if (method.getName().equals(methodName))
+                return method;
+        }
+    
+        throw new IllegalArgumentException(String.format(
+                "Class %s does not provide a method named '%s'.",
+                clazz.getName(),
+                methodName));
+    }
+
+    protected final Method findMethod(String methodName)
+    {
+        return findMethod(getClass(), methodName);
+    }
+
+    protected final Configuration newConfiguration()
+    {
+        return newMock(Configuration.class);
+    }
+
+    protected final ServiceLocator newServiceLocator()
+    {
+        return newMock(ServiceLocator.class);
+    }
+
+    protected final OrderedConfiguration newOrderedConfiguration()
+    {
+        return newMock(OrderedConfiguration.class);
+    }
+
+    protected final MappedConfiguration newMappedConfiguration()
+    {
+        return newMock(MappedConfiguration.class);
+    }
+
+    protected final ContributionDef newContributionDef()
+    {
+        return newMock(ContributionDef.class);
     }
 
 }

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/internal/ioc/IOCStrings.properties
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/internal/ioc/IOCStrings.properties?rev=425234&r1=425233&r2=425234&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/internal/ioc/IOCStrings.properties (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/internal/ioc/IOCStrings.properties Mon Jul 24 17:16:30 2006
@@ -43,4 +43,16 @@
 invoking-method=Invoking method {0}.
 recursive-service-build=Construction of service ''{0}'' has failed due to recursion: \
   the service depends on itself in some way. \
-  Please check {1} for references to another service that is itself dependent on service ''{0}''.
\ No newline at end of file
+  Please check {1} for references to another service that is itself dependent on service ''{0}''.
+contribution-wrong-return-type=Method {0} is named like a service contributor method, \
+  but the return type ({1}) is not appropriate (try void). The return value will be ignored.
+too-many-contribution-parameters=Service contribution method {0} contains more than one parameter of type Configuration, \
+  OrderedConfiguration, or MappedConfiguration. Exactly one such parameter is required for a service contribution method. \
+  The method has been ignored.
+no-contribution-parameter=Service contribution method {0} does not contain a parameter of type \
+  Configuration, OrderedConfiguration or MappedConfiguration. This parameter is how the method \
+  make contributions into the service's configuration. The method has been ignored.
+contribution-method-error=Error invoking service contribution method {0}: {1}
+contribution-was-null=Service contribution (to service ''{0}'', by {1}) was null and has been ignored.
+contribution-wrong-value-type=Service contribution (to service ''{0}'', by {1}) was an instance of {2}, \
+  but {3} was expected. The contribution has been ignored.
\ No newline at end of file

Added: tapestry/tapestry5/tapestry-core/trunk/src/site/apt/ioc/configuration.apt
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/site/apt/ioc/configuration.apt?rev=425234&view=auto
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/site/apt/ioc/configuration.apt (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/site/apt/ioc/configuration.apt Mon Jul 24 17:16:30 2006
@@ -0,0 +1,230 @@
+ ----
+ Tapestry IoC Configurations
+ ----
+ 
+Tapestry IoC Configurations
+
+  One of the key concepts on Tapestry IoC is <distributed configuration>. This is an idea adapted
+  from the Eclipse Plugin API and evidenced in HiveMind prior to Tapestry 5 IoC.
+  
+  So ... nice term, what does it mean?
+  
+  Distributed configuration is the key feature of Tapestry IoC that supports <extensibility>.
+  
+  The distributed part refers to the fact that <any module> may make <contributions> to 
+  any service's configuration (subject to the normal visibility rules for private services).
+  
+  This seems esoteric, but is quite handy, and is best explained by example.
+  
+  Say you are building a service that, say, maps a file extension
+  to an interface called FileServicer. There's a bunch of different services, all implementing the
+  FileServicer interface, across many different modules, each doing something specific for a
+  particular type of file (identified by the file's extension).  
+  
+  A central service uses this configuration to select a particular FileService interface:
+  
++------+
+  public FileServicer buildFileServicerDispatcher(Map<String,FileServicer> contributions)
+  {
+    return new FileServiceDispatcherImpl(contributions);
+  } 
++------+
+
+  In order to provide a value for the contribution parameter, Tapestry will <collect> contributions
+  from service contribution methods. It will ensure that the keys and values match the generic
+  types shown (String for the key, FileServicer for the value). The map will be assembled and passed into
+  the service builder method, and from there, into the FileServiceDispatcherImpl contructor.
+  
+  So where do the values come from?  Service contributor methods, methods that start with
+  "contribute":
+  
++------+
+  @Contribute("FileServicerDispatcher")
+  public void contributeFileServicers(MappedConfiguration<String,FileServicer> configuration)
+  {
+    configuration.add("txt", new TextFileServicer());
+    configuration.add("pdf", new PDFFileServicer());
+  }  
++------+
+
+  Like service builder and service decorator methods, we can inject services if we like:
+  
++------+
+  @Contribute("FileServicerDispatcher")
+  public void contributeFileServicers(MappedConfiguration<String,FileServicer> configuration,
+    @InjectService("TextFileServicer") FileServicer textFileServicer,
+    @InjectService("PDFFileServicer") FileServicer pdfFileServicer,
+  {
+    configuration.add("txt", textFileServicer);
+    configuration.add("pdf", pdfFileServicer);
+  }  
++------+  
+   
+  The <<extensibility>> comes from the fact that many different methods in all kinds 
+  of different module builder classes can make these contributions.  So, another module
+  might understand Microsoft Office formats:
+  
++------+
+  @Contribute("some.module.FileServicerDispatcher")
+  public void contributeOfficeFileServicers(MappedConfiguration<String,FileServicer> configuration)
+  {
+    configuration.add("doc", new WordFileServicer());
+    configuration.add("ppt", new PowerPointFileServicer());
+  }  
++------+
+
+  Now the FileServicerDispatcher builder method gets a Map with at least four entries in it.
+
+  Because Tapestry IoC is highly dynamic (it scans the visible JAR manifest files to identify
+  module builder classes), the FileServicerDispatcher service may be in one module, and the
+  other contributing modules (such as the one that contributes the Office file services) may be written at 
+  a much later date. With no change to the FileServicerDispatcher service or its module builder class,
+  the new services "plug into" the overall solution, simply by having their JAR's on runtime classpath. 
+  
+Configuration Types
+
+  There are three different styles of configurations (with matching contributions):
+  
+  * Unordered Collection. Contributions are simply added in and order is not important.
+  
+  * Ordered List.  Contributions are provided as an ordered list. Contributions must
+    establish the order by giving each contributed object a unique id,
+    by establishing forward and backward dependencies between the values.
+    
+  * Map. Contributions provide unique keys and corresponding values.
+  
+  []
+  
+* Unordered Collection
+
+  A service builder method can collect an unordered list of values by defining
+  a parameter of type java.util.Collection.  Further, you should parameterize
+  the type of collection.  Tapestry will identify the parameterized type
+  and ensure that all contributions match.
+  
+  One thing to remember is that the order in which contributions occur
+  is unspecified. There will be a possibly large number modules, each having
+  zero or more methods that contribute into the service.  The order in which these
+  methods are invoked is unknown.
+  
+  For example, here's a kind of Startup service that needs some Runnable
+  objects.  It doesn't care what order the Runnable objects are executed in.
+  
++------+
+  public Runnable buildStartup(final Collection<Runnable> configuration)
+  {
+    return new Runnable()
+    {
+      public void run()
+      {
+        for (Runnable contribution : configuration)
+          contribution.run();
+      }
+    };
+  }  
++------+
+
+  Here we don't even need a separate class for the implementation,
+  we use a inner class for the implementation. The point is, the configuration
+  is provided to the builder method, which passes it along to the implementation
+  of the service.  
+  
+  On the contribution side, a service contribution method sees a 
+  {{{../apidocs/org/apache/tapestry/ioc/Configuration.html}Configuration}} object:
+  
++------+
+  @Contribute("some.module.Startup")
+  public void contributeStartups(Configuration<Runnable> configuration)
+  {
+    configuration.add(new JMSStartup());
+    configuration.add(new FileSystemStartup());
+  }    
++------+
+   
+  The Configuration interface defines just a single method:  add().  This is very
+  intentional: the only thing you can do is add new items. If we passed in a Collection,
+  you might be tempted to check it for values, or remove them ... but that flys in the face
+  of the fact that the order of execution of these service contribution methods is 
+  entirely unknown.
+  
+  For readability (if Java any longer supports that concept), we've parameterized the
+  configuration parameter of the method, constraining it to instances of java.lang.Runnable,
+  so as to match the corresponding parameter.  This is optional, but often very helpful.  In any case,
+  attempting to contribute an object that doesn't extend or implement the type (Runnable) will result
+  in a runtime warning (and the value will be ignored).
+  
+  Tapestry supports only this simple form of parameterized types.  Java generics supports a wider
+  form, "wildcards", that Tapestry doesn't understand.
+  
+* Ordered List
+
+  Ordered lists are much more common. With an ordered list, the contributions are sorted into a
+  proper order before being provided to the service builder method.
+  
+  Again, the order in which service contribution methods are invoked is unknown. Therefore, the order in
+  which objects are added to the configuration is not known. Instead, we enforce an order on the items
+  <after> all the contributions have been added.  As with {{{decorator.html}service decorators}}, we
+  set the order by giving each contributed object a unique id, and identifying (by id) which items
+  must preceded it in the list, and which must follow.
+  
+  So, if we changed our Startup service to require a specific order for startup:
+  
++------+
+  public Runnable buildStartup(final List<Runnable> configuration)
+  {
+    return new Runnable()
+    {
+      public void run()
+      {
+        for (Runnable contribution : configuration)
+          contribution.run();
+      }
+    };
+  }  
++------+  
+
+  Notice that the service builder method is shielded from the details of how the items are
+  ordered. It doesn't have to know about ids and pre- and post-requisites.  By using
+  a parameter type of List, we've triggered Tapestry to collected all the ordering information.
+  
+  For our service contribution methods, we must provide a parameter
+  of type 
+  {{{../apidocs/org/apache/tapestry/ioc/OrderedConfiguration.html}OrderedConfiguration}}:
+ 
++------+
+  @Contribute("some.module.Startup")
+  public void contributeStartups(OrderedConfiguration<Runnable> configuration)
+  {
+    configuration.add("jms", new JMSStartup());
+    configuration.add("filesystem", "some.other.module.classloader", null, new FileSystemStartup());
+  }    
++------+
+  
+  Often, you don't care about ordering, the first form of the add method is used then. The id value you
+  provide will be prefixed with the contributing module's id.  The ordering algorithm will find a spot for the
+  object (here the JMSStartup instance) based on the constraints of other contributed objects.
+  
+  The second form is more specific, it allows pre-requisites and post-requisites. Each is a comma
+  separated list of ids.  Unqualified ids in the list will be qualified with the contributing module's id.
+  As elsewhere, you may use the value "*" to indicate the item must be last or first in the list.
+  
+  The object passed in may be null; this is valid, and is considered a "join point": points of reference in the
+  list that don't actually have any meaning of their own, but can be used when ordering other elements.
+  <TODO: Show example for chain of command, once that's put together.> 
+  
+  Null values, once ordered,
+  are editted out (the List passed to the service builder method does not include any nulls). Again, they are
+  allowed as placeholders, for the actual contributed objects to organize themselves around.
+  
+  
+* Mapped Configurations
+
+  As discussed in the earlier examples, mapped configurations are also supported.  The keys passed in must
+  be unique.  When conflicts occur, Tapestry will log warnings (identifying the source, in terms of invoked methods, of
+  the conflict), and ignore the conflicting value.
+  
+  The value may not be null.
+  
+    
+  
+   
\ No newline at end of file

Modified: tapestry/tapestry5/tapestry-core/trunk/src/site/apt/ioc/service.apt
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/site/apt/ioc/service.apt?rev=425234&r1=425233&r2=425234&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/site/apt/ioc/service.apt (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/site/apt/ioc/service.apt Mon Jul 24 17:16:30 2006
@@ -100,6 +100,9 @@
   
   No annotation is needed for these cases.
   
+  See also {{{configuration.html}service configuration}} for additional special cases
+  of resources that can be injected.
+  
   Example:
   
 +-----------------------------------------------------------------------------------+

Modified: tapestry/tapestry5/tapestry-core/trunk/src/site/site.xml
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/site/site.xml?rev=425234&r1=425233&r2=425234&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/site/site.xml (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/site/site.xml Mon Jul 24 17:16:30 2006
@@ -55,9 +55,10 @@
             <item name="Modules" href="ioc/module.html"/>
             <item name="Services" href="ioc/service.html"/>
             <item name="Decorators" href="ioc/decorator.html"/>
+            <item name="Configuration" href="ioc/configuration.html"/>
         </menu>
                 
-        ${reports} 
+        ${reports}
         
     </body>
 </project>

Added: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/ConfigurationWithAnnotationOtherModule.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/ConfigurationWithAnnotationOtherModule.java?rev=425234&view=auto
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/ConfigurationWithAnnotationOtherModule.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/ConfigurationWithAnnotationOtherModule.java Mon Jul 24 17:16:30 2006
@@ -0,0 +1,33 @@
+// Copyright 2006 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.internal.ioc;
+
+import org.apache.tapestry.ioc.Configuration;
+import org.apache.tapestry.ioc.annotations.Contribute;
+import org.apache.tapestry.ioc.annotations.Id;
+
+/**
+ * Used by {@link org.apache.tapestry.internal.ioc.DefaultModuleDefImpl}.
+ * 
+ * @author Howard M. Lewis Ship
+ */
+@Id("ioc.test")
+public class ConfigurationWithAnnotationOtherModule
+{
+    @Contribute("some.module.Wilma")
+    public void contributeOtherModule(Configuration configuration)
+    {
+    }
+}

Added: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/ConfigurationWithContributeAnnotationModule.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/ConfigurationWithContributeAnnotationModule.java?rev=425234&view=auto
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/ConfigurationWithContributeAnnotationModule.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/ConfigurationWithContributeAnnotationModule.java Mon Jul 24 17:16:30 2006
@@ -0,0 +1,33 @@
+// Copyright 2006 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.internal.ioc;
+
+import org.apache.tapestry.ioc.Configuration;
+import org.apache.tapestry.ioc.annotations.Contribute;
+import org.apache.tapestry.ioc.annotations.Id;
+
+/**
+ * Used by {@link org.apache.tapestry.internal.ioc.DefaultModuleDefImpl}.
+ * 
+ * @author Howard M. Lewis Ship
+ */
+@Id("ioc.test")
+public class ConfigurationWithContributeAnnotationModule
+{
+    @Contribute("Fred")
+    public void contributeSomething(Configuration configuration)
+    {
+    }
+}

Added: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/ContributionDefImplTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/ContributionDefImplTest.java?rev=425234&view=auto
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/ContributionDefImplTest.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/ContributionDefImplTest.java Mon Jul 24 17:16:30 2006
@@ -0,0 +1,187 @@
+// Copyright 2006 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.internal.ioc;
+
+import java.lang.reflect.Method;
+
+import org.apache.tapestry.internal.test.InternalBaseTestCase;
+import org.apache.tapestry.ioc.Configuration;
+import org.apache.tapestry.ioc.MappedConfiguration;
+import org.apache.tapestry.ioc.OrderedConfiguration;
+import org.apache.tapestry.ioc.ServiceLocator;
+import org.apache.tapestry.ioc.annotations.InjectService;
+import org.apache.tapestry.ioc.def.ContributionDef;
+import org.testng.annotations.Test;
+
+import static org.testng.Assert.assertEquals;
+
+/**
+ * @author Howard M. Lewis Ship
+ */
+public class ContributionDefImplTest extends InternalBaseTestCase
+{
+    private Object _toContribute;
+
+    @Test
+    public void unordered_contribution()
+    {
+        _toContribute = new Object();
+        Configuration configuration = newConfiguration();
+        ServiceLocator locator = newServiceLocator();
+
+        configuration.add(_toContribute);
+
+        replay();
+
+        Method m = findMethod("contributeUnordered");
+        ContributionDef def = new ContributionDefImpl("foo.Bar", m);
+
+        def.contribute(this, locator, configuration);
+
+        verify();
+    }
+
+    @Test
+    public void unordered_collection_with_service_lookup()
+    {
+        Configuration configuration = newConfiguration();
+        ServiceLocator locator = newServiceLocator();
+        UpcaseService service = newUpcaseService();
+
+        trainGetService(locator, "zip.Zap", UpcaseService.class, service);
+
+        configuration.add(service);
+
+        replay();
+
+        Method m = findMethod("contributeUnorderedParameter");
+        ContributionDef def = new ContributionDefImpl("foo.Bar", m);
+
+        def.contribute(this, locator, configuration);
+
+        verify();
+    }
+
+    @Test
+    public void unordered_collection_with_incorrect_configuration_parameter()
+    {
+        Configuration configuration = newConfiguration();
+        ServiceLocator locator = newServiceLocator();
+
+        Throwable t = new RuntimeException("Missing service.");
+
+        locator.getService(MappedConfiguration.class);
+        setThrowable(t);
+
+        replay();
+
+        Method m = findMethod("contributeUnorderedWrongParameter");
+        ContributionDef def = new ContributionDefImpl("foo.Bar", m);
+
+        try
+        {
+            def.contribute(this, locator, configuration);
+            unreachable();
+        }
+        catch (RuntimeException ex)
+        {
+            assertEquals(ex.getMessage(), "Error invoking service contribution method "
+                    + getClass().getName()
+                    + ".contributeUnorderedWrongParameter(MappedConfiguration): Missing service.");
+        }
+
+        verify();
+    }
+
+    // From here on in, it's an almost identical code path, so we won't be
+    // as exhaustive.
+
+    @Test
+    public void ordered_collection_with_service_lookup()
+    {
+        OrderedConfiguration configuration = newOrderedConfiguration();
+        ServiceLocator locator = newServiceLocator();
+        UpcaseService service = newUpcaseService();
+
+        trainGetService(locator, "zip.Zap", UpcaseService.class, service);
+
+        configuration.add("fred", service);
+
+        replay();
+
+        Method m = findMethod("contributeOrderedParameter");
+        ContributionDef def = new ContributionDefImpl("foo.Bar", m);
+
+        def.contribute(this, locator, configuration);
+
+        verify();
+    }
+
+    @Test
+    public void mapped_collection_with_service_lookup()
+    {
+        MappedConfiguration configuration = newMappedConfiguration();
+        ServiceLocator locator = newServiceLocator();
+        UpcaseService service = newUpcaseService();
+
+        trainGetService(locator, "zip.Zap", UpcaseService.class, service);
+
+        configuration.add("upcase", service);
+
+        replay();
+
+        Method m = findMethod("contributeMappedParameter");
+        ContributionDef def = new ContributionDefImpl("foo.Bar", m);
+
+        def.contribute(this, locator, configuration);
+
+        verify();
+    }
+
+    private UpcaseService newUpcaseService()
+    {
+        return newMock(UpcaseService.class);
+    }
+
+    public void contributeUnordered(Configuration configuration)
+    {
+        configuration.add(_toContribute);
+    }
+
+    public void contributeUnorderedParameter(Configuration configuration, @InjectService("zip.Zap")
+    UpcaseService service)
+    {
+        configuration.add(service);
+    }
+
+    public void contributeOrderedParameter(OrderedConfiguration configuration,
+            @InjectService("zip.Zap")
+            UpcaseService service)
+    {
+        configuration.add("fred", service);
+    }
+
+    public void contributeMappedParameter(MappedConfiguration configuration,
+            @InjectService("zip.Zap")
+            UpcaseService service)
+    {
+        configuration.add("upcase", service);
+    }
+
+    public void contributeUnorderedWrongParameter(MappedConfiguration configuration)
+    {
+        unreachable();
+    }
+}

Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/DefaultModuleDefImplTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/DefaultModuleDefImplTest.java?rev=425234&r1=425233&r2=425234&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/DefaultModuleDefImplTest.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/DefaultModuleDefImplTest.java Mon Jul 24 17:16:30 2006
@@ -27,6 +27,7 @@
 import org.apache.hivemind.ErrorLog;
 import org.apache.tapestry.internal.util.InternalUtils;
 import org.apache.tapestry.ioc.IOCConstants;
+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;
@@ -236,5 +237,121 @@
         assertTrue(md.getDecoratorDefs().isEmpty());
 
         verify();
+    }
+
+    @Test
+    public void contribution_without_annotation()
+    {
+        attemptConfigurationMethod(
+                SimpleModuleBuilder.class,
+                "ioc.Barney",
+                "contributeBarney(Configuration)");
+    }
+
+    @Test
+    public void contribution_with_annotation()
+    {
+        attemptConfigurationMethod(
+                ConfigurationWithContributeAnnotationModule.class,
+                "ioc.test.Fred",
+                "contributeSomething(Configuration)");
+
+    }
+
+    @Test
+    public void contribution_with_annotation_to_other_module()
+    {
+        attemptConfigurationMethod(
+                ConfigurationWithAnnotationOtherModule.class,
+                "some.module.Wilma",
+                "contributeOtherModule(Configuration)");
+    }
+
+    @Test
+    public void ordered_contribution_method()
+    {
+        attemptConfigurationMethod(
+                OrderedConfigurationModule.class,
+                "ioc.test.Ordered",
+                "contributeOrdered(OrderedConfiguration)");
+    }
+
+    @Test
+    public void mapped_contribution_method()
+    {
+        attemptConfigurationMethod(
+                MappedConfigurationModule.class,
+                "ioc.test.Mapped",
+                "contributeMapped(MappedConfiguration)");
+    }
+
+    private void attemptConfigurationMethod(Class moduleClass, String expectedServiceId,
+            String expectedMethodSignature)
+    {
+        Log log = newLog();
+
+        replay();
+
+        ModuleDef md = new DefaultModuleDefImpl(moduleClass, log);
+
+        Set<ContributionDef> defs = md.getContributionDefs();
+
+        assertEquals(defs.size(), 1);
+
+        ContributionDef cd = defs.iterator().next();
+
+        // The target service id is derived from the method name
+
+        assertEquals(cd.getServiceId(), expectedServiceId);
+        assertEquals(cd.toString(), moduleClass.getName() + "." + expectedMethodSignature);
+
+        verify();
+    }
+
+    @Test
+    public void contribution_with_too_many_parameters() throws Exception
+    {
+        Class moduleClass = TooManyContributionParametersModule.class;
+        Method m = findMethod(moduleClass, "contributeTooMany");
+
+        Log log = newLog();
+        log.warn(IOCMessages.tooManyContributionParameters(m));
+
+        replay();
+
+        ModuleDef md = new DefaultModuleDefImpl(moduleClass, log);
+
+        assertTrue(md.getContributionDefs().isEmpty());
+
+        verify();
+    }
+
+    @Test
+    public void contribution_with_no_contribution_parameter() throws Exception
+    {
+        Class moduleClass = NoUsableContributionParameterModule.class;
+        Method m = findMethod(moduleClass, "contributeNoParameter");
+
+        Log log = newLog();
+        log.warn(IOCMessages.noContributionParameter(m));
+
+        replay();
+
+        ModuleDef md = new DefaultModuleDefImpl(moduleClass, log);
+
+        assertTrue(md.getContributionDefs().isEmpty());
+
+        verify();
+    }
+
+    private Method findMethod(Class containingClass, String methodName)
+    {
+        for (Method method : containingClass.getMethods())
+        {
+            if (method.getName().equals(methodName))
+                return method;
+        }
+
+        throw new IllegalArgumentException(methodName);
     }
 }

Added: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/MappedConfigurationModule.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/MappedConfigurationModule.java?rev=425234&view=auto
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/MappedConfigurationModule.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/MappedConfigurationModule.java Mon Jul 24 17:16:30 2006
@@ -0,0 +1,32 @@
+// Copyright 2006 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.internal.ioc;
+
+import org.apache.tapestry.ioc.MappedConfiguration;
+import org.apache.tapestry.ioc.annotations.Id;
+
+/**
+ * Used by {@link org.apache.tapestry.internal.ioc.DefaultModuleDefImpl}.
+ * 
+ * @author Howard M. Lewis Ship
+ */
+@Id("ioc.test")
+public class MappedConfigurationModule
+{
+    public void contributeMapped(MappedConfiguration configuration)
+    {
+
+    }
+}

Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/ModuleImplTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/ModuleImplTest.java?rev=425234&r1=425233&r2=425234&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/ModuleImplTest.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/ModuleImplTest.java Mon Jul 24 17:16:30 2006
@@ -269,10 +269,11 @@
             registry.getService("ioc.test.PrimitiveRecursiveFoe", FoeService.class);
             unreachable();
         }
-        catch (IllegalStateException ex)
+        catch (RuntimeException ex)
         {
+            // The exception is now wrapped in a more generic exception.
             assertEquals(
-                    ex.getMessage(),
+                    ex.getCause().getMessage(),
                     "Construction of service 'ioc.test.PrimitiveRecursiveFoe' has failed due to recursion: "
                             + "the service depends on itself in some way. Please check "
                             + ModuleImplTestModule.class.getName()

Added: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/NoUsableContributionParameterModule.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/NoUsableContributionParameterModule.java?rev=425234&view=auto
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/NoUsableContributionParameterModule.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/NoUsableContributionParameterModule.java Mon Jul 24 17:16:30 2006
@@ -0,0 +1,33 @@
+// Copyright 2006 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.internal.ioc;
+
+import org.apache.tapestry.ioc.annotations.Id;
+import org.apache.tapestry.ioc.annotations.InjectService;
+
+/**
+ * Used by {@link org.apache.tapestry.internal.ioc.DefaultModuleDefImpl}.
+ * 
+ * @author Howard M. Lewis Ship
+ */
+@Id("ioc.test")
+public class NoUsableContributionParameterModule
+{
+    public void contributeNoParameter(@InjectService("foo.Bar")
+    UpcaseService service)
+    {
+
+    }
+}

Added: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/OrderedConfigurationModule.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/OrderedConfigurationModule.java?rev=425234&view=auto
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/OrderedConfigurationModule.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/OrderedConfigurationModule.java Mon Jul 24 17:16:30 2006
@@ -0,0 +1,32 @@
+// Copyright 2006 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.internal.ioc;
+
+import org.apache.tapestry.ioc.OrderedConfiguration;
+import org.apache.tapestry.ioc.annotations.Id;
+
+/**
+ * Used by {@link org.apache.tapestry.internal.ioc.DefaultModuleDefImpl}.
+ * 
+ * @author Howard M. Lewis Ship
+ */
+@Id("ioc.test")
+public class OrderedConfigurationModule
+{
+    public void contributeOrdered(OrderedConfiguration configuration)
+    {
+
+    }
+}

Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/ServiceBuilderMethodInvokerTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/ServiceBuilderMethodInvokerTest.java?rev=425234&r1=425233&r2=425234&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/ServiceBuilderMethodInvokerTest.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/ServiceBuilderMethodInvokerTest.java Mon Jul 24 17:16:30 2006
@@ -46,23 +46,6 @@
 
     private FoeService _expectedFoe;
 
-    private Method findMethod(String name)
-    {
-        return findMethod(this, name);
-    }
-
-    private Method findMethod(Object source, String name)
-    {
-        Class clazz = source.getClass();
-        for (Method m : clazz.getMethods())
-        {
-            if (m.getName().equals(name))
-                return m;
-        }
-
-        throw new RuntimeException("No method named '" + name + "'.");
-    }
-
     @Test
     public void noargs_method()
     {
@@ -138,10 +121,10 @@
 
         trainForConstructor(resources, log);
 
-        trainGetService(resources, "Foe", FoeService.class, _expectedFoe);
-
         trainIsDebugEnabled(log, false);
 
+        trainGetService(resources, "Foe", FoeService.class, _expectedFoe);
+
         replay();
 
         ServiceCreator sc = new ServiceBuilderMethodInvoker(findMethod("build_injected"), this,
@@ -239,9 +222,9 @@
 
         trainForConstructor(resources, log);
 
-        trainGetService(resources, FoeService.class, _expectedFoe);
-
         trainIsDebugEnabled(log, false);
+
+        trainGetService(resources, FoeService.class, _expectedFoe);
 
         replay();
 

Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/SimpleModuleBuilder.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/SimpleModuleBuilder.java?rev=425234&r1=425233&r2=425234&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/SimpleModuleBuilder.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/SimpleModuleBuilder.java Mon Jul 24 17:16:30 2006
@@ -14,6 +14,7 @@
 
 package org.apache.tapestry.internal.ioc;
 
+import org.apache.tapestry.ioc.Configuration;
 import org.apache.tapestry.ioc.annotations.Id;
 import org.apache.tapestry.ioc.annotations.Lifecycle;
 import org.apache.tapestry.ioc.annotations.Private;
@@ -49,5 +50,11 @@
     public <T> T decorateLogging(Class<T> serviceInterace, T delegate)
     {
         return null;
+    }
+
+    /** Minimal contribution method. */
+    public void contributeBarney(Configuration configuration)
+    {
+
     }
 }