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


Reply via email to