Author: hlship
Date: Fri Apr 21 11:59:10 2006
New Revision: 395987

URL: http://svn.apache.org/viewcvs?rev=395987&view=rev
Log:
Work on the injectField() method of ClassTransformation

Added:
    
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ResourceAware.java
    
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/transform/worker/ImplementResourceAwareWorker.java
    
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/transform/ClassTransformWorker.java
      - copied, changed from r395912, 
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/transform/ClassTransformWorker.java
    
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/transform/TransformConstants.java
Removed:
    
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/transform/ClassTransformWorker.java
    
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/transform/TransformConstants.java
Modified:
    
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/transform/ClassTransformerImpl.java
    
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/transform/InternalClassTransformation.java
    
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/transform/InternalClassTransformationImpl.java
    
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/transform/TransformMessages.java
    
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/transform/worker/RetainWorker.java
    
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/transform/worker/UnclaimedFieldWorker.java
    
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/transform/ClassTransformation.java
    
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/transform/MethodSignature.java
    
tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/internal/transform/TransformStrings.properties
    
tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/transform/InternalClassTransformationImplTest.java
    
tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/transform/worker/UnclaimedFieldWorkerTest.java

Added: 
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ResourceAware.java
URL: 
http://svn.apache.org/viewcvs/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ResourceAware.java?rev=395987&view=auto
==============================================================================
--- 
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ResourceAware.java
 (added)
+++ 
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ResourceAware.java
 Fri Apr 21 11:59:10 2006
@@ -0,0 +1,13 @@
+package org.apache.tapestry;
+
+/**
+ * Interface implemented by components (after they have been transformed at 
load time). Component
+ * classes should not implement this interface directly.
+ * 
+ * @author Howard M. Lewis Ship
+ */
+public interface ResourceAware
+{
+    /** Returns the resources associated with this component class. */
+    ComponentResources getResources();
+}

Modified: 
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/transform/ClassTransformerImpl.java
URL: 
http://svn.apache.org/viewcvs/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/transform/ClassTransformerImpl.java?rev=395987&r1=395986&r2=395987&view=diff
==============================================================================
--- 
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/transform/ClassTransformerImpl.java
 (original)
+++ 
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/transform/ClassTransformerImpl.java
 Fri Apr 21 11:59:10 2006
@@ -4,8 +4,10 @@
 
 import javassist.CtClass;
 
+import org.apache.tapestry.annotations.ComponentClass;
 import org.apache.tapestry.internal.model.MutableComponentModelImpl;
 import org.apache.tapestry.model.MutableComponentModel;
+import org.apache.tapestry.transform.ClassTransformWorker;
 
 import static org.apache.tapestry.util.CollectionFactory.newMap;
 
@@ -19,6 +21,8 @@
     /** Map from class name to class transformation. */
     private final Map<String, InternalClassTransformation> 
_nameToClassTransformation = newMap();
 
+    private ClassTransformWorker _workers;
+
     public Instantiator findInstantiator(String classname)
     {
         // TODO Auto-generated method stub
@@ -33,11 +37,29 @@
 
         InternalClassTransformation transformation = new 
InternalClassTransformationImpl(ctClass);
 
+        // Not all classes in the packages are components.
+
+        if (transformation.getAnnotation(ComponentClass.class) == null)
+            return;
+
         // Eventually these will also be cached or published or something.
 
         MutableComponentModel model = new MutableComponentModelImpl();
 
+        _workers.transform(transformation, model);
+
+        transformation.finish();
+
         _nameToClassTransformation.put(classname, transformation);
+    }
+
+    /**
+     * For injection. This will usually be an ordered series of [EMAIL 
PROTECTED] ClassTransformWorker}s, as a
+     * chain-of-command.
+     */
+    public final void setWorkers(ClassTransformWorker workers)
+    {
+        _workers = workers;
     }
 
 }

Modified: 
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/transform/InternalClassTransformation.java
URL: 
http://svn.apache.org/viewcvs/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/transform/InternalClassTransformation.java?rev=395987&r1=395986&r2=395987&view=diff
==============================================================================
--- 
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/transform/InternalClassTransformation.java
 (original)
+++ 
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/transform/InternalClassTransformation.java
 Fri Apr 21 11:59:10 2006
