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/18 05:07:00 UTC

svn commit: r422949 [1/2] - in /tapestry/tapestry5/tapestry-core/trunk/src: main/java/org/apache/tapestry/internal/ioc/ main/java/org/apache/tapestry/internal/pageload/ main/java/org/apache/tapestry/internal/parser/ main/java/org/apache/tapestry/intern...

Author: hlship
Date: Mon Jul 17 20:06:58 2006
New Revision: 422949

URL: http://svn.apache.org/viewvc?rev=422949&view=rev
Log:
Partially implement decorator/interceptor support.

Added:
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/DecoratorDefImpl.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/InterceptorStackBuilder.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/util/InternalUtils.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/ServiceDecorator.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/annotations/After.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/annotations/Before.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/def/DecoratorDef.java
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/ArrayDecoratorMethodModule.java
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/NoDelegateDecoratorMethodModule.java
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/PrimitiveDecoratorMethodModule.java
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/ServiceDecoratorImplTest.java
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/VoidBuilderMethodModule.java
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/VoidDecoratorMethodModule.java
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/util/InternalUtilsTest.java
Modified:
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/BasicServiceCreator.java
    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/InternalRegistry.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/Module.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/ModuleImpl.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/RegistryImpl.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/ServiceDefImpl.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/pageload/PageLoaderImpl.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/parser/TemplateParserImpl.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/java/org/apache/tapestry/util/CollectionFactory.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/internal/ioc/IOCStrings.properties
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/BasicServiceCreatorTest.java
    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/SimpleModuleBuilder.java
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/transform/InternalClassTransformationImplTest.java
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/util/CollectionFactoryTest.java

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/BasicServiceCreator.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/BasicServiceCreator.java?rev=422949&r1=422948&r2=422949&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/BasicServiceCreator.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/BasicServiceCreator.java Mon Jul 17 20:06:58 2006
@@ -14,9 +14,9 @@
 
 package org.apache.tapestry.internal.ioc;
 
+import static org.apache.tapestry.internal.ioc.IOCUtilities.calculateParametersForMethod;
 import static org.apache.tapestry.util.CollectionFactory.newMap;
 
-import java.lang.annotation.Annotation;
 import java.lang.reflect.Method;
 import java.util.Map;
 
@@ -24,8 +24,6 @@
 import org.apache.tapestry.ioc.ErrorLog;
 import org.apache.tapestry.ioc.ServiceCreator;
 import org.apache.tapestry.ioc.ServiceResources;
-import org.apache.tapestry.ioc.annotations.InjectService;
-import org.apache.tapestry.ioc.def.ServiceDef;
 
 /**
  * Basic implementation of {@link org.apache.tapestry.ioc.ServiceCreator} that handles invoking a
@@ -38,8 +36,6 @@
 {
     private final Object _moduleBuilder;
 
-    private final ServiceDef _serviceDef;
-
     private final String _serviceId;
 
     private final Map<Class, Object> _parameterDefaults = newMap();
@@ -50,11 +46,9 @@
 
     private final Method _builderMethod;
 
-    public BasicServiceCreator(ServiceDef serviceDef, Method method, Object moduleBuilder,
-            ServiceResources resources)
+    public BasicServiceCreator(Method method, Object moduleBuilder, ServiceResources resources)
     {
-        _serviceId = serviceDef.getServiceId();
-        _serviceDef = serviceDef;
+        _serviceId = resources.getServiceId();
         _builderMethod = method;
         _moduleBuilder = moduleBuilder;
         _log = resources.getErrorLog();
@@ -64,24 +58,18 @@
         _parameterDefaults.put(ServiceResources.class, resources);
         _parameterDefaults.put(ErrorLog.class, _log);
         _parameterDefaults.put(Log.class, resources.getServiceLog());
-        _parameterDefaults.put(Class.class, serviceDef.getServiceInterface());
+        _parameterDefaults.put(Class.class, resources.getServiceInterface());
     }
 
     /**
-     * Invoked from the proxy to create the actual service implementation. TODO: Interceptors, etc.
+     * Invoked from the proxy to create the actual service implementation.
      */
     public Object createService()
     {
-        Class[] parameterTypes = _builderMethod.getParameterTypes();
-        Annotation[][] annotations = _builderMethod.getParameterAnnotations();
-        int parameterCount = parameterTypes.length;
-
-        Object[] parameters = new Object[parameterCount];
-
-        for (int i = 0; i < parameterCount; i++)
-        {
-            parameters[i] = calculateParameterValue(parameterTypes[i], annotations[i]);
-        }
+        Object[] parameters = calculateParametersForMethod(
+                _builderMethod,
+                _resources,
+                _parameterDefaults);
 
         Object result = null;
 
@@ -101,42 +89,6 @@
             throw new RuntimeException(IOCMessages.builderMethodReturnedNull(
                     _builderMethod,
                     _serviceId));
-
-        return result;
-    }
-
-    private <T extends Annotation> T findAnnotation(Annotation[] annotations,
-            Class<T> annotationClass)
-    {
-        for (Annotation a : annotations)
-        {
-            if (annotationClass.isInstance(a))
-                return annotationClass.cast(a);
-        }
-
-        return null;
-    }
-
-    @SuppressWarnings("unchecked")
-    private Object calculateParameterValue(Class parameterType, Annotation[] parameterAnnotations)
-    {
-        InjectService is = findAnnotation(parameterAnnotations, InjectService.class);
-
-        if (is != null)
-        {
-            String serviceId = is.value();
-
-            return _resources.getService(serviceId, parameterType);
-        }
-
-        // See if we have any "pre-determined" parameter type to object mappings
-
-        Object result = _parameterDefaults.get(parameterType);
-
-        // This will return a non-null value, or throw an exception
-
-        if (result == null)
-            result = _resources.getService(parameterType);
 
         return result;
     }

Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/DecoratorDefImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/DecoratorDefImpl.java?rev=422949&view=auto
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/DecoratorDefImpl.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/DecoratorDefImpl.java Mon Jul 17 20:06:58 2006
@@ -0,0 +1,84 @@
+// 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 static org.apache.tapestry.util.Defense.notBlank;
+import static org.apache.tapestry.util.Defense.notNull;
+
+import java.lang.reflect.Method;
+
+import org.apache.tapestry.internal.annotations.SuppressNullCheck;
+import org.apache.tapestry.internal.util.InternalUtils;
+import org.apache.tapestry.ioc.ServiceDecorator;
+import org.apache.tapestry.ioc.ServiceResources;
+import org.apache.tapestry.ioc.def.DecoratorDef;
+import org.apache.tapestry.ioc.def.ServiceDef;
+import org.apache.tapestry.util.Defense;
+
+/**
+ * @author Howard M. Lewis Ship
+ */
+public class DecoratorDefImpl implements DecoratorDef
+{
+    private final String _decoratorId;
+
+    private final String _before;
+
+    private final String _after;
+
+    private final Method _decoratorMethod;
+
+    @SuppressNullCheck
+    public DecoratorDefImpl(String decoratorId, String before, String after, Method decoratorMethod)
+    {
+        _decoratorId = notBlank(decoratorId, "decoratorId");
+        _before = before;
+        _after = after;
+        _decoratorMethod = notNull(decoratorMethod, "decoratorMethod");
+    }
+
+    @Override
+    public String toString()
+    {
+        return InternalUtils.asString(_decoratorMethod);
+    }
+
+    public String getAfter()
+    {
+        return _after;
+    }
+
+    public String getBefore()
+    {
+        return _before;
+    }
+
+    public String getDecoratorId()
+    {
+        return _decoratorId;
+    }
+
+    public ServiceDecorator createDecorator(Object moduleBuilder, ServiceResources resources)
+    {
+        return null;
+    }
+
+    /** Currently just returns false. */
+    public boolean matches(ServiceDef serviceDef)
+    {
+        return false;
+    }
+
+}

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=422949&r1=422948&r2=422949&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 17 20:06:58 2006
@@ -14,6 +14,12 @@
 
 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.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;
