You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tapestry.apache.org by hl...@apache.org on 2011/07/21 20:20:58 UTC
svn commit: r1149300 - in
/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5:
internal/transform/RenderPhaseMethodWorker.java services/TapestryModule.java
Author: hlship
Date: Thu Jul 21 18:20:53 2011
New Revision: 1149300
URL: http://svn.apache.org/viewvc?rev=1149300&view=rev
Log:
TAP5-1508: First pass at converting RenderPhaseMethodWorker to new API, and using InstructionBuilder
to implement the methods, rather than component advice
Modified:
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/transform/RenderPhaseMethodWorker.java
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TapestryModule.java
Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/transform/RenderPhaseMethodWorker.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/transform/RenderPhaseMethodWorker.java?rev=1149300&r1=1149299&r2=1149300&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/transform/RenderPhaseMethodWorker.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/transform/RenderPhaseMethodWorker.java Thu Jul 21 18:20:53 2011
@@ -14,36 +14,27 @@
package org.apache.tapestry5.internal.transform;
-import java.lang.annotation.Annotation;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.Map.Entry;
-
import org.apache.tapestry5.MarkupWriter;
-import org.apache.tapestry5.annotations.AfterRender;
-import org.apache.tapestry5.annotations.AfterRenderBody;
-import org.apache.tapestry5.annotations.AfterRenderTemplate;
-import org.apache.tapestry5.annotations.BeforeRenderBody;
-import org.apache.tapestry5.annotations.BeforeRenderTemplate;
-import org.apache.tapestry5.annotations.BeginRender;
-import org.apache.tapestry5.annotations.CleanupRender;
-import org.apache.tapestry5.annotations.SetupRender;
+import org.apache.tapestry5.annotations.*;
+import org.apache.tapestry5.func.F;
+import org.apache.tapestry5.func.Flow;
import org.apache.tapestry5.func.Predicate;
import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
import org.apache.tapestry5.ioc.internal.util.InternalUtils;
import org.apache.tapestry5.model.MutableComponentModel;
+import org.apache.tapestry5.plastic.*;
import org.apache.tapestry5.runtime.Event;
-import org.apache.tapestry5.services.ClassTransformation;
-import org.apache.tapestry5.services.ComponentClassTransformWorker;
-import org.apache.tapestry5.services.ComponentMethodAdvice;
-import org.apache.tapestry5.services.ComponentMethodInvocation;
-import org.apache.tapestry5.services.MethodAccess;
+import org.apache.tapestry5.services.*;
import org.apache.tapestry5.services.MethodInvocationResult;
-import org.apache.tapestry5.services.TransformConstants;
-import org.apache.tapestry5.services.TransformMethod;
-import org.apache.tapestry5.services.TransformMethodSignature;
+import org.apache.tapestry5.services.transform.ComponentClassTransformWorker2;
+import org.apache.tapestry5.services.transform.TransformationSupport;
+
+import java.lang.annotation.Annotation;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
/**
* Converts one of the methods of {@link org.apache.tapestry5.runtime.Component} into a chain of
@@ -52,7 +43,7 @@ import org.apache.tapestry5.services.Tra
* way.
*/
@SuppressWarnings("all")
-public class RenderPhaseMethodWorker implements ComponentClassTransformWorker
+public class RenderPhaseMethodWorker implements ComponentClassTransformWorker2
{
private final class RenderPhaseMethodAdvice implements ComponentMethodAdvice
{
@@ -126,12 +117,15 @@ public class RenderPhaseMethodWorker imp
private final Map<Class<? extends Annotation>, TransformMethodSignature> annotationToSignature = CollectionFactory
.newMap();
+ private final Map<Class<? extends Annotation>, MethodDescription> annotationToDescription = CollectionFactory.newMap();
+
private final Map<String, Class<? extends Annotation>> nameToAnnotation = CollectionFactory.newCaseInsensitiveMap();
private final Set<Class<? extends Annotation>> reverseAnnotations = CollectionFactory.newSet(AfterRenderBody.class,
AfterRenderTemplate.class, AfterRender.class, CleanupRender.class);
private final Set<TransformMethodSignature> lifecycleMethods = CollectionFactory.newSet();
+ private final Set<MethodDescription> lifecycleMethods2 = CollectionFactory.newSet();
{
annotationToSignature.put(SetupRender.class, TransformConstants.SETUP_RENDER_SIGNATURE);
@@ -143,11 +137,27 @@ public class RenderPhaseMethodWorker imp
annotationToSignature.put(AfterRender.class, TransformConstants.AFTER_RENDER_SIGNATURE);
annotationToSignature.put(CleanupRender.class, TransformConstants.CLEANUP_RENDER_SIGNATURE);
+ annotationToDescription.put(SetupRender.class, TransformConstants.SETUP_RENDER_DESCRIPTION);
+ annotationToDescription.put(BeginRender.class, TransformConstants.BEGIN_RENDER_DESCRIPTION);
+ annotationToDescription.put(BeforeRenderTemplate.class, TransformConstants.BEFORE_RENDER_TEMPLATE_DESCRIPTION);
+ annotationToDescription.put(BeforeRenderBody.class, TransformConstants.BEFORE_RENDER_BODY_DESCRIPTION);
+ annotationToDescription.put(AfterRenderBody.class, TransformConstants.AFTER_RENDER_BODY_DESCRIPTION);
+ annotationToDescription.put(AfterRenderTemplate.class, TransformConstants.AFTER_RENDER_TEMPLATE_DESCRIPTION);
+ annotationToDescription.put(AfterRender.class, TransformConstants.AFTER_RENDER_DESCRIPTION);
+ annotationToDescription.put(CleanupRender.class, TransformConstants.CLEANUP_RENDER_DESCRIPTION);
+
+
for (Entry<Class<? extends Annotation>, TransformMethodSignature> me : annotationToSignature.entrySet())
{
- nameToAnnotation.put(me.getValue().getMethodName(), me.getKey());
lifecycleMethods.add(me.getValue());
}
+
+ for (Entry<Class<? extends Annotation>, MethodDescription> me : annotationToDescription.entrySet())
+ {
+ nameToAnnotation.put(me.getValue().methodName, me.getKey());
+ lifecycleMethods2.add(me.getValue());
+ }
+
}
public void transform(ClassTransformation transformation, MutableComponentModel model)
@@ -160,8 +170,21 @@ public class RenderPhaseMethodWorker imp
}
}
+ public void transform(PlasticClass plasticClass, TransformationSupport support, MutableComponentModel model)
+ {
+ Map<Class, List<PlasticMethod>> methods = mapRenderPhaseAnnotationToMethods(plasticClass);
+
+ for (Class renderPhaseAnnotation : methods.keySet())
+ {
+ mapMethodsToRenderPhase(plasticClass, support.isRootTransformation(), renderPhaseAnnotation, methods.get(renderPhaseAnnotation));
+
+ model.addRenderPhase(renderPhaseAnnotation);
+ }
+
+ }
+
private void mapMethodsToRenderPhase(ClassTransformation transformation, MutableComponentModel model,
- Class annotationType, List<TransformMethod> methods)
+ Class annotationType, List<TransformMethod> methods)
{
ComponentMethodAdvice renderPhaseAdvice = createAdviceForMethods(annotationType, methods);
@@ -172,6 +195,96 @@ public class RenderPhaseMethodWorker imp
model.addRenderPhase(annotationType);
}
+ private InstructionBuilderCallback JUST_RETURN = new InstructionBuilderCallback()
+ {
+ public void doBuild(InstructionBuilder builder)
+ {
+ builder.returnDefaultValue();
+ }
+ };
+
+ private void mapMethodsToRenderPhase(final PlasticClass plasticClass, final boolean isRoot, Class annotationType, List<PlasticMethod> methods)
+ {
+
+ // The method, defined by Component, that will in turn invoke the other methods.
+
+ final MethodDescription interfaceMethodDescription = annotationToDescription.get(annotationType);
+ PlasticMethod interfaceMethod = plasticClass.introduceMethod(interfaceMethodDescription);
+
+ final boolean reverse = reverseAnnotations.contains(annotationType);
+
+ final Flow<PlasticMethod> orderedMethods =
+ reverse ? F.flow(methods).reverse()
+ : F.flow(methods);
+
+ interfaceMethod.changeImplementation(new InstructionBuilderCallback()
+ {
+ private void addSuperCall(InstructionBuilder builder)
+ {
+ // At the top of the inheritance, there's no need to call super (this is a pretty standard case).
+ if (!isRoot)
+ {
+ builder.loadThis().loadArguments().invokeSpecial(plasticClass.getSuperClassName(), interfaceMethodDescription);
+ }
+ }
+
+ private void invokeMethod(InstructionBuilder builder, PlasticMethod method)
+ {
+ // First, tell the Event object what method is being invoked.
+
+ builder.loadArgument(1);
+ builder.loadConstant(
+ String.format("%s.%s", plasticClass.getClassName(),
+ method.getDescription().toShortString()));
+ builder.invoke(Event.class, void.class, "setMethodDescription", String.class);
+
+ builder.loadThis();
+
+ // Methods either take no parameters, or take a MarkupWriter parameter.
+
+ if (method.getParameters().size() > 0)
+ {
+ builder.loadArgument(0);
+ }
+
+ builder.invokeVirtual(method);
+
+ // Non-void methods will pass a value to the event.
+
+ if (!method.getDescription().returnType.equals("void"))
+ {
+ builder.boxPrimitive(method.getDescription().returnType);
+ builder.loadArgument(1).swap();
+
+ builder.invoke(Event.class, boolean.class, "storeResult", Object.class);
+
+ builder.when(Condition.NON_ZERO, JUST_RETURN);
+ }
+ }
+
+ public void doBuild(InstructionBuilder builder)
+ {
+ if (!reverse)
+ {
+ addSuperCall(builder);
+ }
+
+ for (PlasticMethod invokedMethod : orderedMethods)
+ {
+ invokeMethod(builder, invokedMethod);
+ }
+
+ if (reverse)
+ {
+ addSuperCall(builder);
+ }
+
+ builder.returnDefaultValue();
+ }
+ });
+ }
+
+
private ComponentMethodAdvice createAdviceForMethods(Class annotationType, List<TransformMethod> methods)
{
boolean reverse = reverseAnnotations.contains(annotationType);
@@ -242,6 +355,22 @@ public class RenderPhaseMethodWorker imp
return map;
}
+
+ private Map<Class, List<PlasticMethod>> mapRenderPhaseAnnotationToMethods(PlasticClass plasticClass)
+ {
+ Map<Class, List<PlasticMethod>> map = CollectionFactory.newMap();
+
+ Flow<PlasticMethod> matches = matchAllMethodsNotOverriddenFromBaseClass(plasticClass);
+
+ for (PlasticMethod method : matches)
+ {
+ addMethodToRenderPhaseCategoryMap(map, method);
+ }
+
+ return map;
+ }
+
+
private void addMethodToRenderPhaseCategoryMap(Map<Class, List<TransformMethod>> map, TransformMethod method)
{
Class categorized = categorizeMethod(method);
@@ -250,6 +379,19 @@ public class RenderPhaseMethodWorker imp
InternalUtils.addToMapList(map, categorized, method);
}
+
+ private void addMethodToRenderPhaseCategoryMap(Map<Class, List<PlasticMethod>> map, PlasticMethod method)
+ {
+ Class categorized = categorizeMethod(method);
+
+ if (categorized != null)
+ {
+ validateAsRenderPhaseMethod(method);
+
+ InternalUtils.addToMapList(map, categorized, method);
+ }
+ }
+
private Class categorizeMethod(TransformMethod method)
{
for (Class annotationClass : annotationToSignature.keySet())
@@ -261,6 +403,17 @@ public class RenderPhaseMethodWorker imp
return nameToAnnotation.get(method.getName());
}
+ private Class categorizeMethod(PlasticMethod method)
+ {
+ for (Class annotationClass : annotationToDescription.keySet())
+ {
+ if (method.hasAnnotation(annotationClass))
+ return annotationClass;
+ }
+
+ return nameToAnnotation.get(method.getDescription().methodName);
+ }
+
private List<TransformMethod> matchAllMethodsNotOverriddenFromBaseClass(final ClassTransformation transformation)
{
return transformation.matchMethods(new Predicate<TransformMethod>()
@@ -272,4 +425,37 @@ public class RenderPhaseMethodWorker imp
});
}
+
+ private void validateAsRenderPhaseMethod(PlasticMethod method)
+ {
+ final String[] argumentTypes = method.getDescription().argumentTypes;
+
+ switch (argumentTypes.length)
+ {
+ case 0:
+ break;
+
+ case 1:
+ if (argumentTypes[0].equals(MarkupWriter.class.getName()))
+ break;
+ default:
+ throw new RuntimeException(
+ String.format(
+ "Method %s is not a valid render phase method: it should take no parameters, or take a single parameter of type MarkupWriter.",
+ method.toString()));
+ }
+ }
+
+
+ private Flow<PlasticMethod> matchAllMethodsNotOverriddenFromBaseClass(final PlasticClass plasticClass)
+ {
+ return F.flow(plasticClass.getMethods()).filter(new Predicate<PlasticMethod>()
+ {
+ public boolean accept(PlasticMethod method)
+ {
+ return !method.isOverride() && !lifecycleMethods2.contains(method.getDescription());
+ }
+ });
+ }
+
}
Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TapestryModule.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TapestryModule.java?rev=1149300&r1=1149299&r2=1149300&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TapestryModule.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TapestryModule.java Thu Jul 21 18:20:53 2011
@@ -492,13 +492,13 @@ public final class TapestryModule
/**
* Adds a number of standard component class transform workers:
- * <ul>
+ * <dl>
* <dt>Parameter</dt>
* <dd>Identifies parameters based on the {@link org.apache.tapestry5.annotations.Parameter} annotation</dd>
* <dt>BindParameter</dt>
* <dd>Support for the {@link BindParameter} annotation</dd>
* <dt>Property</dt>
- * <dd>Generates accessor methods if {@link org.apache.tapestry5.annotations.Property} annotation is present</dd> *
+ * <dd>Generates accessor methods if {@link org.apache.tapestry5.annotations.Property} annotation is present</dd>
* <dt>Import</dt>
* <dd>Supports the {@link Import} annotation</dd>
* <dt>UnclaimedField</dt>
@@ -509,7 +509,9 @@ public final class TapestryModule
* <dd>Ensures all components also implement {@link org.apache.tapestry5.runtime.RenderCommand}</dd>
* <dt>SupportsInformalParameters</dt>
* <dd>Checks for the annotation</dd>
- * </ul>
+ * <dt>RenderPhase</dt>
+ * <dd>Link in render phaes methods</dd>
+ * </dl>
*/
@Contribute(ComponentClassTransformWorker2.class)
public static void provideTransformWorkers(
@@ -546,6 +548,8 @@ public final class TapestryModule
configuration.add("SupportsInformalParameters", new SupportsInformalParametersWorker());
+ configuration.addInstance("RenderPhase", RenderPhaseMethodWorker.class);
+
// This one is always last. Any additional private fields that aren't
// annotated will
// be converted to clear out at the end of the request.
@@ -579,8 +583,6 @@ public final class TapestryModule
* <dd>Checks for meta data annotations and adds it to the component model</dd>
* <dt>ApplicationState</dt>
* <dd>Converts fields that reference application state objects
- * <dt>RenderPhase</dt>
- * <dd>Link in render phaes methods</dd>
* <dt>Cached</dt>
* <dd>Checks for the {@link org.apache.tapestry5.annotations.Cached} annotation</dd>
* <dt>Log</dt>
@@ -613,8 +615,6 @@ public final class TapestryModule
configuration
.addInstance("ActivationRequestParameter", ActivationRequestParameterWorker.class, "after:OnEvent");
- configuration.addInstance("RenderPhase", RenderPhaseMethodWorker.class);
-
// Ideally, these should be ordered pretty late in the process to make
// sure there are no
// side effects with other workers that do work inside the page