@@ -14,15 +14,20 @@
 
 package org.apache.tapestry.internal.transform;
 
+import org.apache.tapestry.transform.ClassTransformWorker;
 import org.apache.tapestry.transform.ClassTransformation;
 
 /**
- * Extends [EMAIL PROTECTED] 
org.apache.tapestry.transform.ClassTransformation} with additional methods that 
may only be
- * used internally by Tapestry.
+ * Extends [EMAIL PROTECTED] 
org.apache.tapestry.transform.ClassTransformation} with additional methods that
+ * may only be used internally by Tapestry.
  * 
  * @author Howard M. Lewis Ship
  */
 public interface InternalClassTransformation extends ClassTransformation
 {
-
+    /**
+     * Invoked after all [EMAIL PROTECTED] ClassTransformWorker}s have had 
their chance to work over the
+     * class. This performs any final operations for the class transformation.
+     */
+    void finish();
 }

Modified: 
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/transform/InternalClassTransformationImpl.java
URL: 
http://svn.apache.org/viewcvs/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/transform/InternalClassTransformationImpl.java?rev=395987&r1=395986&r2=395987&view=diff
==============================================================================
--- 
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/transform/InternalClassTransformationImpl.java
 (original)
+++ 
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/transform/InternalClassTransformationImpl.java
 Fri Apr 21 11:59:10 2006
@@ -24,14 +24,17 @@
 import javassist.CannotCompileException;
 import javassist.ClassPool;
 import javassist.CtClass;
+import javassist.CtConstructor;
 import javassist.CtField;
 import javassist.CtMember;
 import javassist.CtMethod;
+import javassist.CtNewConstructor;
 import javassist.CtNewMethod;
 import javassist.NotFoundException;
 import javassist.expr.ExprEditor;
 import javassist.expr.FieldAccess;
 
+import org.apache.hivemind.service.BodyBuilder;
 import org.apache.tapestry.transform.MethodSignature;
 import org.apache.tapestry.util.IdAllocator;
 
@@ -67,26 +70,47 @@
 
     private final Set<String> _addedFieldNames = newSet();
 
+    private final Map<String, String> _meta = newMap();
+
     // Cache of class annotations
 
     private Object[] _classAnnotations;
 
+    private final List<ConstructorArg> _constructorArgs = newList();
+
     // All names will have this value as a prefix
 
     private final String NAME_PREFIX = "_$";
 
-    private final static Map<CtClass, String> _defaultMethodBody = newMap();
-
-    static
+    private static class ConstructorArg
     {
-        _defaultMethodBody.put(CtClass.booleanType, "return false;");
-        _defaultMethodBody.put(CtClass.byteType, "return 0;");
-        _defaultMethodBody.put(CtClass.shortType, "return 0;");
-        _defaultMethodBody.put(CtClass.intType, "return 0;");
-        _defaultMethodBody.put(CtClass.longType, "return 0l;");
-        _defaultMethodBody.put(CtClass.floatType, "return 0.0f;");
-        _defaultMethodBody.put(CtClass.doubleType, "return 0.0d;");
-        _defaultMethodBody.put(CtClass.voidType, "return;");
+        private final String _fieldName;
+
+        private final Class _type;
+
+        private final Object _value;
+
+        ConstructorArg(Class type, String fieldName, Object value)
+        {
+            _type = type;
+            _fieldName = fieldName;
+            _value = value;
+        }
+
+        String getFieldName()
+        {
+            return _fieldName;
+        }
+
+        Class getType()
+        {
+            return _type;
+        }
+
+        Object getValue()
+        {
+            return _value;
+        }
     }
 
     public InternalClassTransformationImpl(CtClass ctClass)
@@ -366,16 +390,12 @@
 
             newMethod.setModifiers(Modifier.PUBLIC);
 
-            _ctClass.addMethod(newMethod);
-
-            String body = _defaultMethodBody.get(method.getReturnType());
+            // Javassist will provide a minimal implementation for us (return 
null, false, 0,
+            // whatever).
 
-            // If null, then its an object (or array) return type
+            newMethod.setBody(null);
 
