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/22 15:57:04 UTC

svn commit: r424577 - in /tapestry/tapestry5/tapestry-core/trunk/src: main/java/org/apache/tapestry/annotations/ main/java/org/apache/tapestry/internal/ioc/ main/java/org/apache/tapestry/internal/ioc/services/ main/java/org/apache/tapestry/ioc/ test/ja...

Author: hlship
Date: Sat Jul 22 06:57:04 2006
New Revision: 424577

URL: http://svn.apache.org/viewvc?rev=424577&view=rev
Log:
Move TapestryIOCModule under src/main/java, where it belongs.
Move methods of IdUtils to IOCUtilities.
Add the @Match annotation, used to "target" decorators at services.
Start work on a LoggingDecorator service.

Added:
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/annotations/Match.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/TapestryIOCModule.java
      - copied, changed from r424052, tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/TapestryIOCModule.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/services/Logger.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/services/LoggingDecoratorImpl.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/LoggingDecorator.java
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/IOCUtilitiesTest.java
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/services/LoggerTest.java
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/ioc/IOCUtilitiesTest.java
      - copied, changed from r424052, tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/ioc/TestIdUtils.java
Removed:
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/IdUtils.java
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/TapestryIOCModule.java
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/ioc/TestIdUtils.java
Modified:
    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/DefaultModuleDefImpl.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/RegistryImpl.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/IOCUtilities.java

Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/annotations/Match.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/annotations/Match.java?rev=424577&view=auto
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/annotations/Match.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/annotations/Match.java Sat Jul 22 06:57:04 2006
@@ -0,0 +1,36 @@
+package org.apache.tapestry.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;
+
+/**
+ * Optional, but typically used, annotation for service decorator methods, used to define which
+ * services the decorator applies to. This annotation defines a number of <em>patterns</em> that
+ * allow services across multiple modules to be selected. A decorator is applied to a service if any
+ * of its patterns match the service.
+ * <p>
+ * TODO: Describe pattern glob-match syntax
+ * <p>
+ * When the Match annotation is not supplied, then the decorator only applies to a single service:
+ * the service whose id matches the decorators id; that is, method <code>decorateMyService()</code>
+ * would decorate only the service provided by the <code>buildMyService()</code> method, within
+ * the same module.
+ * 
+ * @author Howard M. Lewis Ship
+ */
+@Target(METHOD)
+@Retention(RUNTIME)
+@Documented
+public @interface Match {
+
+    /**
+     * Defines a list of patterns matched against potential service ids to identify to which
+     * services the decorator applies. A decorator is applied if <em>any</em> of the patterns
+     * match.
+     */
+    String[] value();
+}

Modified: 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=424577&r1=424576&r2=424577&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/DecoratorDefImpl.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/DecoratorDefImpl.java Sat Jul 22 06:57:04 2006
@@ -14,6 +14,8 @@
 
 package org.apache.tapestry.internal.ioc;
 
+import static org.apache.tapestry.internal.ioc.IOCUtilities.decoratorMatch;
+import static org.apache.tapestry.ioc.IOCUtilities.extractModuleId;
 import static org.apache.tapestry.util.Defense.notBlank;
 import static org.apache.tapestry.util.Defense.notNull;
 
@@ -25,7 +27,6 @@
 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
@@ -40,13 +41,17 @@
 
     private final Method _decoratorMethod;
 
+    private final String[] _patterns;
+
     @SuppressNullCheck
-    public DecoratorDefImpl(String decoratorId, String before, String after, Method decoratorMethod)
+    public DecoratorDefImpl(String decoratorId, String before, String after,
+            Method decoratorMethod, String[] patterns)
     {
         _decoratorId = notBlank(decoratorId, "decoratorId");
         _before = before;
         _after = after;
         _decoratorMethod = notNull(decoratorMethod, "decoratorMethod");
+        _patterns = notNull(patterns, "patterns");
     }
 
     @Override
@@ -72,12 +77,23 @@
 
     public ServiceDecorator createDecorator(Object moduleBuilder, ServiceResources resources)
     {
-        return null;
+        return new ServiceDecoratorImpl(_decoratorMethod, moduleBuilder, resources);
     }
 