@@ -22,19 +28,18 @@
 import java.util.Map;
 import java.util.Set;
 
+import org.apache.hivemind.util.IdUtils;
 import org.apache.tapestry.ioc.ErrorLog;
 import org.apache.tapestry.ioc.IOCConstants;
+import org.apache.tapestry.ioc.annotations.After;
+import org.apache.tapestry.ioc.annotations.Before;
 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.DecoratorDef;
 import org.apache.tapestry.ioc.def.ModuleDef;
 import org.apache.tapestry.ioc.def.ServiceDef;
 
-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.voidBuildMethod;
-import static org.apache.tapestry.util.CollectionFactory.newMap;
-
 /**
  * Grinds through a module builder class, identifying all the services and contributions.
  * 
@@ -43,9 +48,11 @@
 public class DefaultModuleDefImpl implements ModuleDef
 {
     /** The prefix used to identify service building methods. */
-
     private static final String BUILD_METHOD_NAME_PREFIX = "build";
 
+    /** The prefix used to identify service decorating methods. */
+    private static final String DECORATE_METHOD_NAME_PREFIX = "decorate";
+
     private final Class _builderClass;
 
     private final ErrorLog _log;
@@ -53,6 +60,9 @@
     /** Keyed on fully qualified service id. */
     private final Map<String, ServiceDef> _serviceDefs = newMap();
 