-            if (body == null)
-                body = "return null;";
-
-            newMethod.setBody(body);
+            _ctClass.addMethod(newMethod);
         }
         catch (CannotCompileException ex)
         {
@@ -433,8 +453,66 @@
 
     public void extendMethod(MethodSignature methodSignature, String 
methodBody)
     {
-        // TODO Auto-generated method stub
+        CtMethod method = findMethod(methodSignature);
+
+        try
+        {
+            method.insertAfter(methodBody);
+        }
+        catch (CannotCompileException ex)
+        {
+            throw new RuntimeException(ex);
+        }
+    }
+
+    private CtMethod findMethod(MethodSignature methodSignature)
+    {
+        for (CtMethod method : _ctClass.getDeclaredMethods())
+        {
+            if (match(method, methodSignature))
+                return method;
+        }
 
+        throw new IllegalArgumentException(TransformMessages.noDeclaredMethod(
+                methodSignature,
+                _ctClass));
+    }
+
+    private boolean match(CtMethod method, MethodSignature sig)
+    {
+        if (!sig.getMethodName().equals(method.getName()))
+            return false;
+
+        CtClass[] paramTypes;
+
+        try
+        {
+            paramTypes = method.getParameterTypes();
+        }
+        catch (NotFoundException ex)
+        {
+            throw new RuntimeException(ex);
+        }
+
+        String[] sigTypes = sig.getParameterTypes();
+
+        int count = sigTypes.length;
+
+        if (paramTypes.length != count)
+            return false;
+
+        for (int i = 0; i < count; i++)
+        {
+            String paramType = paramTypes[i].getName();
+
+            if (!paramType.equals(sigTypes[i]))
+                return false;
+        }
+
+        // Ignore exceptions thrown and modifiers.
+        // TODO: Validate a match on return type?
+
+        return true;
     }
 
     public List<String> findFieldsWithAnnotation(Class<? extends Annotation> 
annotationClass)
@@ -529,9 +607,108 @@
         return fieldName;
     }
 
+    public String addInjectedField(Class type, String suggestedName, Object 
value)
+    {
+        notNull(type, "type");
+
+        // TODO: Probably doesn't handle arrays and primitives.
+
+        String fieldName = newField(Modifier.PROTECTED, type.getName(), 
suggestedName);
+
+        _constructorArgs.add(new ConstructorArg(type, fieldName, value));
+
+        return fieldName;
+    }
+
     private CtClass convertNameToCtType(String type) throws NotFoundException
     {
         return _classPool.get(type);
+    }
+
+    public void finish()
+    {
+        BodyBuilder builder = new BodyBuilder();
+
+        builder.begin();
+
+        int count = _constructorArgs.size();
+
+        CtClass[] types = new CtClass[count];
+
+        for (int i = 0; i < count; i++)
+        {
+            ConstructorArg arg = _constructorArgs.get(i);
+
+            builder.addln("{0} = ${1};", arg.getFieldName(), i + 1);
+
+            try
+            {
+                types[i] = _classPool.get(arg.getType().getName());
+            }
+            catch (NotFoundException ex)
+            {
+                throw new RuntimeException(ex);
+            }
+        }
+
+        builder.end();
+
+        try
+        {
+            CtConstructor cons = CtNewConstructor.make(types, null, 
builder.toString(), _ctClass);
+            _ctClass.addConstructor(cons);
+        }
+        catch (CannotCompileException ex)
+        {
+            throw new RuntimeException(ex);
+        }
+
+    }
+
+    public String readMeta(String key)
+    {
+        return _meta.get(notBlank(key, "key"));
+    }
+
+    public void storeMeta(String key, String value)
+    {
+        notBlank(key, "key");
+
+        if (_meta.containsKey(key))
+            throw new IllegalArgumentException(TransformMessages.metaKeyExists(
+                    key,
+                    _meta.get(key),
+                    value));
+
+        _meta.put(key, notBlank(value, "value"));
+    }
+
+    public void addGetterMethod(String type, String methodName, String 
fieldName)
+    {
+        try
+        {
+            CtClass ctType = _classPool.get(type);
+
+            CtMethod method = CtNewMethod.make(
+                    ctType,
+                    notBlank(methodName, "methodName"),
+                    null,
+                    null,
+                    "return " + fieldName + ";",
+                    _ctClass);
+            _ctClass.addMethod(method);
+
+            _addedMethods.add(method);
+        }
+        catch (NotFoundException ex)
+        {
+            throw new RuntimeException(ex);
+        }
+        catch (CannotCompileException ex)
+        {
+            throw new RuntimeException(ex);
+        }
+
     }
 
 }