-    /** Currently just returns false. */
+    /**
+     * Returns true if <em>any</em> provided pattern matches the id of the service.
+     */
     public boolean matches(ServiceDef serviceDef)
     {
+        String serviceId = serviceDef.getServiceId();
+        String decoratorModuleId = extractModuleId(_decoratorId);
+
+        for (String pattern : _patterns)
+        {
+            if (decoratorMatch(serviceId, decoratorModuleId, pattern))
+                return true;
+        }
+
         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=424577&r1=424576&r2=424577&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 Sat Jul 22 06:57:04 2006
@@ -17,6 +17,7 @@
 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;
 
@@ -29,8 +30,8 @@
 import java.util.Set;
 
 import org.apache.commons.logging.Log;
+import org.apache.tapestry.annotations.Match;
 import org.apache.tapestry.ioc.IOCConstants;
-import org.apache.tapestry.ioc.IdUtils;
 import org.apache.tapestry.ioc.annotations.After;
 import org.apache.tapestry.ioc.annotations.Before;
 import org.apache.tapestry.ioc.annotations.Id;
@@ -41,16 +42,18 @@
 import org.apache.tapestry.ioc.def.ServiceDef;
 
 /**
- * Grinds through a module builder class, identifying all the services and contributions.
+ * 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
+ * contributor methods).
  * 
  * @author Howard M. Lewis Ship
  */
 public class DefaultModuleDefImpl implements ModuleDef
 {
-    /** The prefix used to identify service building methods. */
+    /** The prefix used to identify service builder methods. */
     private static final String BUILD_METHOD_NAME_PREFIX = "build";
 
-    /** The prefix used to identify service decorating methods. */
+    /** The prefix used to identify service decorator methods. */
     private static final String DECORATE_METHOD_NAME_PREFIX = "decorate";
 
     private final Class _builderClass;
@@ -154,23 +157,24 @@
 
             if (name.startsWith(BUILD_METHOD_NAME_PREFIX))
             {
-                addServiceBuildMethod(m);
+                addServiceDef(m);
                 continue;
             }
 
             if (name.startsWith(DECORATE_METHOD_NAME_PREFIX))
             {
-                addDecorateMethod(m);
+                addDecoratorDef(m);
                 continue;
             }
         }
     }
 