+    /** Keyed on fully qualified decorator id. */
+    private final Map<String, DecoratorDef> _decoratorDefs = newMap();
+
     private final String _moduleId;
 
     /**
@@ -142,19 +152,84 @@
         {
             String name = m.getName();
 
-            if (!name.startsWith(BUILD_METHOD_NAME_PREFIX))
+            if (name.startsWith(BUILD_METHOD_NAME_PREFIX))
+            {
+                addServiceBuildMethod(m);
                 continue;
+            }
+
+            if (name.startsWith(DECORATE_METHOD_NAME_PREFIX))
+            {
+                addDecorateMethod(m);
+                continue;
+            }
+        }
+    }
+
+    private void addDecorateMethod(Method method)
+    {
+        // TODO: methods just named "decorate"
+
+        String id = _moduleId + "." + stripMethodPrefix(method, DECORATE_METHOD_NAME_PREFIX);
+
+        // TODO: Check for duplicates
+
+        Class returnType = method.getReturnType();
+
+        if (returnType.isPrimitive() || returnType.isArray())
+        {
+            _log.warn(decoratorMethodWrongReturnType(method), null);
+            return;
+        }
 
-            addServiceBuildMethod(m);
+        if (!methodContainsObjectParameter(method))
+        {
+            _log.warn(IOCMessages.decoratorMethodNeedsDelegateParameter(method), null);
+            return;
         }
+
+        // TODO: Check that at least one parameter is type java.lang.Object,
+        // since that's how the delegate is passed in.
+
+        After afterAnnotation = method.getAnnotation(After.class);
+        Before beforeAnnotation = method.getAnnotation(Before.class);
+
+        String after = afterAnnotation == null ? null : IdUtils.qualifyList(
+                _moduleId,
+                afterAnnotation.value());
+        String before = beforeAnnotation == null ? null : IdUtils.qualifyList(
+                _moduleId,
+                beforeAnnotation.value());
+
+        DecoratorDef def = new DecoratorDefImpl(id, before, after, method);
+
+        _decoratorDefs.put(id, def);
+    }
+
+    private boolean methodContainsObjectParameter(Method method)
+    {
+        for (Class parameterType : method.getParameterTypes())
+        {
+            // TODO: But what if the type Object parameter has an injection?
+            // We should skip it and look for a different parameter.
+
+            if (parameterType.equals(Object.class))
+                return true;
+        }
+
+        return false;
+    }
+
+    private String stripMethodPrefix(Method method, String prefix)
+    {
+        return method.getName().substring(prefix.length());
     }
 
     /** Invoked for public methods that have the proper prefix. */
     private void addServiceBuildMethod(Method method)
     {
         // TODO: Methods named just "build"
-        String serviceId = _moduleId + "."
-                + method.getName().substring(BUILD_METHOD_NAME_PREFIX.length());
+        String serviceId = _moduleId + "." + stripMethodPrefix(method, BUILD_METHOD_NAME_PREFIX);
 
         ServiceDef existing = _serviceDefs.get(serviceId);
 
@@ -171,12 +246,6 @@
 
         Class returnType = method.getReturnType();
 
-        if (returnType.equals(void.class))
-        {
-            _log.warn(voidBuildMethod(method), null);
-            return;
-        }
-
         if (!returnType.isInterface())
         {
             _log.warn(buildMethodWrongReturnType(method), null);
@@ -195,4 +264,10 @@
 
         return lifecycle != null ? lifecycle.value() : IOCConstants.DEFAULT_LIFECYCLE;
     }
+
+    public Set<DecoratorDef> getDecoratorDefs()
+    {
+        return newSet(_decoratorDefs.values());
+    }
+
 }

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=422949&r1=422948&r2=422949&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 17 20:06:58 2006
@@ -14,13 +14,14 @@
 
 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.ServiceDef;
 
 /**
  * @author Howard M. Lewis Ship
@@ -32,17 +33,19 @@
 
     static String buildMethodConflict(Method conflict, String existing)
     {
-        return MESSAGES.format("build-method-conflict", conflict, existing);
+        return MESSAGES.format("build-method-conflict", asString(conflict), existing);
     }
 
-    static String voidBuildMethod(Method method)
+    static String buildMethodWrongReturnType(Method method)
     {
-        return MESSAGES.format("void-build-method", method);
+        return MESSAGES.format("build-method-wrong-return-type", asString(method), method
+                .getReturnType().getCanonicalName());
     }
 
-    static String buildMethodWrongReturnType(Method method)
+    static String decoratorMethodWrongReturnType(Method method)
     {
-        return MESSAGES.format("build-method-wrong-return-type", method);
+        return MESSAGES.format("decorator-method-wrong-return-type", asString(method), method
+                .getReturnType().getCanonicalName());
     }
 
     static String noSuchModule(String moduleId)
@@ -86,14 +89,19 @@
         return MESSAGES.format("proxy-to-string", serviceId, serviceInterface.getName());
     }
 
-    static String builderMethodError(Method m, String serviceId, Throwable cause)
+    static String builderMethodError(Method method, String serviceId, Throwable cause)
+    {
+        return MESSAGES.format("builder-method-error", asString(method), serviceId, cause);
+    }
+
+    static String decoratorMethodError(Method method, String serviceId, Throwable cause)
     {
-        return MESSAGES.format("builder-method-error", m, serviceId, cause);
+        return MESSAGES.format("decorator-method-error", asString(method), serviceId, cause);
     }
 
     static String builderMethodReturnedNull(Method method, String serviceId)
     {
-        return MESSAGES.format("builder-method-returned-null", method, serviceId);
+        return MESSAGES.format("builder-method-returned-null", asString(method), serviceId);
     }
 
     static String serviceIsPrivate(String serviceId)
@@ -128,5 +136,17 @@
     static String unknownLifecycle(String name)
     {
         return MESSAGES.format("unknown-lifecycle", name);
+    }
+
+    static String decoratorMethodNeedsDelegateParameter(Method method)
+    {
+        return MESSAGES.format("decorator-method-needs-delegate-parameter", asString(method));
+    }
+
+    static String decoratorReturnedWrongType(Method method, String serviceId, Object returned,
+            Class serviceInterface)
+    {
+        return MESSAGES.format("decorator-returned-wrong-type", new Object[]
+        { asString(method), serviceId, returned, serviceInterface.getName() });
     }
 }

Added: 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=422949&view=auto
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/IOCUtilities.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/IOCUtilities.java Mon Jul 17 20:06:58 2006
@@ -0,0 +1,94 @@
+// 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.annotation.Annotation;
+import java.lang.reflect.Method;
+import java.util.Map;
+
+import org.apache.tapestry.internal.annotations.Utility;
+import org.apache.tapestry.ioc.ServiceResources;
+import org.apache.tapestry.ioc.annotations.InjectService;
+
+/**
+ * Contains static methods used within this package.
+ * 
+ * @author Howard M. Lewis Ship
+ */
+@Utility
+public class IOCUtilities
+{
+
+    public static <T extends Annotation> T findAnnotation(Annotation[] annotations,
+            Class<T> annotationClass)
+    {
+        for (Annotation a : annotations)
+        {
+            if (annotationClass.isInstance(a))
+                return annotationClass.cast(a);
+        }
+    
+        return null;
+    }
+
+    @SuppressWarnings("unchecked")
+    public static Object calculateParameterValue(Class parameterType,
+            Annotation[] parameterAnnotations, ServiceResources serviceResources,
+            Map<Class, Object> parameterDefaults)
+    {
+        InjectService is = findAnnotation(parameterAnnotations, InjectService.class);
+    
+        if (is != null)
+        {
+            String serviceId = is.value();
+    
+            return serviceResources.getService(serviceId, parameterType);
+        }
+    
+        // See if we have any "pre-determined" parameter type to object mappings
+    
+        Object result = parameterDefaults.get(parameterType);
+    
+        // This will return a non-null value, or throw an exception
+    
+        if (result == null)
+            result = serviceResources.getService(parameterType);
+    
+        // ... so the result is never null
+    
+        return result;
+    }
+
+    public static Object[] calculateParametersForMethod(Method method,
+            ServiceResources serviceResources, Map<Class, Object> parameterDefaults)
+    {
+        Class[] parameterTypes = method.getParameterTypes();
+        Annotation[][] annotations = method.getParameterAnnotations();
+        int parameterCount = parameterTypes.length;
+    
+        Object[] parameters = new Object[parameterCount];
+    
+        for (int i = 0; i < parameterCount; i++)
+        {
+            parameters[i] = calculateParameterValue(
+                    parameterTypes[i],
+                    annotations[i],
+                    serviceResources,
+                    parameterDefaults);
+        }
+        return parameters;
+    }
+
+}

Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/InterceptorStackBuilder.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/InterceptorStackBuilder.java?rev=422949&view=auto
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/InterceptorStackBuilder.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/InterceptorStackBuilder.java Mon Jul 17 20:06:58 2006
@@ -0,0 +1,83 @@
+// 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.util.Collections;
+import java.util.List;
+
+import org.apache.tapestry.ioc.ServiceCreator;
+import org.apache.tapestry.ioc.ServiceDecorator;
+
+/**
+ * Responsible for constructing the interceptor stack, on demand, by invoking an ordered series of
+ * decorators ({@link org.apache.tapestry.ioc.def.DecoratorDef}.
+ * 
+ * @author Howard M. Lewis Ship
+ */
+public class InterceptorStackBuilder implements ServiceCreator
+{
+    private final String _serviceId;
+
+    private final ServiceCreator _coreServiceCreator;
+
+    private final Module _module;
+
+    /**
+     * @param module
+     *            the module containing the decorator method
+     * @param serviceId
+     *            identifies the service to be decorated
+     * @param coreServiceCreator
+     *            responsible for creating the core service which is then decorated with a stack of
+     *            interceptors
+     */
+    public InterceptorStackBuilder(Module module, String serviceId,
+            ServiceCreator coreServiceCreator)
+    {
+        _module = module;
+        _serviceId = serviceId;
+        _coreServiceCreator = coreServiceCreator;
+    }
+
+    public Object createService()
+    {
+        Object current = _coreServiceCreator.createService();
+
+        List<ServiceDecorator> decorators = _module.findDecoratorsForService(_serviceId);
+
+        // We get the decorators ordered according to their dependencies. However, we want to
+        // process from the last interceptor to the first, so we reverse the list.
+
+        Collections.reverse(decorators);
+
+        for (ServiceDecorator decorator : decorators)
+        {
+            Object interceptor = decorator.createInterceptor(current);
+
+            // Decorator methods may return null; this indicates that the decorator chose not to
+            // decorate.
+
+            if (interceptor != null)
+                current = interceptor;
+        }
+
+        // The stack of interceptors (plus the core service implementation) are "represented" to the
+        // outside world
+        // as the outermost interceptor. That will still be buried inside the service proxy.
+
+        return current;
+    }
+
+}

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/InternalRegistry.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/InternalRegistry.java?rev=422949&r1=422948&r2=422949&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/InternalRegistry.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/InternalRegistry.java Mon Jul 17 20:06:58 2006
@@ -14,8 +14,12 @@
 
 package org.apache.tapestry.internal.ioc;
 
+import java.util.List;
+
 import org.apache.tapestry.ioc.Registry;
+import org.apache.tapestry.ioc.ServiceDecorator;
 import org.apache.tapestry.ioc.ServiceLifecycle;
+import org.apache.tapestry.ioc.def.ServiceDef;
 
 /**
  * Internal view of the module registry, adding additional methods needed by modules.
@@ -70,4 +74,11 @@
      *             if the lifecycle name does not match a known lifecycle
      */
     ServiceLifecycle getServiceLifecycle(String lifecycle);