Modified: 
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/transform/TransformMessages.java
URL: 
http://svn.apache.org/viewcvs/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/transform/TransformMessages.java?rev=395987&r1=395986&r2=395987&view=diff
==============================================================================
--- 
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/transform/TransformMessages.java
 (original)
+++ 
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/transform/TransformMessages.java
 Fri Apr 21 11:59:10 2006
@@ -18,6 +18,7 @@
 
 import org.apache.hivemind.Messages;
 import org.apache.hivemind.impl.MessageFormatter;
+import org.apache.tapestry.transform.MethodSignature;
 
 /**
  * @author Howard M. Lewis Ship
@@ -51,5 +52,15 @@
     {
         return MESSAGES.format("field-already-claimed", new Object[]
         { fieldName, ctClass.getName(), existingTag, newTag });
+    }
+
+    static String metaKeyExists(String key, String existing, String value)
+    {
+        return MESSAGES.format("meta-key-exists", key, existing, value);
+    }
+
+    static String noDeclaredMethod(MethodSignature methodSignature, CtClass 
ctClass)
+    {
+        return MESSAGES.format("no-declared-method", methodSignature, 
ctClass.getName());
     }
 }

Added: 
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/transform/worker/ImplementResourceAwareWorker.java
URL: 
http://svn.apache.org/viewcvs/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/transform/worker/ImplementResourceAwareWorker.java?rev=395987&view=auto
==============================================================================
--- 
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/transform/worker/ImplementResourceAwareWorker.java
 (added)
+++ 
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/transform/worker/ImplementResourceAwareWorker.java
 Fri Apr 21 11:59:10 2006
@@ -0,0 +1,45 @@
+package org.apache.tapestry.internal.transform.worker;
+
+import java.lang.reflect.Modifier;
+
+import org.apache.tapestry.ComponentResources;
+import org.apache.tapestry.ResourceAware;
+import org.apache.tapestry.internal.InternalComponentResources;
+import org.apache.tapestry.model.MutableComponentModel;
+import org.apache.tapestry.transform.ClassTransformWorker;
+import org.apache.tapestry.transform.ClassTransformation;
+import org.apache.tapestry.transform.MethodSignature;
+import org.apache.tapestry.transform.TransformConstants;
+
+/**
+ * Transforms classes so that they implement the [EMAIL PROTECTED] 
org.apache.tapestry.ResourceAware}
+ * interface. In addition, sets things up so that the first constructor 
argument is an
+ * [EMAIL PROTECTED] org.apache.tapestry.internal.InternalComponentResources} 
that is exposed through a
+ * protected instance variable.
+ * <p>
+ * This worker should be "scheduled" to operate absolutely first.
+ * 
+ * @author Howard M. Lewis Ship
+ */
+public class ImplementResourceAwareWorker implements ClassTransformWorker
+{
+
+    public void transform(ClassTransformation transformation, 
MutableComponentModel model)
+    {
+        transformation.addImplementedInterface(ResourceAware.class);
+
+        String fieldName = transformation.addInjectedField(
+                InternalComponentResources.class,
+                "resources",
+                null);
+
+        MethodSignature sig = new MethodSignature(Modifier.PUBLIC, 
ComponentResources.class
+                .getName(), "getResources", null, null);
+
+        // Override the default, empty implementation to simply return the 
field.
+
+        transformation.extendMethod(sig, "return " + fieldName + ";");
+
+        transformation.storeMeta(TransformConstants.RESOURCES_FIELD_NAME_KEY, 
fieldName);
+    }
+}

Modified: 
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/transform/worker/RetainWorker.java
URL: 
http://svn.apache.org/viewcvs/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/transform/worker/RetainWorker.java?rev=395987&r1=395986&r2=395987&view=diff
==============================================================================
--- 
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/transform/worker/RetainWorker.java
 (original)
+++ 
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/transform/worker/RetainWorker.java
 Fri Apr 21 11:59:10 2006
@@ -17,8 +17,8 @@
 import java.util.List;
 
 import org.apache.tapestry.annotations.Retain;
-import org.apache.tapestry.internal.transform.ClassTransformWorker;
 import org.apache.tapestry.model.MutableComponentModel;