-    private void addDecorateMethod(Method method)
+    private void addDecoratorDef(Method method)
     {
         // TODO: methods just named "decorate"
 
-        String id = _moduleId + "." + stripMethodPrefix(method, DECORATE_METHOD_NAME_PREFIX);
+        String simpleDecoratorId = stripMethodPrefix(method, DECORATE_METHOD_NAME_PREFIX);
+        String id = _moduleId + "." + simpleDecoratorId;
 
         // TODO: Check for duplicates
 
@@ -193,15 +197,18 @@
 
         After afterAnnotation = method.getAnnotation(After.class);
         Before beforeAnnotation = method.getAnnotation(Before.class);
+        Match match = method.getAnnotation(Match.class);
 
-        String after = afterAnnotation == null ? null : IdUtils.qualifyList(
+        String after = afterAnnotation == null ? null : qualifySimpleIdList(
                 _moduleId,
                 afterAnnotation.value());
-        String before = beforeAnnotation == null ? null : IdUtils.qualifyList(
+        String before = beforeAnnotation == null ? null : qualifySimpleIdList(
                 _moduleId,
                 beforeAnnotation.value());
+        String[] patterns = match == null ? new String[]
+        { simpleDecoratorId } : match.value();
 
-        DecoratorDef def = new DecoratorDefImpl(id, before, after, method);
+        DecoratorDef def = new DecoratorDefImpl(id, before, after, method, patterns);
 
         _decoratorDefs.put(id, def);
     }
@@ -226,13 +233,12 @@
     }
 
     /** Invoked for public methods that have the proper prefix. */
-    private void addServiceBuildMethod(Method method)
+    private void addServiceDef(Method method)
     {
         // TODO: Methods named just "build"
         String serviceId = _moduleId + "." + stripMethodPrefix(method, BUILD_METHOD_NAME_PREFIX);
 
         ServiceDef existing = _serviceDefs.get(serviceId);
-
         if (existing != null)
         {
             _log.warn(buildMethodConflict(method, existing.toString()), null);

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=424577&r1=424576&r2=424577&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 Sat Jul 22 06:57:04 2006
@@ -28,9 +28,18 @@
  * @author Howard M. Lewis Ship
  */
 @Utility
-public class IOCUtilities
+public final class IOCUtilities
 {
-
+    /**
+     * Finds a specific annotation type within an array of annotations.
+     * 
+     * @param <T>
+     * @param annotations
+     *            to search
+     * @param annotationClass
+     *            to match
+     * @return the annotation instance, if found, or null otherwise
+     */
     public static <T extends Annotation> T findAnnotation(Annotation[] annotations,
             Class<T> annotationClass)
     {
@@ -39,7 +48,7 @@
             if (annotationClass.isInstance(a))
                 return annotationClass.cast(a);
         }
-    
+
         return null;
     }
 
@@ -49,25 +58,25 @@
             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;
     }
 
@@ -77,9 +86,9 @@
         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(
@@ -88,7 +97,86 @@
                     serviceResources,
                     parameterDefaults);
         }
+
         return parameters;
+    }
+
+    /**
+     * Checks to see if a string matches against a "glob pattern". A glob pattern is a string to
+     * match that may contain a leading or trailing asterisk ("*"), or may consist of only an
+     * asterisk. The asterisk matches any sequence of characters (including the empty string). The
+     * term "glob" comes from POSIX tools, though this is a very limited subset.
+     * <p>
+     * I'm not happy with the efficiency and utility of this class, so for the moment, it's going to
+     * stay as internal.
+     * 
+     * @param input
+     * @param pattern
+     * @return true if the input matches the pattern, false otherwise
+     */
+    public static boolean globMatch(String input, String pattern)
+    {
+        if (pattern.equals("*"))
+            return true;
+
+        boolean globPrefix = pattern.startsWith("*");
+        boolean globSuffix = pattern.endsWith("*");
+
+        if (globPrefix && globSuffix)
+        {
+            String substring = pattern.substring(1, pattern.length() - 1);
+            return input.contains(substring);
+        }
+
+        if (globPrefix)
+            return input.endsWith(pattern.substring(1));
+
+        if (globSuffix)
+            return input.startsWith(pattern.substring(0, pattern.length() - 1));
+
+        // No globs!
+
+        return input.equals(pattern);
+    }
+
+    /**
+     * Used by the default implementation of {@link org.apache.tapestry.ioc.def.DecoratorDef} to
+     * match a pattern against a prospective service id. The pattern is either simple or qualified.
+     * A simple pattern contains no '.' character, in which case the pattern is matched against just
+     * the simple id portion of the service id and a match can only occur within the same module as
+     * the decorator. Alternately, with a complex pattern, such as <code>foo.bar.*.*Data*</code>
+     * is really two matches: <code>foo.bar.*</code> against the module id portion of the
+     * service's id, and <code>*Data*</code> against the unqualified portion of the service id.
+     * The split occurs on the <em>last</em> period character.
+     * 
+     * @param serviceId
+     *            the fully qualified id of the service to match against
+     * @param decoratorModuleId
+     *            the id of the module containing the decorator, used when the pattern is simple
+     * @param pattern
+     *            the pattern to match against serviceId
+     * @return true if the service id matches the pattern, false otherwise
+     */
+    public static boolean decoratorMatch(String serviceId, String decoratorModuleId, String pattern)
+    {
+        int dotx = serviceId.lastIndexOf('.');
+
+        String serviceModuleId = serviceId.substring(0, dotx);
+        String serviceSimpleId = serviceId.substring(dotx + 1);
+
+        dotx = pattern.lastIndexOf('.');
+
+        // Simple patterns only match within their own module and the pattern
+        // matches the unqualified service id
+
+        if (dotx <= 0)
+            return serviceModuleId.equals(decoratorModuleId) && globMatch(serviceSimpleId, pattern);
+
+        String moduleIdPattern = pattern.substring(0, dotx);
+        String servicePattern = pattern.substring(dotx + 1);
+
+        return globMatch(serviceModuleId, moduleIdPattern)
+                && globMatch(serviceSimpleId, servicePattern);
     }
 
 }

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=424577&r1=424576&r2=424577&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 Sat Jul 22 06:57:04 2006
@@ -26,7 +26,7 @@
 import org.apache.commons.logging.Log;
 import org.apache.tapestry.internal.annotations.SuppressNullCheck;
 import org.apache.tapestry.internal.util.Orderer;
