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