+import org.apache.tapestry.transform.ClassTransformWorker;
 import org.apache.tapestry.transform.ClassTransformation;
 
 /**

Modified: 
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/transform/worker/UnclaimedFieldWorker.java
URL: 
http://svn.apache.org/viewcvs/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/transform/worker/UnclaimedFieldWorker.java?rev=395987&r1=395986&r2=395987&view=diff
==============================================================================
--- 
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/transform/worker/UnclaimedFieldWorker.java
 (original)
+++ 
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/transform/worker/UnclaimedFieldWorker.java
 Fri Apr 21 11:59:10 2006
@@ -18,10 +18,10 @@
 
 import org.apache.hivemind.service.BodyBuilder;
 import org.apache.tapestry.events.ComponentLifecycle;
-import org.apache.tapestry.internal.transform.ClassTransformWorker;
-import org.apache.tapestry.internal.transform.TransformConstants;
 import org.apache.tapestry.model.MutableComponentModel;
+import org.apache.tapestry.transform.ClassTransformWorker;
 import org.apache.tapestry.transform.ClassTransformation;
+import org.apache.tapestry.transform.TransformConstants;
 
 /**
  * Designed to be just about the last worker in the pipeline. Its job is to 
add cleanup code that

Copied: 
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/transform/ClassTransformWorker.java
 (from r395912, 
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/transform/ClassTransformWorker.java)
URL: 
http://svn.apache.org/viewcvs/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/transform/ClassTransformWorker.java?p2=tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/transform/ClassTransformWorker.java&p1=tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/transform/ClassTransformWorker.java&r1=395912&r2=395987&rev=395987&view=diff
==============================================================================
--- 
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/transform/ClassTransformWorker.java
 (original)
+++ 
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/transform/ClassTransformWorker.java
 Fri Apr 21 11:59:10 2006
@@ -12,10 +12,9 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package org.apache.tapestry.internal.transform;
+package org.apache.tapestry.transform;
 
 import org.apache.tapestry.model.MutableComponentModel;
-import org.apache.tapestry.transform.ClassTransformation;
 
 /**
  * Interface for a set of objects that can perform component class 
transformations. Implementations

Modified: 
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/transform/ClassTransformation.java
URL: 
http://svn.apache.org/viewcvs/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/transform/ClassTransformation.java?rev=395987&r1=395986&r2=395987&view=diff
==============================================================================
--- 
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/transform/ClassTransformation.java
 (original)
+++ 
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/transform/ClassTransformation.java
 Fri Apr 21 11:59:10 2006
@@ -131,6 +131,19 @@
     String newField(int modifiers, String type, String suggestedName);
 
     /**
+     * Defines a new protected instance variable whose initial value is 
provided statically.
+     * 
+     * @param type
+     *            the type of object to inject
+     * @param suggestedName
+     *            the suggested name for the new field
+     * @param value
+     *            to be injected. This value is retained.
+     * @return the actual name of the injected field
+     */
+    String addInjectedField(Class type, String suggestedName, Object value);
+
+    /**
      * Transforms the class to implement the indicated interface. If the class 
(or its super class)
      * does not already implement the interface, then the interface is added, 
and default
      * implementations of any methods of the interface are added.
@@ -146,8 +159,9 @@
     void addImplementedInterface(Class interfaceClass);
 
     /**
-     * Extends an existing method. The body of the method is replaced with the 
provided body.
-     * However, a call to the Javassist pseudo-method $proceed() is required.
+     * Extends an existing method. The provided method body is inserted at the 
end of the existing
+     * method (i.e. [EMAIL PROTECTED] 
javassist.CtBehavior#insertAfter(java.lang.String)}). To access or
+     * change the return value, use the <code>$_</code> pseudo variable.
      * 
      * @param signature
      *            the signature of the method to extend
@@ -158,4 +172,32 @@
      *             Javassist method body can not be compiled
      */
     void extendMethod(MethodSignature methodSignature, String methodBody);