-import org.apache.tapestry.ioc.IdUtils;
+import org.apache.tapestry.ioc.IOCUtilities;
 import org.apache.tapestry.ioc.LogSource;
 import org.apache.tapestry.ioc.Registry;
 import org.apache.tapestry.ioc.ServiceDecorator;
@@ -87,7 +87,7 @@
 
     private Module locateModuleForService(String serviceId)
     {
-        String moduleId = IdUtils.extractModule(serviceId);
+        String moduleId = IOCUtilities.extractModuleId(serviceId);
 
         Module module = _modules.get(moduleId);
 
@@ -171,7 +171,7 @@
 
         for (DecoratorDef dd : ordered)
         {
-            String decoratorModuleId = IdUtils.extractModule(dd.getDecoratorId());
+            String decoratorModuleId = IOCUtilities.extractModuleId(dd.getDecoratorId());
 
             // Whenever the module id containing the decorator changes,
             // "refresh" the resources, etc., to point to the (new) module.
@@ -222,7 +222,7 @@
 
     private Set<DecoratorDef> findDecoratorsDefsForPrivateService(ServiceDef serviceDef)
     {
-        String moduleId = IdUtils.extractModule(serviceDef.getServiceId());
+        String moduleId = IOCUtilities.extractModuleId(serviceDef.getServiceId());
         Module module = _modules.get(moduleId);
 
         return module.findMatchingDecoratorDefs(serviceDef);

Copied: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/TapestryIOCModule.java (from r424052, tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/TapestryIOCModule.java)
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/TapestryIOCModule.java?p2=tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/TapestryIOCModule.java&p1=tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/TapestryIOCModule.java&r1=424052&r2=424577&rev=424577&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/TapestryIOCModule.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/TapestryIOCModule.java Sat Jul 22 06:57:04 2006
@@ -15,10 +15,18 @@
 package org.apache.tapestry.internal.ioc;
 
 import org.apache.tapestry.internal.ioc.services.ClassFactoryImpl;
+import org.apache.tapestry.internal.ioc.services.LoggingDecoratorImpl;
+import org.apache.tapestry.ioc.LoggingDecorator;
 import org.apache.tapestry.ioc.annotations.Id;
+import org.apache.tapestry.ioc.annotations.InjectService;
 import org.apache.tapestry.ioc.annotations.Lifecycle;
 import org.apache.tapestry.ioc.services.ClassFactory;
 
+/**
+ * Defines the base set of services for the Tapestry IOC container.
+ * 
+ * @author Howard M. Lewis Ship
+ */
 @Id("tapestry.ioc")
 public class TapestryIOCModule
 {
@@ -26,5 +34,11 @@
     public ClassFactory buildClassFactory()
     {
         return new ClassFactoryImpl();
+    }
+
+    public LoggingDecorator buildLoggingDecorator(@InjectService("ClassFactory")
+    ClassFactory classFactory)
+    {
+        return new LoggingDecoratorImpl(classFactory);
     }
 }

Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/services/Logger.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/services/Logger.java?rev=424577&view=auto
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/services/Logger.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/services/Logger.java Sat Jul 22 06:57:04 2006
@@ -0,0 +1,155 @@
+package org.apache.tapestry.internal.ioc.services;
+
+import static java.lang.String.format;
+
+import java.util.Iterator;
+
+import org.apache.commons.logging.Log;
+
+/**
+ * Used by {@link org.apache.tapestry.internal.ioc.services.LoggingDecoratorImpl} to delegate out
+ * logging behavior to a seperate object (helps ensure no naming conflicts).
+ * 
+ * @author Howard M. Lewis Ship
+ */
+public final class Logger
+{
+    private final Log _log;
+
+    private static final String ENTER = "ENTER";
+
+    private static final String EXIT = " EXIT";
+
+    private static final String FAIL = " FAIL";
+
+    public Logger(Log log)
+    {
+        _log = log;
+    }
+
+    /** Returns true if the debugging is enabled for the underlying Log. */
+    public boolean isDebugEnabled()
+    {
+        return _log.isDebugEnabled();
+    }
+
+    /**
+     * Invoked when a method is first entered
+     * 
+     * @param name
+     *            of the method
+     * @param arguments
+     */
+    public void entry(String name, Object[] arguments)
+    {
+        StringBuffer buffer = new StringBuffer();
+
+        buffer.append(format("[%s] %s(", ENTER, name));
+
+        for (int i = 0; i < arguments.length; i++)
+        {
+            if (i > 0)
+                buffer.append(", ");
+
+            convert(buffer, arguments[i]);
+        }
+
+        buffer.append(")");
+
+        _log.debug(buffer.toString());
+    }
+
+    private void convert(StringBuffer buffer, Object object)
+    {
+        if (object == null)
+        {
+            buffer.append("null");
+            return;
+        }
+
+        // Minimal, alas: Doesn't handle embedded quotes and other
+        // characters. Really want to convert the string back to what it
+        // would look like as source code.
+
+        if (object instanceof String)
+        {
+            buffer.append("\"");
+            buffer.append(object.toString());
+            buffer.append("\"");
+            return;
+        }
+
+        if (object instanceof Object[])
+        {
+            Object[] values = (Object[]) object;
+            buffer.append('{');
+
+            for (int i = 0; i < values.length; i++)
+            {
+                if (i > 0)
+                    buffer.append(", ");
+
+                convert(buffer, values[i]);
+            }
+
+            buffer.append('}');
+            return;
+        }
+
+        if (object instanceof Iterable)
+        {
+            Iterable itr = (Iterable) object;
+            boolean first = true;
+
+            buffer.append('[');
+            Iterator i = itr.iterator();
+            while (i.hasNext())
+            {
+                if (!first)
+                    buffer.append(", ");
+
+                convert(buffer, i.next());
+                first = false;
+            }
+            buffer.append(']');
+            return;
+        }
+
+        // Might need to add a few more, for things like character values ...
+
+        buffer.append(object.toString());
+    }
+
+    /**
+     * Invoked when a method returns a value
+     * 
+     * @param name
+     *            of the method
+     * @param result
+     *            the return value for the method invocation
+     */
+    public void exit(String name, Object result)
+    {
+        StringBuffer buffer = new StringBuffer();
+
+        buffer.append(format("[%s] %s [", EXIT, name));
+
+        convert(buffer, result);
+
+        buffer.append(']');
+
+        _log.debug(buffer.toString());
+    }
+
+    /** Invoked when void method finishes succesfully. */
+    public void voidExit(String name)
+    {
+        _log.debug(format("[%s] %s", EXIT, name));
+    }
+
+    /** Invoked when method invocation instead throws an exception. */
+    public void fail(String name, Throwable t)
+    {
+        _log.debug(format("[%s] %s -- %s", FAIL, name, t.getClass().getName()), t);
+    }
+}

Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/services/LoggingDecoratorImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/services/LoggingDecoratorImpl.java?rev=424577&view=auto
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/services/LoggingDecoratorImpl.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/services/LoggingDecoratorImpl.java Sat Jul 22 06:57:04 2006
@@ -0,0 +1,23 @@
+package org.apache.tapestry.internal.ioc.services;
+
+import org.apache.tapestry.ioc.LoggingDecorator;
+import org.apache.tapestry.ioc.services.ClassFactory;
+
+/**
+ * @author Howard M. Lewis Ship
+ */
+public class LoggingDecoratorImpl implements LoggingDecorator
+{
+    private final ClassFactory _classFactory;
+
+    public LoggingDecoratorImpl(ClassFactory classFactory)
+    {
+        _classFactory = classFactory;
+    }
+
+    public <T> T createLoggingInterceptor(Class<T> serviceInterface, T delegate)
+    {
+        return null;
+    }
+
+}

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/IOCUtilities.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/IOCUtilities.java?rev=424577&r1=424576&r2=424577&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/IOCUtilities.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/IOCUtilities.java Sat Jul 22 06:57:04 2006
@@ -21,10 +21,17 @@
 import java.util.Enumeration;
 import java.util.jar.Manifest;
 
+import org.apache.tapestry.internal.annotations.SuppressNullCheck;
 import org.apache.tapestry.internal.annotations.Utility;
 
 import static org.apache.tapestry.ioc.IOCConstants.MODULE_BUILDER_MANIFEST_ENTRY_NAME;
 
+/**
+ * A collection of utility methods for a couple of different areas, including creating the initial
+ * {@link org.apache.tapestry.ioc.Registry}.
+ * 
+ * @author Howard M. Lewis Ship
+ */
 @Utility
 public final class IOCUtilities
 {
@@ -125,5 +132,71 @@
                 // Ignore.
             }
         }
+    }
+
+    public static boolean match(String serviceId, String moduleId, String pattern)
+    {
+        return true;
+    }
+
+    /**
+     * Returns a fully qualfied id. If the id contains a '.', then it is returned unchanged.
+     * Otherwise, the module's id is prefixed (with a seperator '.') and returned;
+     */
+    public static String toQualifiedId(String moduleId, String id)
+    {
+        if (id.indexOf('.') > 0)
+            return id;
+
+        return moduleId + "." + id;
+    }
+
+    /**
+     * Qualifies a list of interceptor service ids provided for an interceptor contribution. The
+     * special value "*" is not qualified.
+     */
+    @SuppressNullCheck
+    public static String qualifySimpleIdList(String sourceModuleId, String list)
+    {
+        if (list == null || list.equals("") || list.equals("*"))
+            return list;
+
+        String[] items = list.split("\\s*,\\s*");
+
+        StringBuffer buffer = new StringBuffer();
+
+        for (int i = 0; i < items.length; i++)
+        {
+            if (i > 0)
+                buffer.append(",");
+
+            buffer.append(toQualifiedId(sourceModuleId, items[i]));
+        }
+
+        return buffer.toString();
+    }
+
+    /**
+     * Removes the module name from a fully qualified id
+     */
+    public static String toSimpleId(String id)
+    {
+        int lastPoint = id.lastIndexOf('.');
+        if (lastPoint > 0)
+            return id.substring(lastPoint + 1, id.length());
+
+        return id;
+    }
+
+    /**
+     * Extracts the module name from a fully qualified id Returns null if id contains no module
+     */
+    public static String extractModuleId(String id)
+    {
+        int lastPoint = id.lastIndexOf('.');
+        if (lastPoint > 0)
+            return id.substring(0, lastPoint);
+
+        return null;
     }
 }

Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/LoggingDecorator.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/LoggingDecorator.java?rev=424577&view=auto
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/LoggingDecorator.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/LoggingDecorator.java Sat Jul 22 06:57:04 2006
@@ -0,0 +1,23 @@
+package org.apache.tapestry.ioc;
+
+/**
+ * Service that can create a logging interceptor that wraps around a service implementation (or
+ * interceptor).
+ * 
+ * @author Howard M. Lewis Ship
+ */
+public interface LoggingDecorator
+{
+    /**
+     * Creates the logging interceptor.
+     * 
+     * @param <T>
+     * @param serviceInterface
+     *            interface implemented by the delegate
+     * @param delegate
+     *            existing object to be wrapped
+     * @return a new object implementing the interface that can be used in place of the delegate,
+     *         providing logging behavior around each method call on the service interface
+     */
+    <T> T createLoggingInterceptor(Class<T> serviceInterface, T delegate);
+}