+
+    /**
+     * Searches for decorators for a particular service. The resulting
+     * {@link org.apache.tapestry.ioc.def.DecoratorDef}s are ordered, then converted into
+     * {@link ServiceDecorator}s.
+     */
+    List<ServiceDecorator> findDecoratorsForService(ServiceDef serviceDef);
 }

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/Module.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/Module.java?rev=422949&r1=422948&r2=422949&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/Module.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/Module.java Mon Jul 17 20:06:58 2006
@@ -15,6 +15,9 @@
 package org.apache.tapestry.internal.ioc;
 
 import java.util.Collection;
+import java.util.List;
+
+import org.apache.tapestry.ioc.ServiceDecorator;
 
 /**
  * A module within the Tapestry IoC registry. Each Module is constructed around a corresponding
@@ -53,4 +56,22 @@
      * @return a collection of strings, each a fully qualified id of a service
      */
     Collection<String> findServiceIdsForInterface(Class serviceInterface, Module module);
+
+    /**
+     * Locates all the decorators that should apply the identified service. This includes visibility
+     * rules (private services may only be decorated by decorators in the same module) and other
+     * filtering rules. The resulting list is ordered and from the list of
+     * {@link org.apache.tapestry.ioc.def.DecoratorDef}s, a list of {@link ServiceDecorator}s is
+     * returned.
+     * 
+     * @param serviceId
+     *            identifies the service to be decorated
+     * @return the ordered list of service decorators
+     */
+    List<ServiceDecorator> findDecoratorsForService(String serviceId);
+
+    /**
+     * Returns the instantiated module builder instance.
+     */
+    Object getModuleBuilder();
 }

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/ModuleImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/ModuleImpl.java?rev=422949&r1=422948&r2=422949&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/ModuleImpl.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/ModuleImpl.java Mon Jul 17 20:06:58 2006
@@ -14,8 +14,14 @@
 
 package org.apache.tapestry.internal.ioc;
 
+import static org.apache.tapestry.util.CollectionFactory.newList;
+import static org.apache.tapestry.util.CollectionFactory.newMap;
+import static org.apache.tapestry.util.Defense.notBlank;
+import static org.apache.tapestry.util.Defense.notNull;
+
 import java.lang.reflect.Modifier;
 import java.util.Collection;
+import java.util.List;
 import java.util.Map;
 
 import org.apache.hivemind.service.BodyBuilder;
@@ -27,16 +33,12 @@
 import org.apache.tapestry.internal.annotations.SuppressNullCheck;
 import org.apache.tapestry.ioc.IOCConstants;
 import org.apache.tapestry.ioc.ServiceCreator;
+import org.apache.tapestry.ioc.ServiceDecorator;
 import org.apache.tapestry.ioc.ServiceLifecycle;
 import org.apache.tapestry.ioc.ServiceResources;
 import org.apache.tapestry.ioc.def.ModuleDef;
 import org.apache.tapestry.ioc.def.ServiceDef;
 
-import static org.apache.tapestry.util.CollectionFactory.newList;
-import static org.apache.tapestry.util.CollectionFactory.newMap;
-import static org.apache.tapestry.util.Defense.notBlank;
-import static org.apache.tapestry.util.Defense.notNull;
-
 /**
  * @author Howard M. Lewis Ship
  */
@@ -48,6 +50,10 @@
 
     private Object _moduleBuilder;
 
+    /** Identifies the internal module. Services within this module are never decorated. */
+
+    private static final String INTERNAL_MODULE_ID = "tapestry.ioc";
+
     public ModuleImpl(InternalRegistry registry, ModuleDef moduleDef)
     {
         _registry = registry;
@@ -94,6 +100,14 @@
         return def.isPrivate() && this != module;
     }
 
