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]