Added: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/IOCUtilitiesTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/IOCUtilitiesTest.java?rev=424577&view=auto
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/IOCUtilitiesTest.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/IOCUtilitiesTest.java Sat Jul 22 06:57:04 2006
@@ -0,0 +1,78 @@
+package org.apache.tapestry.internal.ioc;
+
+import static org.apache.tapestry.internal.ioc.IOCUtilities.decoratorMatch;
+import static org.apache.tapestry.internal.ioc.IOCUtilities.globMatch;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+
+import org.testng.annotations.Test;
+
+/**
+ * @author Howard M. Lewis Ship
+ */
+public class IOCUtilitiesTest
+{
+    @Test
+    public void glob_match_exact()
+    {
+        assertTrue(globMatch("fred", "fred"));
+        assertFalse(globMatch("xfred", "fred"));
+        assertFalse(globMatch("fredx", "fred"));
+        assertFalse(globMatch("fred", "xfred"));
+        assertFalse(globMatch("fred", "fredx"));
+    }
+
+    @Test
+    public void glob_match_wild()
+    {
+        assertTrue(globMatch("fred", "*"));
+        assertTrue(globMatch("", "*"));
+    }
+
+    @Test
+    public void glob_match_prefix()
+    {
+        assertTrue(globMatch("fred.Barney", "*Barney"));
+        assertFalse(globMatch("fred.Barneyx", "*Barney"));
+        assertFalse(globMatch("fred.Barney", "*Barneyx"));
+        assertFalse(globMatch("fred.Barney", "*xBarney"));
+    }
+
+    @Test
+    public void glob_match_suffix()
+    {
+        assertTrue(globMatch("fred.Barney", "fred*"));
+        assertFalse(globMatch("xfred.Barney", "fred*"));
+        assertFalse(globMatch("fred.Barney", "fredx*"));
+        assertFalse(globMatch("fred.Barney", "xfred*"));
+    }
+
+    @Test
+    public void glob_match_infix()
+    {
+        assertTrue(globMatch("fred.Barney", "*d.B*"));
+        assertTrue(globMatch("fred.Barney", "*Barney*"));
+        assertTrue(globMatch("fred.Barney", "*fred*"));
+        assertFalse(globMatch("fred.Barney", "*flint*"));
+    }
+
+    @Test
+    public void decorator_match_simple()
+    {
+        assertTrue(decoratorMatch("foo.bar.Baz", "foo.bar", "Baz"));
+        assertFalse(decoratorMatch("foo.bar.Baz", "fie.foo", "Baz"));
+        assertTrue(decoratorMatch("foo.bar.Baz", "foo.bar", "*az"));
+        assertTrue(decoratorMatch("foo.bar.Baz", "foo.bar", "Ba*"));
+        assertTrue(decoratorMatch("foo.bar.Baz", "foo.bar", "*a*"));
+    }
+
+    @Test
+    public void decorate_match_complex()
+    {
+        assertTrue(decoratorMatch("foo.bar.Baz", "foo.bar", "foo*.Baz"));
+        assertTrue(decoratorMatch("foo.bar.Baz", "foo.bar", "*.Baz"));
+        assertTrue(decoratorMatch("foo.bar.Baz", "foo.bar", "foo.bar.*az"));
+        assertFalse(decoratorMatch("foo.bar.Baz", "foo.bar", "*fie*.*az"));
+        assertFalse(decoratorMatch("foo.bar.Baz", "foo.bar", "*.Goop"));
+    }
+}

