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 [EMAIL PROTECTED] 
org.apache.tapestry.ioc.ObjectCreator}.
- * Method invocations are delegated to the per-thread service instance. The 
proxy also implements
- * [EMAIL PROTECTED] 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 [EMAIL PROTECTED] 
org.apache.tapestry.ioc.ObjectCreator}.
+ * Method invocations are delegated to the per-thread service instance. The 
proxy also implements
+ * [EMAIL PROTECTED] 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.
      * 


Reply via email to