+    /** TODO: Returns an empty list currently. */
+    public List<ServiceDecorator> findDecoratorsForService(String serviceId)
+    {
+        ServiceDef sd = _moduleDef.getServiceDef(serviceId);
+
+        return _registry.findDecoratorsForService(sd);
+    }
+
     @SuppressNullCheck
     public Collection<String> findServiceIdsForInterface(Class serviceInterface, Module module)
     {
@@ -119,10 +133,11 @@
 
     // 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
-    // Synchronized.Write annotation doesn't currently support that. Second, I'm concerned about
+    // @Synchronized.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!
+    // 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)
     {
@@ -139,41 +154,41 @@
         return result;
     }
 
-    /** Creates the service and updates the cache of created services. */
+    /**
+     * Creates the service and updates the cache of created services. Method is called from
+     * synchronized block.
+     */
     private Object create(ServiceDef def)
     {
-        if (_moduleBuilder == null)
-        {
-            Class builderClass = _moduleDef.getBuilderClass();
-
-            try
-            {
-                _moduleBuilder = builderClass.newInstance();
-            }
-            catch (Exception ex)
-            {
-                throw new RuntimeException(IOCMessages.instantiateBuilderError(
-                        builderClass,
-                        _moduleDef.getModuleId(),
-                        ex), ex);
-            }
-        }
+        ensureModuleBuilderExists();
 
-        String lifecycleName = def.getServiceLifeycle();
+        // TODO: Check for recursive service build? This could happen if the
+        // builder method for the service (or a decorator method applied to the service)
+        // takes the service as a parameter.
 
-        ServiceLifecycle lifecycle = _registry.getServiceLifecycle(lifecycleName);
+        ServiceLifecycle lifecycle = _registry.getServiceLifecycle(def.getServiceLifeycle());
 
         ServiceResources resources = new ServiceResourcesImpl(_registry, this, def);
 
-        ServiceCreator coreCreator = def.createServiceCreator(_moduleBuilder, resources);
+        // Build up a stack of operations that will be needed to instantiate the service
+        // (by the proxy, at a later date).
+
+        ServiceCreator creator = def.createServiceCreator(_moduleBuilder, resources);
+
+        creator = new LifecycleWrappedServiceCreator(lifecycle, resources, creator);
 
-        ServiceCreator creator = new LifecycleWrappedServiceCreator(lifecycle, resources,
-                coreCreator);
+        // Built in services are not decorated, ever.
+        
+        if (!_moduleDef.getModuleId().equals(INTERNAL_MODULE_ID))
+            creator = new InterceptorStackBuilder(this, def.getServiceId(), creator);
 
-        // TODO: Somewhere, in here, we have to add a chance for decorators to
-        // create interceptors for the service.
+        // TODO: Add a creator that checks to prevent recursive construction of the service.
+        // What would be a scenario where this could occur? I guess builder method for A
+        // injects B and invokes a method on B and B itself is dependant on A.
 
         // For primitive services, we just create the service right here. For non-primitive services
+        // we create the proxy the defers creation until needed.
+
         Object service = lifecycle.getCreateProxy() ? createProxy(resources, creator) : creator
                 .createService();
 
@@ -182,6 +197,36 @@
         return service;
     }
 
+    private synchronized void ensureModuleBuilderExists()
+    {
+        if (_moduleBuilder != null)
+            return;
+
+        Class builderClass = _moduleDef.getBuilderClass();
+
+        // TODO: Support additional constructors (beyond no arguments constructor)?
+
+        try
+        {
+            _moduleBuilder = builderClass.newInstance();
+        }
+        catch (Exception ex)
+        {
+            throw new RuntimeException(IOCMessages.instantiateBuilderError(builderClass, _moduleDef
+                    .getModuleId(), ex), ex);
+        }
+    }
+
+    public Object getModuleBuilder()
+    {
+        // Pretty sure that in the situations where this method is invoked, the MB will already have
+        // been instantiated, but just to be safe.
+
+        ensureModuleBuilderExists();
+
+        return _moduleBuilder;
+    }
+
     private Object createProxy(ServiceResources resources, ServiceCreator creator)
     {
         String serviceId = resources.getServiceId();
@@ -211,9 +256,10 @@
 
     private Class createProxyClass(String serviceId, Class serviceInterface, String proxyDescription)
     {
-
         String name = ClassFabUtils.generateClassName(serviceInterface);
 
+        // This is why ClassFactory has to be primitive.
+
         ClassFactory factory = _registry.getService(
                 IOCConstants.CLASS_FACTORY_SERVICE_ID,
                 ClassFactory.class,
@@ -273,6 +319,10 @@
         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 minimal.
+        // 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());
     }

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/RegistryImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/RegistryImpl.java?rev=422949&r1=422948&r2=422949&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/RegistryImpl.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/RegistryImpl.java Mon Jul 17 20:06:58 2006
@@ -14,6 +14,9 @@
 
 package org.apache.tapestry.internal.ioc;
 
+import static org.apache.tapestry.util.CollectionFactory.newList;
+import static org.apache.tapestry.util.CollectionFactory.newMap;
+
 import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
@@ -22,12 +25,12 @@
 import org.apache.hivemind.util.IdUtils;
 import org.apache.tapestry.internal.annotations.SuppressNullCheck;
 import org.apache.tapestry.ioc.Registry;
+import org.apache.tapestry.ioc.ServiceDecorator;
 import org.apache.tapestry.ioc.ServiceLifecycle;
 import org.apache.tapestry.ioc.def.ModuleDef;
+import org.apache.tapestry.ioc.def.ServiceDef;
 import org.apache.tapestry.util.CollectionFactory;
 
-import static org.apache.tapestry.util.CollectionFactory.newMap;
-
 /**
  * @author Howard M. Lewis Ship
  */
@@ -131,6 +134,12 @@
             throw new RuntimeException(IOCMessages.unknownLifecycle(lifecycle));
 
         return result;
+    }
+
+    // TODO: Real implementation
+    public List<ServiceDecorator> findDecoratorsForService(ServiceDef serviceDef)
+    {
+        return newList();
     }
 
 }

Added: 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=422949&view=auto
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/ServiceDecoratorImpl.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/ServiceDecoratorImpl.java Mon Jul 17 20:06:58 2006
@@ -0,0 +1,107 @@
+// 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 static org.apache.tapestry.internal.ioc.IOCUtilities.calculateParametersForMethod;
+import static org.apache.tapestry.util.CollectionFactory.newMap;
+
+import java.lang.reflect.Method;
+import java.util.Map;
+
+import org.apache.commons.logging.Log;
+import org.apache.tapestry.ioc.ErrorLog;
+import org.apache.tapestry.ioc.ServiceDecorator;
+import org.apache.tapestry.ioc.ServiceResources;
+
+/**
+ * A wrapper around a decorator method.
+ * 
+ * @author Howard M. Lewis Ship
+ */
+public class ServiceDecoratorImpl implements ServiceDecorator
+{
+    private final Object _moduleBuilder;
+
+    private final String _serviceId;
+
+    private final Map<Class, Object> _parameterDefaults = newMap();
+
+    private final ErrorLog _log;
+
+    private final ServiceResources _resources;
+
+    private final Method _decoratorMethod;
+
+    private final Class _serviceInterface;
+
+    public ServiceDecoratorImpl(Method method, Object moduleBuilder, ServiceResources resources)
+    {
+        _serviceId = resources.getServiceId();
+        _decoratorMethod = method;
+        _moduleBuilder = moduleBuilder;
+        _log = resources.getErrorLog();
+        _resources = resources;
+        _serviceInterface = resources.getServiceInterface();
+
+        _parameterDefaults.put(String.class, _serviceId);
+        _parameterDefaults.put(ServiceResources.class, resources);
+        _parameterDefaults.put(ErrorLog.class, _log);
+        _parameterDefaults.put(Log.class, resources.getServiceLog());
+        _parameterDefaults.put(Class.class, _serviceInterface);
+    }
+
+    public Object createInterceptor(Object delegate)
+    {
+        // Create a copy of the parameters map so that Object.class points to the delegate instance.
+
+        Map<Class, Object> parameterDefaults = newMap(_parameterDefaults);
+        parameterDefaults.put(Object.class, delegate);
+
+        Object[] parameters = calculateParametersForMethod(
+                _decoratorMethod,
+                _resources,
+                parameterDefaults);
+
+        Object result = null;
+
+        try
+        {
+            result = _decoratorMethod.invoke(_moduleBuilder, parameters);
+        }
+        catch (Exception ex)
+        {
+            throw new RuntimeException(IOCMessages.decoratorMethodError(
+                    _decoratorMethod,
+                    _serviceId,
+                    ex), ex);
+        }
+
+        if (result != null && !_serviceInterface.isInstance(result))
+        {
+            _log.warn(IOCMessages.decoratorReturnedWrongType(
+                    _decoratorMethod,
+                    _serviceId,
+                    result,
+                    _serviceInterface), null);
+
+            // Change the result to null so that we won't use the interceptor,
+            // and so that ClassCastExceptions don't occur later down the pipeline.
+
+            result = null;
+        }
+
+        return result;
+    }
+}

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/ServiceDefImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/ServiceDefImpl.java?rev=422949&r1=422948&r2=422949&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/ServiceDefImpl.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/ServiceDefImpl.java Mon Jul 17 20:06:58 2006
@@ -16,6 +16,7 @@
 
 import java.lang.reflect.Method;
 
+import org.apache.tapestry.internal.util.InternalUtils;
 import org.apache.tapestry.ioc.ServiceCreator;
 import org.apache.tapestry.ioc.ServiceResources;
 import org.apache.tapestry.ioc.def.ServiceDef;
@@ -41,9 +42,10 @@
         _private = isprivate;
     }
 
+    @Override
     public String toString()
     {
-        return _builderMethod.toString();
+        return InternalUtils.asString(_builderMethod);
     }
 
     Method getBuilderMethod()