+
+    /**
+     * Stores meta data about the transformation. This is how workers can 
communicate; earlier
+     * workers may record meta data needed by later workers.
+     * 
+     * @throws IllegalArgumentException
+     *             if the provided key has already been stored
+     */
+    void storeMeta(String key, String value);
+
+    /*
+     * Retrieves previously stored meta data. @return value for key, or null 
if not found.
+     */
+
+    String readMeta(String key);
+
+    /**
+     * Adds a getter method, a public instance method that returns the value 
of a field. This is
+     * often paired with [EMAIL PROTECTED] #addInjectedField(Class, String, 
Object)}.
+     * 
+     * @param the
+     *            return type of the method
+     * @param methodName
+     *            the name of the method (i.e., "getFoo")
+     * @param fieldName
+     *            the field to return
+     */
+    void addGetterMethod(String type, String methodName, String fieldName);
 }

Modified: 
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/transform/MethodSignature.java
URL: 
http://svn.apache.org/viewcvs/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/transform/MethodSignature.java?rev=395987&r1=395986&r2=395987&view=diff
==============================================================================
--- 
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/transform/MethodSignature.java
 (original)
+++ 
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/transform/MethodSignature.java
 Fri Apr 21 11:59:10 2006
@@ -14,11 +14,10 @@
 
 package org.apache.tapestry.transform;
 
-import static org.apache.tapestry.util.Defense.notBlank;
-import static org.apache.tapestry.util.Defense.notNull;
-
 import java.lang.reflect.Modifier;
 
+import static org.apache.tapestry.util.Defense.notBlank;
+
 /**
  * A representation of a method signature, which consists of its name, 
modifiers (primarily,
  * visibility), return type, parameter types, and declared exception types.
@@ -63,8 +62,13 @@
         // TODO: Checks that no element within the two arrays
         // is null or blank.
 
-        _parameterTypes = notNull(parameterTypes, "parameterTypes");
-        _exceptionTypes = notNull(exceptionTypes, "exceptionTypes");
+        _parameterTypes = typeNamesOrEmpty(parameterTypes);
+        _exceptionTypes = typeNamesOrEmpty(exceptionTypes);
+    }
+
+    private String[] typeNamesOrEmpty(String[] types)
+    {
+        return types == null ? EMPTY_STRINGS : types;
     }
 
     /**

Added: 
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/transform/TransformConstants.java
URL: 
http://svn.apache.org/viewcvs/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/transform/TransformConstants.java?rev=395987&view=auto
==============================================================================
--- 
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/transform/TransformConstants.java
 (added)
+++ 
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/transform/TransformConstants.java
 Fri Apr 21 11:59:10 2006
@@ -0,0 +1,31 @@
+package org.apache.tapestry.transform;
+
+/**
+ * Constants used by implementations of [EMAIL PROTECTED] 
org.apache.tapestry.transform.ClassTransformWorker}.
+ * 
+ * @author Howard M. Lewis Ship
+ */
+public final class TransformConstants
+{
+    /**
+     * Meta key used to get the name of the field which will contain the
+     * [EMAIL PROTECTED] org.apache.tapestry.ComponentResources} instance for 
the component (which is passed
+     * into the component instance via its constructor).
+     */
+    public static final String RESOURCES_FIELD_NAME_KEY = 
"org.apache.tapestry.resources-field-name-key";
+
+    /** Signature for [EMAIL PROTECTED] 
org.apache.tapestry.events.ComponentLifecycle#containingPageDidLoad()}. */
+    public static final MethodSignature CONTAINING_PAGE_DID_LOAD_SIGNATURE = 
new MethodSignature(
+            "containingPageDidLoad");
+
+    /**
+     * Signature for [EMAIL PROTECTED] 
org.apache.tapestry.events.ComponentLifecycle#containingPageDidDetach()}.
+     */
+    public static final MethodSignature CONTAINING_PAGE_DID_DETACH = new 
MethodSignature(
+            "containingPageDidDetach");
+
+    /** Prevent instantiation. */
+    private TransformConstants()
+    {
+    }
+}

Modified: 
tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/internal/transform/TransformStrings.properties
URL: 
http://svn.apache.org/viewcvs/tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/internal/transform/TransformStrings.properties?rev=395987&r1=395986&r2=395987&view=diff
==============================================================================
--- 
tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/internal/transform/TransformStrings.properties
 (original)
+++ 
tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/internal/transform/TransformStrings.properties
 Fri Apr 21 11:59:10 2006
