You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tapestry.apache.org by hl...@apache.org on 2007/03/19 01:10:39 UTC

svn commit: r519755 - in /tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc: internal/ internal/services/ services/

Author: hlship
Date: Sun Mar 18 17:10:38 2007
New Revision: 519755

URL: http://svn.apache.org/viewvc?view=rev&rev=519755
Log:
Add ability to define ClasFab fields with modifiers (such as final) and change several generated proxy classes to use final fields for injected, immutable values.

Modified:
    tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/internal/ModuleImpl.java
    tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/internal/services/BridgeBuilder.java
    tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/internal/services/ChainBuilderImpl.java
    tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/internal/services/ClassFabImpl.java
    tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/internal/services/LoggingDecoratorImpl.java
    tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/internal/services/PerThreadServiceLifecycle.java
    tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/internal/services/PropertyShadowBuilderImpl.java
    tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/internal/services/StrategyBuilderImpl.java
    tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/services/ClassFab.java

Modified: tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/internal/ModuleImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/internal/ModuleImpl.java?view=diff&rev=519755&r1=519754&r2=519755
==============================================================================
--- tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/internal/ModuleImpl.java (original)
+++ tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/internal/ModuleImpl.java Sun Mar 18 17:10:38 2007
@@ -366,7 +366,7 @@
     {
         ClassFab cf = _registry.newClass(serviceInterface);
 
-        cf.addField("_creator", ObjectCreator.class);
+        cf.addField("_creator", Modifier.PRIVATE | Modifier.FINAL, ObjectCreator.class);
 
         cf.addConstructor(new Class[]
         { ObjectCreator.class }, null, "_creator = $1;");

Modified: tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/internal/services/BridgeBuilder.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/internal/services/BridgeBuilder.java?view=diff&rev=519755&r1=519754&r2=519755
==============================================================================
--- tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/internal/services/BridgeBuilder.java (original)
+++ tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/internal/services/BridgeBuilder.java Sun Mar 18 17:10:38 2007
@@ -108,8 +108,8 @@
 
     private void createInfrastructure()
     {
-        _classFab.addField("_next", _serviceInterface);
-        _classFab.addField("_filter", _filterInterface);
+        _classFab.addField("_next", Modifier.PRIVATE | Modifier.FINAL, _serviceInterface);
+        _classFab.addField("_filter", Modifier.PRIVATE | Modifier.FINAL, _filterInterface);
 
         _classFab.addConstructor(new Class[]
         { _serviceInterface, _filterInterface }, null, "{ _next = $1; _filter = $2; }");

Modified: tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/internal/services/ChainBuilderImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/internal/services/ChainBuilderImpl.java?view=diff&rev=519755&r1=519754&r2=519755
==============================================================================
--- tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/internal/services/ChainBuilderImpl.java (original)
+++ tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/internal/services/ChainBuilderImpl.java Sun Mar 18 17:10:38 2007
@@ -12,205 +12,199 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package org.apache.tapestry.ioc.internal.services;
-
-import static java.lang.String.format;
+package org.apache.tapestry.ioc.internal.services;
+
+import static java.lang.String.format;
 import static org.apache.tapestry.ioc.internal.util.CollectionFactory.newConcurrentMap;
-
-import java.lang.reflect.Constructor;
-import java.lang.reflect.Modifier;
-import java.util.List;
-import java.util.Map;
-
-import org.apache.tapestry.ioc.services.ChainBuilder;
-import org.apache.tapestry.ioc.services.ClassFab;
-import org.apache.tapestry.ioc.services.ClassFabUtils;
-import org.apache.tapestry.ioc.services.ClassFactory;
-import org.apache.tapestry.ioc.services.MethodIterator;
-import org.apache.tapestry.ioc.services.MethodSignature;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Modifier;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.tapestry.ioc.services.ChainBuilder;
+import org.apache.tapestry.ioc.services.ClassFab;
+import org.apache.tapestry.ioc.services.ClassFabUtils;
+import org.apache.tapestry.ioc.services.ClassFactory;
+import org.apache.tapestry.ioc.services.MethodIterator;
+import org.apache.tapestry.ioc.services.MethodSignature;
 import org.apache.tapestry.ioc.util.BodyBuilder;
-
-/**
- * 
- */
-public class ChainBuilderImpl implements ChainBuilder
-{
-    private final ClassFactory _classFactory;
-
-    /**
-     * Map, keyed on service interface, of implementation Class.
-     */
-
-    private Map<Class, Class> _cache = newConcurrentMap();
-
-    public ChainBuilderImpl(ClassFactory classFactory)
-    {
-        _classFactory = classFactory;
-    }
-
-    @SuppressWarnings("unchecked")
-    public <T> T build(Class<T> commandInterface, List<T> commands)
-    {
-        Class<T> chainClass = findImplementationClass(commandInterface);
-
-        return createInstance(chainClass, commands);
-    }
-
-    private Class findImplementationClass(Class commandInterface)
-    {
-        Class result = _cache.get(commandInterface);
-
-        if (result == null)
-        {
-            result = constructImplementationClass(commandInterface);
-            _cache.put(commandInterface, result);
-        }
-
-        return result;
-    }
-
-    private Class constructImplementationClass(Class commandInterface)
-    {
-        // In rare, rare cases, a race condition to create an implementation class
-        // for the same interface may occur. We just let that happen, and there'll
-        // be two different classes corresponding to the same interface.
-
-        String name = ClassFabUtils.generateClassName(commandInterface);
-
-        ClassFab cf = _classFactory.newClass(name, Object.class);
-
-        addInfrastructure(cf, commandInterface);
-
-        addMethods(cf, commandInterface);
-
-        return cf.createClass();
-    }
-
-    private void addInfrastructure(ClassFab cf, Class commandInterface)
-    {
-        // Array types are very, very tricky to deal with.
-        // Also, generics don't help (<T> new T[]) is still java.lang.Object[].
-
-        String arrayClassName = commandInterface.getCanonicalName() + "[]";
-        String jvmName = ClassFabUtils.toJVMBinaryName(arrayClassName);
-
-        Class array = null;
-
-        try
-        {
-            ClassLoader loader = commandInterface.getClass().getClassLoader();
-            if (loader == null)
-                loader = Thread.currentThread().getContextClassLoader();
-
-            array = Class.forName(jvmName, true, loader);
-        }
-        catch (Exception ex)
-        {
-            throw new RuntimeException(ex);
-        }
-
-        cf.addInterface(commandInterface);
-        cf.addField("_commands", array);
-
-        BodyBuilder builder = new BodyBuilder();
-        builder.addln("_commands = (%s[]) $1.toArray(new %<s[0]);", commandInterface.getName());
-
-        cf.addConstructor(new Class[]
-        { List.class }, null, builder.toString());
-    }
-
+
+public class ChainBuilderImpl implements ChainBuilder
+{
+    private final ClassFactory _classFactory;
+
+    /**
+     * Map, keyed on service interface, of implementation Class.
+     */
+
+    private Map<Class, Class> _cache = newConcurrentMap();
+
+    public ChainBuilderImpl(ClassFactory classFactory)
+    {
+        _classFactory = classFactory;
+    }
+
     @SuppressWarnings("unchecked")
-    private <T> T createInstance(Class<T> instanceClass, List<T> commands)
-    {
-        try
-        {
-            Constructor<T> ctor = instanceClass.getConstructors()[0];
-
-            return instanceClass.cast(ctor.newInstance(commands));
-        }
-        catch (Exception ex)
-        {
-            // This should not be reachable!
-            throw new RuntimeException(ex);
-        }
-
-    }
-
-    private void addMethods(ClassFab cf, Class commandInterface)
-    {
-        MethodIterator mi = new MethodIterator(commandInterface);
-
-        while (mi.hasNext())
-        {
-            MethodSignature sig = mi.next();
-
-            addMethod(cf, commandInterface, sig);
-        }
-
-        if (!mi.getToString())
-            cf.addToString(format("<Command chain of %s>", commandInterface.getName()));
-    }
-
-    private void addMethod(ClassFab cf, Class commandInterface, MethodSignature sig)
-    {
-        Class returnType = sig.getReturnType();
-
-        if (returnType.equals(void.class))
-        {
-            addVoidMethod(cf, commandInterface, sig);
-            return;
-        }
-
-        String defaultValue = defaultForReturnType(returnType);
-
-        BodyBuilder builder = new BodyBuilder();
-        builder.begin();
-
-        builder.addln("%s result = %s;", ClassFabUtils.toJavaClassName(returnType), defaultValue);
-        builder.addln("for (int i = 0; i < _commands.length; i++)");
-
-        builder.begin();
-        builder.addln("result = _commands[i].%s($$);", sig.getName());
-
-        builder.addln("if (result != %s) break;", defaultValue);
-
-        builder.end();
-
-        builder.addln("return result;");
-        builder.end();
-
-        cf.addMethod(Modifier.PUBLIC, sig, builder.toString());
-    }
-
-    private String defaultForReturnType(Class returnType)
-    {
-        // For all object and array types.
-
-        if (!returnType.isPrimitive())
-            return "null";
-
-        if (returnType.equals(boolean.class))
-            return "false";
-
-        // Assume, then, that it is a numeric type (this method
-        // isn't called for type void). Javassist seems to be
-        // able to handle 0 for all numeric types.
-
-        return "0";
-    }
-
-    private void addVoidMethod(ClassFab cf, Class commandInterface, MethodSignature sig)
-    {
-        BodyBuilder builder = new BodyBuilder();
-
-        builder.begin();
-
-        builder.addln("for (int i = 0; i < _commands.length; i++)");
-        builder.addln("  _commands[i].%s($$);", sig.getName());
-
-        builder.end();
-
-        cf.addMethod(Modifier.PUBLIC, sig, builder.toString());
-    }
-
-}
+    public <T> T build(Class<T> commandInterface, List<T> commands)
+    {
+        Class<T> chainClass = findImplementationClass(commandInterface);
+
+        return createInstance(chainClass, commands);
+    }
+
+    private Class findImplementationClass(Class commandInterface)
+    {
+        Class result = _cache.get(commandInterface);
+
+        if (result == null)
+        {
+            result = constructImplementationClass(commandInterface);
+            _cache.put(commandInterface, result);
+        }
+
+        return result;
+    }
+
+    private Class constructImplementationClass(Class commandInterface)
+    {
+        // In rare, rare cases, a race condition to create an implementation class
+        // for the same interface may occur. We just let that happen, and there'll
+        // be two different classes corresponding to the same interface.
+
+        String name = ClassFabUtils.generateClassName(commandInterface);
+
+        ClassFab cf = _classFactory.newClass(name, Object.class);
+
+        addInfrastructure(cf, commandInterface);
+
+        addMethods(cf, commandInterface);
+
+        return cf.createClass();
+    }
+
+    private void addInfrastructure(ClassFab cf, Class commandInterface)
+    {
+        // Array types are very, very tricky to deal with.
+        // Also, generics don't help (<T> new T[]) is still java.lang.Object[].
+
+        String arrayClassName = commandInterface.getCanonicalName() + "[]";
+        String jvmName = ClassFabUtils.toJVMBinaryName(arrayClassName);
+
+        Class array = null;
+
+        try
+        {
+            ClassLoader loader = commandInterface.getClass().getClassLoader();
+            if (loader == null) loader = Thread.currentThread().getContextClassLoader();
+
+            array = Class.forName(jvmName, true, loader);
+        }
+        catch (Exception ex)
+        {
+            throw new RuntimeException(ex);
+        }
+
+        cf.addInterface(commandInterface);
+        cf.addField("_commands", Modifier.PRIVATE | Modifier.FINAL, array);
+
+        BodyBuilder builder = new BodyBuilder();
+        builder.addln("_commands = (%s[]) $1.toArray(new %<s[0]);", commandInterface.getName());
+
+        cf.addConstructor(new Class[]
+        { List.class }, null, builder.toString());
+    }
+
+    @SuppressWarnings("unchecked")
+    private <T> T createInstance(Class<T> instanceClass, List<T> commands)
+    {
+        try
+        {
+            Constructor<T> ctor = instanceClass.getConstructors()[0];
+
+            return instanceClass.cast(ctor.newInstance(commands));
+        }
+        catch (Exception ex)
+        {
+            // This should not be reachable!
+            throw new RuntimeException(ex);
+        }
+
+    }
+
+    private void addMethods(ClassFab cf, Class commandInterface)
+    {
+        MethodIterator mi = new MethodIterator(commandInterface);
+
+        while (mi.hasNext())
+        {
+            MethodSignature sig = mi.next();
+
+            addMethod(cf, commandInterface, sig);
+        }
+
+        if (!mi.getToString())
+            cf.addToString(format("<Command chain of %s>", commandInterface.getName()));
+    }
+
+    private void addMethod(ClassFab cf, Class commandInterface, MethodSignature sig)
+    {
+        Class returnType = sig.getReturnType();
+
+        if (returnType.equals(void.class))
+        {
+            addVoidMethod(cf, commandInterface, sig);
+            return;
+        }
+
+        String defaultValue = defaultForReturnType(returnType);
+
+        BodyBuilder builder = new BodyBuilder();
+        builder.begin();
+
+        builder.addln("%s result = %s;", ClassFabUtils.toJavaClassName(returnType), defaultValue);
+        builder.addln("for (int i = 0; i < _commands.length; i++)");
+
+        builder.begin();
+        builder.addln("result = _commands[i].%s($$);", sig.getName());
+
+        builder.addln("if (result != %s) break;", defaultValue);
+
+        builder.end();
+
+        builder.addln("return result;");
+        builder.end();
+
+        cf.addMethod(Modifier.PUBLIC, sig, builder.toString());
+    }
+
+    private String defaultForReturnType(Class returnType)
+    {
+        // For all object and array types.
+
+        if (!returnType.isPrimitive()) return "null";
+
+        if (returnType.equals(boolean.class)) return "false";
+
+        // Assume, then, that it is a numeric type (this method
+        // isn't called for type void). Javassist seems to be
+        // able to handle 0 for all numeric types.
+
+        return "0";
+    }
+
+    private void addVoidMethod(ClassFab cf, Class commandInterface, MethodSignature sig)
+    {
+        BodyBuilder builder = new BodyBuilder();
+
+        builder.begin();
+
+        builder.addln("for (int i = 0; i < _commands.length; i++)");
+        builder.addln("  _commands[i].%s($$);", sig.getName());
+
+        builder.end();
+
+        cf.addMethod(Modifier.PUBLIC, sig, builder.toString());
+    }
+
+}

Modified: tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/internal/services/ClassFabImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/internal/services/ClassFabImpl.java?view=diff&rev=519755&r1=519754&r2=519755
==============================================================================
--- tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/internal/services/ClassFabImpl.java (original)
+++ tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/internal/services/ClassFabImpl.java Sun Mar 18 17:10:38 2007
@@ -137,6 +137,11 @@
 
     public void addField(String name, Class type)
     {
+        addField(name, Modifier.PRIVATE, type);
+    }
+
+    public void addField(String name, int modifiers, Class type)
+    {
         _lock.check();
 
         CtClass ctType = convertClass(type);
@@ -144,7 +149,7 @@
         try
         {
             CtField field = new CtField(ctType, name, getCtClass());
-            field.setModifiers(Modifier.PRIVATE);
+            field.setModifiers(modifiers);
 
             getCtClass().addField(field);
         }
@@ -154,7 +159,8 @@
             throw new RuntimeException(ServiceMessages.unableToAddField(name, getCtClass(), ex), ex);
         }
 
-        _formatter.format("private %s %s;\n\n", ClassFabUtils.toJavaClassName(type), name);
+        _formatter.format("%s %s %s;\n\n", Modifier.toString(modifiers), ClassFabUtils
+                .toJavaClassName(type), name);
     }
 
     public void proxyMethodsToDelegate(Class serviceInterface, String delegateExpression,

Modified: tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/internal/services/LoggingDecoratorImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/internal/services/LoggingDecoratorImpl.java?view=diff&rev=519755&r1=519754&r2=519755
==============================================================================
--- tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/internal/services/LoggingDecoratorImpl.java (original)
+++ tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/internal/services/LoggingDecoratorImpl.java Sun Mar 18 17:10:38 2007
@@ -12,156 +12,151 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package org.apache.tapestry.ioc.internal.services;
-
-import static java.lang.String.format;
-import static org.apache.tapestry.ioc.services.ClassFabUtils.toJavaClassName;
-
-import java.lang.reflect.Constructor;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Modifier;
-
-import org.apache.commons.logging.Log;
-import org.apache.tapestry.ioc.services.ClassFab;
-import org.apache.tapestry.ioc.services.ClassFactory;
-import org.apache.tapestry.ioc.services.ExceptionTracker;
-import org.apache.tapestry.ioc.services.LoggingDecorator;
-import org.apache.tapestry.ioc.services.MethodIterator;
-import org.apache.tapestry.ioc.services.MethodSignature;
+package org.apache.tapestry.ioc.internal.services;
+
+import static java.lang.String.format;
+import static org.apache.tapestry.ioc.services.ClassFabUtils.toJavaClassName;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Modifier;
+
+import org.apache.commons.logging.Log;
+import org.apache.tapestry.ioc.services.ClassFab;
+import org.apache.tapestry.ioc.services.ClassFactory;
+import org.apache.tapestry.ioc.services.ExceptionTracker;
+import org.apache.tapestry.ioc.services.LoggingDecorator;
+import org.apache.tapestry.ioc.services.MethodIterator;
+import org.apache.tapestry.ioc.services.MethodSignature;
 import org.apache.tapestry.ioc.util.BodyBuilder;
-
-/**
- * 
- */
-public class LoggingDecoratorImpl implements LoggingDecorator
-{
-    private final ClassFactory _classFactory;
-
-    private final ExceptionTracker _exceptionTracker;
-
-    public LoggingDecoratorImpl(ClassFactory classFactory, ExceptionTracker exceptionTracker)
-    {
-        _classFactory = classFactory;
-        _exceptionTracker = exceptionTracker;
-    }
-
-    public <T> T build(Class<T> serviceInterface, T delegate, String serviceId, Log serviceLog)
-    {
-        Class interceptorClass = createInterceptorClass(serviceInterface, serviceId);
-
-        ServiceLogger logger = new ServiceLogger(serviceLog, _exceptionTracker);
-
-        Constructor cc = interceptorClass.getConstructors()[0];
-
-        Object interceptor = null;
-        Throwable fail = null;
-
-        try
-        {
-            interceptor = cc.newInstance(delegate, logger);
-        }
-        catch (InvocationTargetException ite)
-        {
-            fail = ite.getTargetException();
-        }
-        catch (Exception ex)
-        {
-            fail = ex;
-        }
-
-        if (fail != null)
-            throw new RuntimeException(fail);
-
-        return serviceInterface.cast(interceptor);
-    }
-
-    private Class createInterceptorClass(Class serviceInterface, String serviceId)
-    {
-        ClassFab cf = _classFactory.newClass(serviceInterface);
-
-        cf.addField("_delegate", serviceInterface);
-        cf.addField("_logger", ServiceLogger.class);
-
-        cf.addConstructor(new Class[]
-        { serviceInterface, ServiceLogger.class }, null, "{ _delegate = $1; _logger = $2; }");
-
-        addMethods(cf, serviceInterface, serviceId);
-
-        return cf.createClass();
-    }
-
-    private void addMethods(ClassFab cf, Class serviceInterface, String serviceId)
-    {
-        MethodIterator mi = new MethodIterator(serviceInterface);
-
-        while (mi.hasNext())
-            addMethod(cf, mi.next());
-
-        if (!mi.getToString())
-            cf.addToString(ServiceMessages.loggingInterceptor(serviceId, serviceInterface));
-    }
-
-    private void addMethod(ClassFab cf, MethodSignature signature)
-    {
-        String name = '"' + signature.getName() + '"';
-        Class returnType = signature.getReturnType();
-        boolean isVoid = returnType.equals(void.class);
-
-        // We'll see how well Javassist handles void methods with this setup
-
-        BodyBuilder builder = new BodyBuilder();
-        builder.begin();
-        builder.addln("boolean debug = _logger.isDebugEnabled();");
-
-        builder.addln("if (debug)");
-        builder.addln("  _logger.entry(%s, $args);", name);
-
-        builder.addln("try");
-        builder.begin();
-
-        if (!isVoid)
-            builder.add("%s result = ", toJavaClassName(returnType));
-
-        builder.addln("_delegate.%s($$);", signature.getName());
-
-        if (isVoid)
-        {
-            builder.addln("if (debug)");
-            builder.addln(format("  _logger.voidExit(%s);", name));
-            builder.addln("return;");
-        }
-        else
-        {
-            builder.addln("if (debug)");
-            builder.addln(format("  _logger.exit(%s, ($w)result);", name));
-            builder.addln("return result;");
-        }
-
-        builder.end(); // try
-
-        // Now, a catch for each declared exception (if any)
-
-        if (signature.getExceptionTypes() != null)
-            for (Class exceptionType : signature.getExceptionTypes())
-                addExceptionHandler(builder, name, exceptionType);
-
-        // And a catch for RuntimeException
-
-        addExceptionHandler(builder, name, RuntimeException.class);
-
-        builder.end();
-
-        cf.addMethod(Modifier.PUBLIC, signature, builder.toString());
-    }
-
-    private void addExceptionHandler(BodyBuilder builder, String quotedMethodName,
-            Class exceptionType)
-    {
-        builder.addln("catch (%s ex)", exceptionType.getName());
-        builder.begin();
-        builder.addln("if (debug)");
-        builder.addln("  _logger.fail(%s, ex);", quotedMethodName);
-        builder.addln("throw ex;");
-        builder.end();
-    }
-}
+
+public class LoggingDecoratorImpl implements LoggingDecorator
+{
+    private final ClassFactory _classFactory;
+
+    private final ExceptionTracker _exceptionTracker;
+
+    public LoggingDecoratorImpl(ClassFactory classFactory, ExceptionTracker exceptionTracker)
+    {
+        _classFactory = classFactory;
+        _exceptionTracker = exceptionTracker;
+    }
+
+    public <T> T build(Class<T> serviceInterface, T delegate, String serviceId, Log serviceLog)
+    {
+        Class interceptorClass = createInterceptorClass(serviceInterface, serviceId);
+
+        ServiceLogger logger = new ServiceLogger(serviceLog, _exceptionTracker);
+
+        Constructor cc = interceptorClass.getConstructors()[0];
+
+        Object interceptor = null;
+        Throwable fail = null;
+
+        try
+        {
+            interceptor = cc.newInstance(delegate, logger);
+        }
+        catch (InvocationTargetException ite)
+        {
+            fail = ite.getTargetException();
+        }
+        catch (Exception ex)
+        {
+            fail = ex;
+        }
+
+        if (fail != null) throw new RuntimeException(fail);
+
+        return serviceInterface.cast(interceptor);
+    }
+
+    private Class createInterceptorClass(Class serviceInterface, String serviceId)
+    {
+        ClassFab cf = _classFactory.newClass(serviceInterface);
+
+        cf.addField("_delegate", Modifier.PRIVATE | Modifier.FINAL, serviceInterface);
+        cf.addField("_logger", Modifier.PRIVATE | Modifier.FINAL, ServiceLogger.class);
+
+        cf.addConstructor(new Class[]
+        { serviceInterface, ServiceLogger.class }, null, "{ _delegate = $1; _logger = $2; }");
+
+        addMethods(cf, serviceInterface, serviceId);
+
+        return cf.createClass();
+    }
+
+    private void addMethods(ClassFab cf, Class serviceInterface, String serviceId)
+    {
+        MethodIterator mi = new MethodIterator(serviceInterface);
+
+        while (mi.hasNext())
+            addMethod(cf, mi.next());
+
+        if (!mi.getToString())
+            cf.addToString(ServiceMessages.loggingInterceptor(serviceId, serviceInterface));
+    }
+
+    private void addMethod(ClassFab cf, MethodSignature signature)
+    {
+        String name = '"' + signature.getName() + '"';
+        Class returnType = signature.getReturnType();
+        boolean isVoid = returnType.equals(void.class);
+
+        // We'll see how well Javassist handles void methods with this setup
+
+        BodyBuilder builder = new BodyBuilder();
+        builder.begin();
+        builder.addln("boolean debug = _logger.isDebugEnabled();");
+
+        builder.addln("if (debug)");
+        builder.addln("  _logger.entry(%s, $args);", name);
+
+        builder.addln("try");
+        builder.begin();
+
+        if (!isVoid) builder.add("%s result = ", toJavaClassName(returnType));
+
+        builder.addln("_delegate.%s($$);", signature.getName());
+
+        if (isVoid)
+        {
+            builder.addln("if (debug)");
+            builder.addln(format("  _logger.voidExit(%s);", name));
+            builder.addln("return;");
+        }
+        else
+        {
+            builder.addln("if (debug)");
+            builder.addln(format("  _logger.exit(%s, ($w)result);", name));
+            builder.addln("return result;");
+        }
+
+        builder.end(); // try
+
+        // Now, a catch for each declared exception (if any)
+
+        if (signature.getExceptionTypes() != null)
+            for (Class exceptionType : signature.getExceptionTypes())
+                addExceptionHandler(builder, name, exceptionType);
+
+        // And a catch for RuntimeException
+
+        addExceptionHandler(builder, name, RuntimeException.class);
+
+        builder.end();
+
+        cf.addMethod(Modifier.PUBLIC, signature, builder.toString());
+    }
+
+    private void addExceptionHandler(BodyBuilder builder, String quotedMethodName,
+            Class exceptionType)
+    {
+        builder.addln("catch (%s ex)", exceptionType.getName());
+        builder.begin();
+        builder.addln("if (debug)");
+        builder.addln("  _logger.fail(%s, ex);", quotedMethodName);
+        builder.addln("throw ex;");
+        builder.end();
+    }
+}

Modified: tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/internal/services/PerThreadServiceLifecycle.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/internal/services/PerThreadServiceLifecycle.java?view=diff&rev=519755&r1=519754&r2=519755
==============================================================================
--- tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/internal/services/PerThreadServiceLifecycle.java (original)
+++ tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/internal/services/PerThreadServiceLifecycle.java Sun Mar 18 17:10:38 2007
@@ -1,4 +1,4 @@
-// Copyright 2006 The Apache Software Foundation
+// Copyright 2006, 2007 The Apache Software Foundation
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
@@ -12,98 +12,96 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package org.apache.tapestry.ioc.internal.services;
-
-import static java.lang.String.format;
-
-import java.lang.reflect.Constructor;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Modifier;
-
-import org.apache.tapestry.ioc.ObjectCreator;
-import org.apache.tapestry.ioc.ServiceLifecycle;
-import org.apache.tapestry.ioc.ServiceResources;
-import org.apache.tapestry.ioc.services.ClassFab;
-import org.apache.tapestry.ioc.services.ClassFactory;
-import org.apache.tapestry.ioc.services.MethodSignature;
-import org.apache.tapestry.ioc.services.ThreadCleanupHub;
-
-/**
- * Allows a service to exist "per thread" (in each thread). This involves an inner proxy, with a
- * ThreadLocal whose initial value is derived from a {@link org.apache.tapestry.ioc.ObjectCreator}.
- * Method invocations are delegated to the per-thread service instance. The proxy also implements
- * {@link org.apache.tapestry.ioc.services.ThreadCleanupListener} so that it can discard the
- * per-thread implementation.
- * <p>
- * This scheme ensures that, although the service builder method will be invoked many times over the
- * life of the application, the service decoration process occurs only once. The final calling chain
- * is: Service Proxy --&gt; Decorator(s) --&gt; PerThread Proxy --&gt; (per thread) instance.
- * 
- * 
- */
-public class PerThreadServiceLifecycle implements ServiceLifecycle
-{
-    private final ThreadCleanupHub _threadCleanupHub;
-
-    private final ClassFactory _classFactory;
-
-    private static final String PER_THREAD_METHOD_NAME = "_perThreadInstance";
-
-    public PerThreadServiceLifecycle(ThreadCleanupHub threadCleanupHub, ClassFactory classFactory)
-    {
-        _threadCleanupHub = threadCleanupHub;
-        _classFactory = classFactory;
-    }
-
-    public Object createService(ServiceResources resources, final ObjectCreator creator)
-    {
-        Class proxyClass = createProxyClass(resources);
-
-        ObjectCreator perThreadCreator = new PerThreadServiceCreator(_threadCleanupHub, creator);
-
-        try
-        {
-            Constructor ctor = proxyClass.getConstructors()[0];
-
-            return ctor.newInstance(perThreadCreator);
-        }
-        catch (InvocationTargetException ex)
-        {
-            throw new RuntimeException(ex.getCause());
-        }
-        catch (Exception ex)
-        {
-            throw new RuntimeException(ex);
-        }
-    }
-
-    private Class createProxyClass(ServiceResources resources)
-    {
-        Class serviceInterface = resources.getServiceInterface();
-
-        ClassFab cf = _classFactory.newClass(serviceInterface);
-
-        cf.addField("_creator", ObjectCreator.class);
-
-        // Constructor takes a ServiceCreator
-
-        cf.addConstructor(new Class[]
-        { ObjectCreator.class }, null, "_creator = $1;");
-
-        String body = format("return (%s) _creator.createObject();", serviceInterface.getName());
-
-        MethodSignature sig = new MethodSignature(serviceInterface, PER_THREAD_METHOD_NAME, null,
-                null);
-
-        cf.addMethod(Modifier.PRIVATE, sig, body);
-
-        String toString = format(
-                "<PerThread Proxy for %s(%s)>",
-                resources.getServiceId(),
-                serviceInterface.getName());
-
-        cf.proxyMethodsToDelegate(serviceInterface, PER_THREAD_METHOD_NAME + "()", toString);
-
-        return cf.createClass();
-    }
-}
+package org.apache.tapestry.ioc.internal.services;
+
+import static java.lang.String.format;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Modifier;
+
+import org.apache.tapestry.ioc.ObjectCreator;
+import org.apache.tapestry.ioc.ServiceLifecycle;
+import org.apache.tapestry.ioc.ServiceResources;
+import org.apache.tapestry.ioc.services.ClassFab;
+import org.apache.tapestry.ioc.services.ClassFactory;
+import org.apache.tapestry.ioc.services.MethodSignature;
+import org.apache.tapestry.ioc.services.ThreadCleanupHub;
+
+/**
+ * Allows a service to exist "per thread" (in each thread). This involves an inner proxy, with a
+ * ThreadLocal whose initial value is derived from a {@link org.apache.tapestry.ioc.ObjectCreator}.
+ * Method invocations are delegated to the per-thread service instance. The proxy also implements
+ * {@link org.apache.tapestry.ioc.services.ThreadCleanupListener} so that it can discard the
+ * per-thread implementation.
+ * <p>
+ * This scheme ensures that, although the service builder method will be invoked many times over the
+ * life of the application, the service decoration process occurs only once. The final calling chain
+ * is: Service Proxy --&gt; Decorator(s) --&gt; PerThread Proxy --&gt; (per thread) instance.
+ */
+public class PerThreadServiceLifecycle implements ServiceLifecycle
+{
+    private final ThreadCleanupHub _threadCleanupHub;
+
+    private final ClassFactory _classFactory;
+
+    private static final String PER_THREAD_METHOD_NAME = "_perThreadInstance";
+
+    public PerThreadServiceLifecycle(ThreadCleanupHub threadCleanupHub, ClassFactory classFactory)
+    {
+        _threadCleanupHub = threadCleanupHub;
+        _classFactory = classFactory;
+    }
+
+    public Object createService(ServiceResources resources, final ObjectCreator creator)
+    {
+        Class proxyClass = createProxyClass(resources);
+
+        ObjectCreator perThreadCreator = new PerThreadServiceCreator(_threadCleanupHub, creator);
+
+        try
+        {
+            Constructor ctor = proxyClass.getConstructors()[0];
+
+            return ctor.newInstance(perThreadCreator);
+        }
+        catch (InvocationTargetException ex)
+        {
+            throw new RuntimeException(ex.getCause());
+        }
+        catch (Exception ex)
+        {
+            throw new RuntimeException(ex);
+        }
+    }
+
+    private Class createProxyClass(ServiceResources resources)
+    {
+        Class serviceInterface = resources.getServiceInterface();
+
+        ClassFab cf = _classFactory.newClass(serviceInterface);
+
+        cf.addField("_creator", Modifier.PRIVATE | Modifier.FINAL, ObjectCreator.class);
+
+        // Constructor takes a ServiceCreator
+
+        cf.addConstructor(new Class[]
+        { ObjectCreator.class }, null, "_creator = $1;");
+
+        String body = format("return (%s) _creator.createObject();", serviceInterface.getName());
+
+        MethodSignature sig = new MethodSignature(serviceInterface, PER_THREAD_METHOD_NAME, null,
+                null);
+
+        cf.addMethod(Modifier.PRIVATE, sig, body);
+
+        String toString = format(
+                "<PerThread Proxy for %s(%s)>",
+                resources.getServiceId(),
+                serviceInterface.getName());
+
+        cf.proxyMethodsToDelegate(serviceInterface, PER_THREAD_METHOD_NAME + "()", toString);
+
+        return cf.createClass();
+    }
+}

Modified: tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/internal/services/PropertyShadowBuilderImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/internal/services/PropertyShadowBuilderImpl.java?view=diff&rev=519755&r1=519754&r2=519755
==============================================================================
--- tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/internal/services/PropertyShadowBuilderImpl.java (original)
+++ tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/internal/services/PropertyShadowBuilderImpl.java Sun Mar 18 17:10:38 2007
@@ -1,4 +1,4 @@
-// Copyright 2006 The Apache Software Foundation
+// Copyright 2006, 2007 The Apache Software Foundation
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
@@ -12,88 +12,85 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package org.apache.tapestry.ioc.internal.services;
-
-import static java.lang.String.format;
-
-import java.lang.reflect.Constructor;
-import java.lang.reflect.Modifier;
-
-import org.apache.tapestry.ioc.services.ClassFab;
-import org.apache.tapestry.ioc.services.ClassFactory;
-import org.apache.tapestry.ioc.services.MethodSignature;
-import org.apache.tapestry.ioc.services.PropertyAccess;
-import org.apache.tapestry.ioc.services.PropertyAdapter;
-import org.apache.tapestry.ioc.services.PropertyShadowBuilder;
-
-/**
- * 
- */
-public class PropertyShadowBuilderImpl implements PropertyShadowBuilder
-{
-    private final ClassFactory _classFactory;
-
-    private final PropertyAccess _propertyAccess;
-
-    public PropertyShadowBuilderImpl(ClassFactory classFactory, PropertyAccess propertyAccess)
-    {
-        _classFactory = classFactory;
-        _propertyAccess = propertyAccess;
-    }
-
-    public <T> T build(Object source, String propertyName, Class<T> propertyType)
-    {
-        Class sourceClass = source.getClass();
-        PropertyAdapter adapter = _propertyAccess.getAdapter(sourceClass).getPropertyAdapter(
-                propertyName);
-
-        // TODO: Perhaps extend ClassPropertyAdapter to do these checks?
-
-        if (adapter == null)
-            throw new RuntimeException(ServiceMessages.noSuchProperty(sourceClass, propertyName));
-
-        if (!adapter.isRead())
-            throw new RuntimeException(ServiceMessages.readNotSupported(source, propertyName));
-
-        if (!propertyType.isAssignableFrom(adapter.getType()))
-            throw new RuntimeException(ServiceMessages.propertyTypeMismatch(
-                    propertyName,
-                    sourceClass,
-                    adapter.getType(),
-                    propertyType));
-
-        ClassFab cf = _classFactory.newClass(propertyType);
-
-        cf.addField("_source", sourceClass);
-
-        cf.addConstructor(new Class[]
-        { sourceClass }, null, "_source = $1;");
-
-        String body = format("return _source.%s();", adapter.getReadMethod().getName());
-
-        MethodSignature sig = new MethodSignature(propertyType, "_delegate", null, null);
-        cf.addMethod(Modifier.PRIVATE, sig, body);
-
-        String toString = format("<Shadow: property %s of %s>", propertyName, source);
-
-        cf.proxyMethodsToDelegate(propertyType, "_delegate()", toString);
-
-        Class shadowClass = cf.createClass();
-
-        try
-        {
-            Constructor cc = shadowClass.getConstructors()[0];
-
-            Object instance = cc.newInstance(source);
-
-            return propertyType.cast(instance);
-        }
-        catch (Exception ex)
-        {
-            // Should not be reachable
-            throw new RuntimeException(ex);
-        }
-
-    }
-
-}
+package org.apache.tapestry.ioc.internal.services;
+
+import static java.lang.String.format;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Modifier;
+
+import org.apache.tapestry.ioc.services.ClassFab;
+import org.apache.tapestry.ioc.services.ClassFactory;
+import org.apache.tapestry.ioc.services.MethodSignature;
+import org.apache.tapestry.ioc.services.PropertyAccess;
+import org.apache.tapestry.ioc.services.PropertyAdapter;
+import org.apache.tapestry.ioc.services.PropertyShadowBuilder;
+
+public class PropertyShadowBuilderImpl implements PropertyShadowBuilder
+{
+    private final ClassFactory _classFactory;
+
+    private final PropertyAccess _propertyAccess;
+
+    public PropertyShadowBuilderImpl(ClassFactory classFactory, PropertyAccess propertyAccess)
+    {
+        _classFactory = classFactory;
+        _propertyAccess = propertyAccess;
+    }
+
+    public <T> T build(Object source, String propertyName, Class<T> propertyType)
+    {
+        Class sourceClass = source.getClass();
+        PropertyAdapter adapter = _propertyAccess.getAdapter(sourceClass).getPropertyAdapter(
+                propertyName);
+
+        // TODO: Perhaps extend ClassPropertyAdapter to do these checks?
+
+        if (adapter == null)
+            throw new RuntimeException(ServiceMessages.noSuchProperty(sourceClass, propertyName));
+
+        if (!adapter.isRead())
+            throw new RuntimeException(ServiceMessages.readNotSupported(source, propertyName));
+
+        if (!propertyType.isAssignableFrom(adapter.getType()))
+            throw new RuntimeException(ServiceMessages.propertyTypeMismatch(
+                    propertyName,
+                    sourceClass,
+                    adapter.getType(),
+                    propertyType));
+
+        ClassFab cf = _classFactory.newClass(propertyType);
+
+        cf.addField("_source", Modifier.PRIVATE | Modifier.FINAL, sourceClass);
+
+        cf.addConstructor(new Class[]
+        { sourceClass }, null, "_source = $1;");
+
+        String body = format("return _source.%s();", adapter.getReadMethod().getName());
+
+        MethodSignature sig = new MethodSignature(propertyType, "_delegate", null, null);
+        cf.addMethod(Modifier.PRIVATE, sig, body);
+
+        String toString = format("<Shadow: property %s of %s>", propertyName, source);
+
+        cf.proxyMethodsToDelegate(propertyType, "_delegate()", toString);
+
+        Class shadowClass = cf.createClass();
+
+        try
+        {
+            Constructor cc = shadowClass.getConstructors()[0];
+
+            Object instance = cc.newInstance(source);
+
+            return propertyType.cast(instance);
+        }
+        catch (Exception ex)
+        {
+            // Should not be reachable
+            throw new RuntimeException(ex);
+        }
+
+    }
+
+}

Modified: tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/internal/services/StrategyBuilderImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/internal/services/StrategyBuilderImpl.java?view=diff&rev=519755&r1=519754&r2=519755
==============================================================================
--- tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/internal/services/StrategyBuilderImpl.java (original)
+++ tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/internal/services/StrategyBuilderImpl.java Sun Mar 18 17:10:38 2007
@@ -1,4 +1,4 @@
-// Copyright 2006 The Apache Software Foundation
+// Copyright 2006, 2007 The Apache Software Foundation
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
@@ -37,8 +37,8 @@
     {
         Class<S> interfaceClass = registry.getAdapterType();
 
-        // TODO: Could cache the implClass by interfaceClass ... 
-        
+        // TODO: Could cache the implClass by interfaceClass ...
+
         Class implClass = createImplClass(interfaceClass);
 
         try
@@ -59,7 +59,7 @@
 
         String interfaceClassName = interfaceClass.getName();
 
-        cf.addField("_registry", StrategyRegistry.class);
+        cf.addField("_registry", Modifier.PRIVATE | Modifier.FINAL, StrategyRegistry.class);
         cf.addConstructor(new Class[]
         { StrategyRegistry.class }, null, "_registry = $1;");
 
@@ -72,7 +72,7 @@
             MethodSignature sig = mi.next();
 
             // TODO: Checks for methods that don't have at least one parameter, or don't have a
-            // compatible 1st parameter.  Currently, we'll get a Javassist exception.
+            // compatible 1st parameter. Currently, we'll get a Javassist exception.
 
             builder.clear();
             builder.begin();

Modified: tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/services/ClassFab.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/services/ClassFab.java?view=diff&rev=519755&r1=519754&r2=519755
==============================================================================
--- tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/services/ClassFab.java (original)
+++ tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/services/ClassFab.java Sun Mar 18 17:10:38 2007
@@ -55,6 +55,9 @@
      */
     void addField(String name, Class type);
 
+    /** Adds a new field with the provided modifiers. */
+    void addField(String name, int modifiers, Class Type);
+
     /**
      * Adds a method. The method is a public instance method.
      *