Added: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/services/LoggerTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/services/LoggerTest.java?rev=424577&view=auto
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/services/LoggerTest.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/services/LoggerTest.java Sat Jul 22 06:57:04 2006
@@ -0,0 +1,96 @@
+package org.apache.tapestry.internal.ioc.services;
+
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+
+import java.util.Arrays;
+
+import org.apache.commons.logging.Log;
+import org.apache.tapestry.test.BaseTestCase;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+/**
+ * @author Howard M. Lewis Ship
+ */
+public class LoggerTest extends BaseTestCase
+{
+    private void try_entry(String methodName, String expected, Object... arguments)
+    {
+        Log log = newLog();
+
+        log.debug("[ENTER] " + expected);
+
+        replay();
+
+        new Logger(log).entry(methodName, arguments);
+
+        verify();
+
+    }
+
+    private void try_exit(String methodName, String expected, Object result)
+    {
+        Log log = newLog();
+
+        log.debug("[ EXIT] " + expected);
+
+        replay();
+
+        new Logger(log).exit(methodName, result);
+
+        verify();
+    }
+
+    @Test
+    public void entry_tests()
+    {
+        try_entry("fred", "fred()");
+        try_entry("barney", "barney(\"rubble\")", "rubble");
+        try_entry("yogi", "yogi(null, null)", null, null);
+        try_entry("wilma", "wilma(1, 2, 3)", 1, 2, 3);
+        try_entry("betty", "betty(\"rubble\", {1, 2, 3, \"four\"})", "rubble", new Object[]
+        { 1, 2, 3, "four" });
+        try_entry("betty", "betty(\"rubble\", [1, 2, 3, \"four\", [5, 6]])", "rubble", Arrays
+                .asList(1, 2, 3, "four", Arrays.asList(5, 6)));
+    }
+
+    @Test
+    public void exit_test()
+    {
+        try_exit("fred", "fred [true]", true);
+        try_exit("barney", "barney [\"rubble\"]", "rubble");
+    }
+
+    @Test
+    public void void_exit_test()
+    {
+        Log log = newLog();
+
+        log.debug("[ EXIT] wilma");
+
+        replay();
+
+        new Logger(log).voidExit("wilma");
+
+        verify();
+    }
+
+    @Test
+    public void debug_enabled()
+    {
+        Log log = newLog();
+
+        trainIsDebugEnabled(log, true);
+        trainIsDebugEnabled(log, false);
+
+        replay();
+
+        Logger logger = new Logger(log);
+
+        assertTrue(logger.isDebugEnabled());
+        assertFalse(logger.isDebugEnabled());
+
+        verify();
+    }
+}
\ No newline at end of file