@@ -15,4 +15,6 @@
 no-constructor-found=Unable to find an applicable constructor for class {0}.
 missing-declared-field=Class {0} does not contain a field named ''{1}''.
 error-adding-method=Error adding method {1} to class {0}: {2} 
-field-already-claimed=Field {0} of class {1} is already claimed by {2} and can 
not be claimed by {3}.
\ No newline at end of file
+field-already-claimed=Field {0} of class {1} is already claimed by {2} and can 
not be claimed by {3}.
+meta-key-exists=Class transformation meta key ''{0}'' already contains value 
''{1}'' and can not be set to ''{2}''.
+no-declared-method=Class {1} does not declare method ''{0}''.
\ No newline at end of file

Modified: 
tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/transform/InternalClassTransformationImplTest.java
URL: 
http://svn.apache.org/viewcvs/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/transform/InternalClassTransformationImplTest.java?rev=395987&r1=395986&r2=395987&view=diff
==============================================================================
--- 
tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/transform/InternalClassTransformationImplTest.java
 (original)
+++ 
tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/transform/InternalClassTransformationImplTest.java
 Fri Apr 21 11:59:10 2006
@@ -16,7 +16,7 @@
 
 import java.lang.annotation.Documented;
 import java.lang.annotation.Target;
-import java.lang.reflect.Method;
+import java.lang.reflect.Constructor;
 import java.lang.reflect.Modifier;
 import java.util.Arrays;
 import java.util.List;
@@ -27,15 +27,20 @@
 import javassist.Loader;
 import javassist.NotFoundException;
 
+import org.apache.tapestry.ResourceAware;
 import org.apache.tapestry.annotations.ComponentClass;
 import org.apache.tapestry.annotations.Retain;
+import org.apache.tapestry.internal.InternalComponentResources;
 import org.apache.tapestry.internal.transform.pages.AbstractFoo;
 import org.apache.tapestry.internal.transform.pages.BarImpl;
 import 
org.apache.tapestry.internal.transform.pages.ChildClassInheritsAnnotation;
 import org.apache.tapestry.internal.transform.pages.ClaimedFields;
 import org.apache.tapestry.internal.transform.pages.ParentClass;
 import org.apache.tapestry.internal.transform.pages.TargetObject;
+import 
org.apache.tapestry.internal.transform.worker.ImplementResourceAwareWorker;
+import org.apache.tapestry.model.MutableComponentModel;
 import org.apache.tapestry.test.TestBase;
+import org.apache.tapestry.transform.ClassTransformWorker;
 import org.apache.tapestry.transform.ClassTransformation;
 import org.testng.annotations.Configuration;
 import org.testng.annotations.Test;
@@ -45,6 +50,7 @@
 import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertNotNull;
 import static org.testng.Assert.assertNull;