@@ -53,7 +55,7 @@
 
     public ServiceCreator createServiceCreator(Object moduleBuilder, ServiceResources resources)
     {
-        return new BasicServiceCreator(this, _builderMethod, moduleBuilder, resources);
+        return new BasicServiceCreator(_builderMethod, moduleBuilder, resources);
     }
 
     public String getServiceId()

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/pageload/PageLoaderImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/pageload/PageLoaderImpl.java?rev=422949&r1=422948&r2=422949&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/pageload/PageLoaderImpl.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/pageload/PageLoaderImpl.java Mon Jul 17 20:06:58 2006
@@ -26,8 +26,6 @@
 import org.apache.tapestry.internal.structure.PageImpl;
 import org.apache.tapestry.internal.transform.ComponentInstantiatorSource;
 import org.apache.tapestry.internal.transform.Instantiator;
-import org.apache.tapestry.runtime.ComponentLifecycle;
-import org.apache.tapestry.util.CollectionFactory;
 
 /**
  * This implementation is not threadsafe.
@@ -89,9 +87,9 @@
     /** Works the component queue, until exausted. */
     private void workComponentQueue()
     {
-        
+
     }
-    
+
     /** For injection. */
     public void setComponentInstantiatorSource(ComponentInstantiatorSource source)
     {

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/parser/TemplateParserImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/parser/TemplateParserImpl.java?rev=422949&r1=422948&r2=422949&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/parser/TemplateParserImpl.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/parser/TemplateParserImpl.java Mon Jul 17 20:06:58 2006
@@ -17,7 +17,6 @@
 import static org.apache.tapestry.util.CollectionFactory.newList;
 import static org.apache.tapestry.util.CollectionFactory.newMap;
 
-import java.io.IOException;
 import java.net.URL;
 import java.util.List;
 import java.util.Map;

Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/util/InternalUtils.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/util/InternalUtils.java?rev=422949&view=auto
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/util/InternalUtils.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/util/InternalUtils.java Mon Jul 17 20:06:58 2006
@@ -0,0 +1,59 @@
+// 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.util;
+
+import java.lang.reflect.Method;
+
+import org.apache.tapestry.internal.annotations.Utility;
+
+/**
+ * @author Howard M. Lewis Ship
+ */
+@Utility
+public class InternalUtils
+{
+    /**
+     * Converts a method to a user presentable string consisting of the containing class name, the
+     * method name, and the short form of the parameter list (the class name of each parameter type,
+     * shorn of the package name portion).
+     * 
+     * @param method
+     * @return short string representation
+     */
+    public static String asString(Method method)
+    {
+        StringBuffer buffer = new StringBuffer();
+
+        buffer.append(method.getDeclaringClass().getName());
+        buffer.append(".");
+        buffer.append(method.getName());
+        buffer.append("(");
+
+        for (int i = 0; i < method.getParameterTypes().length; i++)
+        {
+            if (i > 0)
+                buffer.append(", ");
+
+            String name = method.getParameterTypes()[i].getSimpleName();
+
+            int dotx = name.lastIndexOf('.');
+
+            buffer.append(name.substring(dotx + 1));
+
+        }
+
+        return buffer.append(")").toString();
+    }
+}

Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/ServiceDecorator.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/ServiceDecorator.java?rev=422949&view=auto
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/ServiceDecorator.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/ServiceDecorator.java Mon Jul 17 20:06:58 2006
@@ -0,0 +1,35 @@
+// 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;
+
+/**
+ * A service decorator is derived from a {@link org.apache.tapestry.ioc.def.DecoratorDef} and is
+ * responsible for building an interceptor around an existing implementation (called the
+ * "delegate").
+ * 
+ * @author Howard M. Lewis Ship
+ */
+public interface ServiceDecorator
+{
+    /**
+     * Creates a new object implementing the same service interface as the delegate object.
+     * 
+     * @param delegate
+     *            an existing object implementing the service interface.
+     * @return a new object implementing the same service interface, or delegate or null if the
+     *         decorator chooses not to create a new interceptor.
+     */
+    public Object createInterceptor(Object delegate);
+}

Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/annotations/After.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/annotations/After.java?rev=422949&view=auto
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/annotations/After.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/annotations/After.java Mon Jul 17 20:06:58 2006
@@ -0,0 +1,42 @@
+// 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 static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+/**
+ * Used with a service decorator method to control the order in which decorations occur. Identifies
+ * decorators which should occur after the annotated decorator.
+ * 
+ * @author Howard M. Lewis Ship
+ * @see org.apache.tapestry.ioc.def.DecoratorDef
+ */
+@Target(METHOD)
+@Retention(RUNTIME)
+@Documented
+public @interface After {
+
+    /**
+     * A comma separated list of ids. Ids that are simple (unqualified) will be qualified with the
+     * appropriate module id. Alternately, the value "*" may be used to indicate the method should
+     * be ordered last.
+     */
+    String value();
+}

Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/annotations/Before.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/annotations/Before.java?rev=422949&view=auto
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/annotations/Before.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/annotations/Before.java Mon Jul 17 20:06:58 2006
@@ -0,0 +1,41 @@
+// 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 static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+/**
+ * Used with a service decorator method to control the order in which decorations occur. Identifies
+ * other decorators which should occur before the annotated decorator.
+ * 
+ * @author Howard M. Lewis Ship
+ * @see org.apache.tapestry.ioc.def.DecoratorDef
+ */
+@Target(METHOD)
+@Retention(RUNTIME)
+@Documented
+public @interface Before {
+    /**
+     * A comma separated list of ids. Ids that are simple (unqualified) will be qualified with the
+     * appropriate module id. Alternately, the value "*" may be used to indicate the method should
+     * be ordered last.
+     */
+    String value();
+}

Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/def/DecoratorDef.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/def/DecoratorDef.java?rev=422949&view=auto
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/def/DecoratorDef.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/def/DecoratorDef.java Mon Jul 17 20:06:58 2006
@@ -0,0 +1,92 @@
+// 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.ServiceDecorator;
+import org.apache.tapestry.ioc.ServiceResources;
+
+/**
+ * Definition of a service decorator, which (by default) is derived from a service decorator method.
+ * <p>
+ * A note on decorator scheduling. The scheduling is based on the desired order of <em>behavior</em>.
+ * Thus, if logging should occur before security checks, and security checks should occur before
+ * transaction management, then the desired decorator order is Logging, Security, Transactions. This
+ * might be specified as having Security occur after Logging, and Transactions occur after Security.
+ * It might also be specified by having Logging occur before "*", and Transactions occur after "*",
+ * with no specified scheduling for Security.
+ * <p>
+ * Once this order is established, decorators are <em>applied</em> in reverse order. Each
+ * decorator's job is to create an <em>interceptor</em> for the service, that delegates to the
+ * next implementation. This implies that the decorators are executed last to first. In the above
+ * example, the core service implementation would be passed to the Transaction decorator, resulting
+ * in the Transaction interceptor. The Transaction interceptor would be passed to the Security
+ * decorator, resulting in the Security interceptor. The Security interceptor would be passed to the
+ * Logging decorator, resulting in the Logging interceptor. Thus at runtime, the Logging interceptor
+ * will execute first, then delegate to the Security interceptor, which would delegate to the
+ * Transaction interceptor, which would finally delegate to the core service implementation.
+ * 
+ * @author Howard M. Lewis Ship
+ */
+public interface DecoratorDef
+{
+    /**
+     * Returns the id of the decorator, qualified by containing modules's id. The id uniquely
+     * identifies the decorator and may be used to set the order of operations for decorators.
+     * Decorators and services are in different namespaces (thus it is acceptible, even common, for
+     * a service and a decorator to have the same id).
+     */
+    String getDecoratorId();
+
+    /**
+     * Returns a comma-seperated list of decorators who should precede this decorator. May also
+     * return "*" to indicate that this decorator is always last. May return an empty string.
+     */
+
+    String getBefore();
+
+    /**
+     * Returns a comma-seperated list of decorators who should follow this decorator. May also
+     * return a "*" to indicate that this decorator is always first. May return an empty string.
+     */
+
+    String getAfter();
+
+    /**
+     * Creates an object that can perform the decoration (in the default case, by invoking the
+     * decorator method on the module builder instance.
+     * 
+     * @param moduleBuilder
+     *            the module builder instance associated with the module containing the decorator
+     *            (not necessarily the module containing the service being decorated)
+     * @param resources
+     *            the resources visible <em>to the decorator</em> (which may be in a different
+     *            module than the service being decorated). Other resource properties (serviceId,
+     *            serviceInterface, log, etc.) are for the service being decorated.
+     * @return
+     */
+    ServiceDecorator createDecorator(Object moduleBuilder, ServiceResources resources);
+
+    /**
+     * Used to determine which services may be decorated by this decorator. When decorating a
+     * service, first the decorators that target the service are identified, then ordering occurs,
+     * then the {@link ServiceDecorator}s are invoked.
+     * 
+     * @param serviceDef
+     * @return true if the decorator applies to the service
+     */
+    boolean matches(ServiceDef serviceDef);
+
+    // TODO: Filtering information ... what modules and services are decorated by the decorator
+}
\ No newline at end of file

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=422949&r1=422948&r2=422949&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 17 20:06:58 2006
@@ -24,7 +24,7 @@
  */
 public interface ModuleDef
 {
-    /** Returns the ids of the services built/provided by the module. */
+    /** Returns the fully qualified ids of the services built/provided by the module. */
     Set<String> getServiceIds();
 
     /**
@@ -35,6 +35,11 @@
      * @return service definition or null if it doesn't exist
      */
     ServiceDef getServiceDef(String serviceId);
+
+    /**
+     * Returns all the decorator definitions built/provided by this module.
+     */
+    Set<DecoratorDef> getDecoratorDefs();
 
     /**
      * Returns the module id extracted from the {@link org.apache.tapestry.ioc.annotations.Id}

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=422949&r1=422948&r2=422949&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 17 20:06:58 2006
@@ -15,7 +15,6 @@
 package org.apache.tapestry.test;
 
 import static java.lang.Thread.sleep;
-import static org.apache.tapestry.util.CollectionFactory.newList;
 
 import java.io.File;
 import java.io.FileOutputStream;

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/util/CollectionFactory.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/util/CollectionFactory.java?rev=422949&r1=422948&r2=422949&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/util/CollectionFactory.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/util/CollectionFactory.java Mon Jul 17 20:06:58 2006
@@ -15,7 +15,6 @@
 package org.apache.tapestry.util;
 
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -57,6 +56,12 @@
     public static <T> Set<T> newSet()
     {
         return new HashSet<T>();
+    }
+
+    /** Contructs a new {@link HashSet} and initializes it using the provided collection. */
+    public static <T> Set<T> newSet(Collection<T> values)
+    {
+        return new HashSet<T>(values);
     }
 
     /**

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=422949&r1=422948&r2=422949&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 17 20:06:58 2006
@@ -12,9 +12,13 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-build-method-conflict=Service building method {0} conflicts with (has the same name as, but different parameters than) previously seen method {1} and has been ignored.
-void-build-method=Method {0} appears to be a service builder method, but a void return type doesn't make sense. The method has been ignored.
-build-method-wrong-return-type=Method {0} is named like a service builder method, but the return type is not acceptible (try an interface). The method has been ignored.
+build-method-conflict=Service building method {0} conflicts with (has the same name as, but different parameters than) \
+  previously seen method {1} and has been ignored.
+build-method-wrong-return-type=Method {0} is named like a service builder method, \
+ but the return type ({1}) is not acceptible (try an interface). \
+ The method has been ignored.
+decorator-method-wrong-return-type=Method {0} is named like a service decorator method, \
+  but the return type ({1}) is not acceptible (try Object). The method has been ignored.
 missing-service=Service ''{0}'' does not exist.
 builder-locked=The Registry Builder has created the Registry, further operations are not allowed.
 module-id-conflict=Module ''{0}'' has already been defined. The duplicate definition will be ignored.
@@ -23,8 +27,16 @@
 instantiate-builder-error=Unable to instantiate class {0} as builder for module ''{1}'': {2}
 proxy-to-string=<Proxy for {0}({1})>
 builder-method-error=Error invoking service builder method {0} (for service ''{1}''): {2}
+decorator-method-error=Error invoking service decorator method {0} (for service ''{1}''): {2}
 builder-method-returned-null=Builder method {0} (for service ''{1}'') returned null.
 service-is-private=Service ''{0}'' is private, and may not be referenced outside of its containing module.
 no-service-matches-type=No (visible) service implements the interface {0}.
-many-service-matches=Service interface {0} is matched by {1,number} (visible) services: {2}.  Automatic dependency resolution requires that exactly one service implement the interface.
-unknown-lifecycle=Unknown service lifecycle ''{0}''.
\ No newline at end of file
+many-service-matches=Service interface {0} is matched by {1,number} (visible) services: {2}.  \
+  Automatic dependency resolution requires that exactly one service implement the interface.
+unknown-lifecycle=Unknown service lifecycle ''{0}''.
+decorator-method-needs-delegate-parameter=Decorator methods must a parameter for the service delegate \
+ (i.e., the object the created interceptor will delegate to). \
+ Method {0} does not include such a parameter, and has been ignored.
+decorator-returned-wrong-type=Decorator method {0} (invoked for service ''{1}'') returned {2}, \
+  which is not assignable to the {3} service interface.
+  
\ No newline at end of file

Added: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/ArrayDecoratorMethodModule.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/ArrayDecoratorMethodModule.java?rev=422949&view=auto
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/ArrayDecoratorMethodModule.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/ArrayDecoratorMethodModule.java Mon Jul 17 20:06:58 2006
@@ -0,0 +1,29 @@
+// 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;
+
+/**
+ * Used by {@link org.apache.tapestry.internal.ioc.DefaultModuleDefImplTest}.
+ * 
+ * @author Howard M. Lewis Ship
+ */
+public class ArrayDecoratorMethodModule
+{
+    public Object[] decorateArray(Object delegate)
+    {
+        return null;
+    }
+
+}

Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/BasicServiceCreatorTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/BasicServiceCreatorTest.java?rev=422949&r1=422948&r2=422949&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/BasicServiceCreatorTest.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/BasicServiceCreatorTest.java Mon Jul 17 20:06:58 2006
@@ -26,7 +26,6 @@
 import org.apache.tapestry.ioc.ServiceCreator;
 import org.apache.tapestry.ioc.ServiceResources;
 import org.apache.tapestry.ioc.annotations.InjectService;
-import org.apache.tapestry.ioc.def.ServiceDef;
 import org.testng.Assert;
 import org.testng.annotations.Test;
 
@@ -71,18 +70,16 @@
     @Test
     public void noargs_method()
     {
-        ServiceDef def = newServiceDef();
         ServiceResources resources = newServiceResources();
         ErrorLog errorLog = newErrorLog();
         Log log = newLog();
         _fie = newFieService();
 
-        trainForConstructor(def, resources, errorLog, log);
+        trainForConstructor(resources, errorLog, log);
 
         replay();
 
-        ServiceCreator sc = new BasicServiceCreator(def, findMethod("build_noargs"), this,
-                resources);
+        ServiceCreator sc = new BasicServiceCreator(findMethod("build_noargs"), this, resources);
 
         Object actual = sc.createService();
 
@@ -91,22 +88,20 @@
         verify();
     }
 
-    private void trainForConstructor(ServiceDef def, ServiceResources resources, ErrorLog errorLog,
-            Log log)
+    private void trainForConstructor(ServiceResources resources, ErrorLog errorLog, Log log)
     {
-        trainGetServiceId(def, SERVICE_ID);
+        trainGetServiceId(resources, SERVICE_ID);
 
         trainGetErrorLog(resources, errorLog);
 
         trainGetServiceLog(resources, log);
 
-        trainGetServiceInterface(def, FieService.class);
+        trainGetServiceInterface(resources, FieService.class);
     }
 
     @Test
     public void method_with_args()
     {
-        ServiceDef def = newServiceDef();
         ServiceResources resources = newServiceResources();
         ErrorLog errorLog = newErrorLog();
         Log log = newLog();
@@ -119,11 +114,11 @@
 
         _fie = newFieService();
 
-        trainForConstructor(def, resources, errorLog, log);
+        trainForConstructor(resources, errorLog, log);
 
         replay();
 
-        ServiceCreator sc = new BasicServiceCreator(def, findMethod("build_args"), this, resources);
+        ServiceCreator sc = new BasicServiceCreator(findMethod("build_args"), this, resources);
 
         Object actual = sc.createService();
 
@@ -135,7 +130,6 @@
     @Test
     public void injected_service_method()
     {
-        ServiceDef def = newServiceDef();
         ServiceResources resources = newServiceResources();
         ErrorLog errorLog = newErrorLog();
         Log log = newLog();
@@ -143,14 +137,13 @@
         _fie = newFieService();
         _expectedFoe = newFoe();
 
-        trainForConstructor(def, resources, errorLog, log);
+        trainForConstructor(resources, errorLog, log);
 
         trainGetService(resources, "Foe", FoeService.class, _expectedFoe);
 
         replay();
 
-        ServiceCreator sc = new BasicServiceCreator(def, findMethod("build_injected"), this,
-                resources);
+        ServiceCreator sc = new BasicServiceCreator(findMethod("build_injected"), this, resources);
 
         Object actual = sc.createService();
 
@@ -167,19 +160,17 @@
     @Test
     public void builder_method_returns_null()
     {
-        ServiceDef def = newServiceDef();
         ServiceResources resources = newServiceResources();
         ErrorLog errorLog = newErrorLog();
         Log log = newLog();
 
         _fie = null;
 
-        trainForConstructor(def, resources, errorLog, log);
+        trainForConstructor(resources, errorLog, log);
 
         replay();
 
-        ServiceCreator sc = new BasicServiceCreator(def, findMethod("build_noargs"), this,
-                resources);
+        ServiceCreator sc = new BasicServiceCreator(findMethod("build_noargs"), this, resources);
 
         try
         {
@@ -188,12 +179,9 @@
         }
         catch (RuntimeException ex)
         {
-            Assert
-                    .assertEquals(
-                            ex.getMessage(),
-                            "Builder method public org.apache.tapestry.internal.ioc.FieService "
-                                    + "org.apache.tapestry.internal.ioc.BasicServiceCreatorTest.build_noargs() "
-                                    + "(for service 'ioc.Fie') returned null.");
+            Assert.assertEquals(ex.getMessage(), "Builder method "
+                    + "org.apache.tapestry.internal.ioc.BasicServiceCreatorTest.build_noargs() "
+                    + "(for service 'ioc.Fie') returned null.");
         }
 
         verify();
@@ -202,18 +190,17 @@
     @Test
     public void builder_method_failed()
     {
-        ServiceDef def = newServiceDef();
         ServiceResources resources = newServiceResources();
         ErrorLog errorLog = newErrorLog();
         Log log = newLog();
 
         _fie = null;
 
-        trainForConstructor(def, resources, errorLog, log);
+        trainForConstructor(resources, errorLog, log);
 
         replay();
 
-        ServiceCreator sc = new BasicServiceCreator(def, findMethod("build_fail"), this, resources);
+        ServiceCreator sc = new BasicServiceCreator(findMethod("build_fail"), this, resources);
 
         try
         {
@@ -222,11 +209,9 @@
         }
         catch (RuntimeException ex)
         {
-            assertEquals(
-                    ex.getMessage(),
-                    "Error invoking service builder method public org.apache.tapestry.internal.ioc.FieService "
-                            + "org.apache.tapestry.internal.ioc.BasicServiceCreatorTest.build_fail() "
-                            + "(for service 'ioc.Fie'): java.lang.reflect.InvocationTargetException");
+            assertEquals(ex.getMessage(), "Error invoking service builder method "
+                    + "org.apache.tapestry.internal.ioc.BasicServiceCreatorTest.build_fail() "
+                    + "(for service 'ioc.Fie'): java.lang.reflect.InvocationTargetException");
 
             InvocationTargetException inner1 = (InvocationTargetException) ex.getCause();
             RuntimeException inner2 = (RuntimeException) inner1.getTargetException();
@@ -240,7 +225,6 @@
     @Test
     public void auto_dependency()
     {
-        ServiceDef def = newServiceDef();
         ServiceResources resources = newServiceResources();
         ErrorLog errorLog = newErrorLog();
         Log log = newLog();
@@ -248,7 +232,7 @@
         _fie = newFieService();
         _expectedFoe = newFoeService();
 
-        trainForConstructor(def, resources, errorLog, log);
+        trainForConstructor(resources, errorLog, log);
 
         Method method = findMethod("build_auto");
 
@@ -256,7 +240,7 @@
 
         replay();
 
-        ServiceCreator sc = new BasicServiceCreator(def, method, this, resources);
+        ServiceCreator sc = new BasicServiceCreator(method, this, resources);
 
         Object actual = sc.createService();