Copied: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/ioc/IOCUtilitiesTest.java (from r424052, tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/ioc/TestIdUtils.java)
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/ioc/IOCUtilitiesTest.java?p2=tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/ioc/IOCUtilitiesTest.java&p1=tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/ioc/TestIdUtils.java&r1=424052&r2=424577&rev=424577&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/ioc/TestIdUtils.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/ioc/IOCUtilitiesTest.java Sat Jul 22 06:57:04 2006
@@ -14,50 +14,52 @@
 
 package org.apache.tapestry.ioc;
 
+import static org.apache.tapestry.ioc.IOCUtilities.qualifySimpleIdList;
+import static org.apache.tapestry.ioc.IOCUtilities.toQualifiedId;
 import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertNull;
 
 import org.testng.annotations.Test;
 
 /**
- * Tests for {@link org.apache.tapestry.ioc.IdUtils}.
+ * Tests for {@link org.apache.tapestry.ioc.IOCUtilities}.
  * 
  * @author Howard M. Lewis Ship
  */
-public class TestIdUtils
+public class IOCUtilitiesTest
 {
 
     @Test
     public void qualify_single_simple_id()
     {
-        assertEquals(IdUtils.qualify("module", "Fred"), "module.Fred");
+        assertEquals(toQualifiedId("module", "Fred"), "module.Fred");
     }
 
     @Test
     public void qualify_single_qualified_id()
     {
-        assertEquals(IdUtils.qualify("zaphod", "module.Fred"), "module.Fred");
+        assertEquals(toQualifiedId("zaphod", "module.Fred"), "module.Fred");
     }
 
     @Test
     public void qualify_id_list()
     {
         assertEquals(
-                IdUtils.qualifyList("module", "Fred,othermodule.Barney,module.Wilma"),
+                qualifySimpleIdList("module", "Fred,othermodule.Barney,module.Wilma"),
                 "module.Fred,othermodule.Barney,module.Wilma");
     }
 
     @Test
     public void qualify_list_as_star()
     {
-        assertEquals(IdUtils.qualifyList("module", "*"), "*");
+        assertEquals(qualifySimpleIdList("module", "*"), "*");
     }
 
     @Test
     public void qualify_blank_or_null_list()
     {
-        assertNull(IdUtils.qualifyList("module", null));
+        assertNull(qualifySimpleIdList("module", null));
 
-        assertEquals(IdUtils.qualifyList("module", ""), "");
+        assertEquals(qualifySimpleIdList("module", ""), "");
     }
 }