+import static org.testng.Assert.assertSame;
 import static org.testng.Assert.assertTrue;
 
 /**
@@ -95,7 +101,7 @@
         assertEquals(ct.newMemberName("conflictMethod"), "_$conflictMethod_0");
     }
 
-    private ClassTransformation createClassTransformation(Class targetClass)
+    private InternalClassTransformation createClassTransformation(Class 
targetClass)
             throws NotFoundException
     {
         CtClass ctClass = findCtClass(targetClass);
@@ -103,6 +109,30 @@
     }
 
     @Test
+    public void meta() throws Exception
+    {
+        ClassTransformation ct = createClassTransformation(ParentClass.class);
+
+        assertNull(ct.readMeta("foo.bar"));
+
+        ct.storeMeta("foo.bar", "baz");
+
+        assertEquals(ct.readMeta("foo.bar"), "baz");
+
+        try
+        {
+            ct.storeMeta("foo.bar", "Biff");
+            unreachable();
+        }
+        catch (IllegalArgumentException ex)
+        {
+            assertEquals(
+                    ex.getMessage(),
+                    "Class transformation meta key 'foo.bar' already contains 
value 'baz' and can not be set to 'Biff'.");
+        }
+    }
+
+    @Test
     public void findAnnotationOnUnknownField() throws Exception
     {
         ClassTransformation ct = createClassTransformation(ParentClass.class);
@@ -303,9 +333,53 @@
     }
 
     @Test
+    public void injectedField() throws Exception
+    {
+        MutableComponentModel model = newMock(MutableComponentModel.class);
+        InternalComponentResources resources = 
newMock(InternalComponentResources.class);
+
+        ClassLoader childLoader = newLoader();
+
+        CtClass targetObjectCtClass = findCtClass(TargetObject.class);
+
+        InternalClassTransformation ct = new 
InternalClassTransformationImpl(targetObjectCtClass);
+
+        replay();
+
+        ClassTransformWorker worker = new ImplementResourceAwareWorker();
+
+        worker.transform(ct, model);
+
+        verify();
+
+        ct.finish();
+
+        Class modified = _classPool.toClass(targetObjectCtClass, childLoader);
+
+        Constructor cons = modified.getConstructors()[0];
+
+        ResourceAware instance = (ResourceAware) cons.newInstance(resources);
+
+        assertSame(instance.getResources(), resources);
+    }
+
+    private Loader newLoader()
+    {
+        Loader loader = new Loader(_contextClassLoader, _classPool);
+
+        // This ensures that only the classes we explicitly access and modify
+        // are loaded by the new loader; everthing else comes out of the common
+        // context class loader, which prevents a lot of nasty class cast 
exceptions.
+
+        loader.delegateLoadingOf("org.apache.tapestry.");
+
+        return loader;
+    }
+
+    @Test
     public void addImplementedInterface() throws Exception
     {
-        ClassLoader childLoader = new Loader(_contextClassLoader, _classPool);
+        ClassLoader childLoader = newLoader();
 
         CtClass targetObjectCtClass = findCtClass(TargetObject.class);
 
@@ -330,28 +404,21 @@
 
         Object target = modified.newInstance();
 
-        invoke(target, "foo");
+        FooInterface asFoo = (FooInterface) target;
 
-        assertEquals(invoke(target, "getBoolean"), false);
-        assertEquals(invoke(target, "getByte"), (byte) 0);
-        assertEquals(invoke(target, "getShort"), (short) 0);
-        assertEquals(invoke(target, "getInt"), 0);
-        assertEquals(invoke(target, "getLong"), 0l);
-        assertEquals(invoke(target, "getFloat"), 0.0f);
-        assertEquals(invoke(target, "getDouble"), 0.0d);
-        assertNull(invoke(target, "getString"));
-        assertNull(invoke(target, "getObjectArray"));
-        assertNull(invoke(target, "getIntArray"));
-    }
+        asFoo.foo();
 
-    @SuppressWarnings("unchecked")
-    private <T> T invoke(Object target, String methodName) throws Exception
-    {
-        Class targetClass = target.getClass();
+        GetterMethodsInterface getters = (GetterMethodsInterface) target;
 
-        Method method = targetClass.getMethod(methodName);
-
-        return (T) method.invoke(target);
+        assertEquals(getters.getBoolean(), false);
+        assertEquals(getters.getByte(), (byte) 0);
+        assertEquals(getters.getShort(), (short) 0);
+        assertEquals(getters.getInt(), 0);
+        assertEquals(getters.getLong(), 0l);
+        assertEquals(getters.getFloat(), 0.0f);
+        assertEquals(getters.getDouble(), 0.0d);
+        assertNull(getters.getString());
+        assertNull(getters.getObjectArray());
+        assertNull(getters.getIntArray());
     }
-
 }

Modified: 
tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/transform/worker/UnclaimedFieldWorkerTest.java
URL: 
http://svn.apache.org/viewcvs/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/transform/worker/UnclaimedFieldWorkerTest.java?rev=395987&r1=395986&r2=395987&view=diff
==============================================================================
--- 
tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/transform/worker/UnclaimedFieldWorkerTest.java
 (original)
+++ 
tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/transform/worker/UnclaimedFieldWorkerTest.java
 Fri Apr 21 11:59:10 2006
@@ -18,10 +18,10 @@
 
 import org.apache.hivemind.service.BodyBuilder;
 import org.apache.tapestry.events.ComponentLifecycle;
-import org.apache.tapestry.internal.transform.TransformConstants;
 import org.apache.tapestry.model.MutableComponentModel;
 import org.apache.tapestry.test.BaseTestCase;
 import org.apache.tapestry.transform.ClassTransformation;
+import org.apache.tapestry.transform.TransformConstants;
 import org.testng.annotations.Test;
 
 /**



---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to