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 2010/02/19 19:54:29 UTC

svn commit: r911931 [2/3] - in /tapestry/tapestry5/trunk: src/site/apt/ tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/ tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ tapestry-core/src/main/java/org/apache/tape...

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/transform/ParameterWorker.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/transform/ParameterWorker.java?rev=911931&r1=911930&r2=911931&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/transform/ParameterWorker.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/transform/ParameterWorker.java Fri Feb 19 18:54:27 2010
@@ -14,7 +14,6 @@
 
 package org.apache.tapestry5.internal.transform;
 
-import java.util.Iterator;
 import java.util.List;
 
 import org.apache.tapestry5.Binding;
@@ -23,19 +22,14 @@
 import org.apache.tapestry5.internal.InternalComponentResources;
 import org.apache.tapestry5.internal.bindings.LiteralBinding;
 import org.apache.tapestry5.internal.services.ComponentClassCache;
+import org.apache.tapestry5.ioc.Predicate;
 import org.apache.tapestry5.ioc.internal.util.InternalUtils;
 import org.apache.tapestry5.ioc.internal.util.TapestryException;
 import org.apache.tapestry5.ioc.services.TypeCoercer;
 import org.apache.tapestry5.model.MutableComponentModel;
-import org.apache.tapestry5.services.BindingSource;
-import org.apache.tapestry5.services.ClassTransformation;
-import org.apache.tapestry5.services.ComponentClassTransformWorker;
-import org.apache.tapestry5.services.ComponentDefaultProvider;
-import org.apache.tapestry5.services.ComponentValueProvider;
-import org.apache.tapestry5.services.MethodFilter;
-import org.apache.tapestry5.services.TransformConstants;
-import org.apache.tapestry5.services.TransformField;
-import org.apache.tapestry5.services.TransformMethodSignature;
+import org.apache.tapestry5.services.*;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 /**
  * Responsible for identifying parameters via the {@link org.apache.tapestry5.annotations.Parameter} annotation on
@@ -43,6 +37,69 @@
  */
 public class ParameterWorker implements ComponentClassTransformWorker
 {
+    private final Logger logger = LoggerFactory.getLogger(ParameterWorker.class);
+
+    private final class InvokeResetOnParameterConduit implements ComponentMethodAdvice
+    {
+        private final FieldAccess conduitAccess;
+
+        private InvokeResetOnParameterConduit(FieldAccess conduitAccess)
+        {
+            this.conduitAccess = conduitAccess;
+        }
+
+        public void advise(ComponentMethodInvocation invocation)
+        {
+            getConduit(invocation, conduitAccess).reset();
+
+            invocation.proceed();
+        }
+    }
+
+    private final class InvokeParameterDefaultMethod implements ComponentMethodAdvice
+    {
+        private final FieldAccess conduitAccess;
+
+        private final MethodAccess defaultMethodAccess;
+
+        private InvokeParameterDefaultMethod(FieldAccess conduitAccess, MethodAccess defaultMethodAccess)
+        {
+            this.conduitAccess = conduitAccess;
+            this.defaultMethodAccess = defaultMethodAccess;
+        }
+
+        public void advise(ComponentMethodInvocation invocation)
+        {
+            logger.debug(String.format("%s invoking default method %s", invocation.getComponentResources()
+                    .getCompleteId(), defaultMethodAccess));
+
+            MethodInvocationResult result = defaultMethodAccess.invoke(invocation.getInstance());
+
+            result.rethrow();
+
+            getConduit(invocation, conduitAccess).setDefault(result.getReturnValue());
+
+            invocation.proceed();
+        }
+    }
+
+    private final class InvokeLoadOnParmeterConduit implements ComponentMethodAdvice
+    {
+        private final FieldAccess conduitAccess;
+
+        private InvokeLoadOnParmeterConduit(FieldAccess conduitAccess)
+        {
+            this.conduitAccess = conduitAccess;
+        }
+
+        public void advise(ComponentMethodInvocation invocation)
+        {
+            getConduit(invocation, conduitAccess).load();
+
+            invocation.proceed();
+        }
+    }
+
     private final ComponentClassCache classCache;
 
     private final BindingSource bindingSource;
@@ -62,57 +119,90 @@
 
     public void transform(ClassTransformation transformation, MutableComponentModel model)
     {
-        List<String> fieldNames = transformation.findFieldsWithAnnotation(Parameter.class);
+        transformFields(transformation, model, true);
+        transformFields(transformation, model, false);
+    }
 
-        for (int pass = 0; pass < 2; pass++)
+    private void transformFields(ClassTransformation transformation, MutableComponentModel model, boolean principal)
+    {
+        for (TransformField field : matchParameterFields(transformation, principal))
         {
-            Iterator<String> i = fieldNames.iterator();
+            convertFieldIntoParameter(transformation, model, field);
+        }
+    }
 
-            while (i.hasNext())
+    private List<TransformField> matchParameterFields(ClassTransformation transformation, final boolean principal)
+    {
+        Predicate<TransformField> predicate = new Predicate<TransformField>()
+        {
+            public boolean accept(TransformField field)
             {
-                String fieldName = i.next();
+                Parameter annotation = field.getAnnotation(Parameter.class);
+
+                return annotation != null && annotation.principal() == principal;
+            }
+        };
+
+        return transformation.matchFields(predicate);
+    }
 
-                Parameter annotation = transformation
-                        .getFieldAnnotation(fieldName, Parameter.class);
+    private void convertFieldIntoParameter(ClassTransformation transformation, MutableComponentModel model,
+            TransformField field)
+    {
+        Parameter annotation = field.getAnnotation(Parameter.class);
 
-                // Process the principal annotations on the first pass, handle the others
-                // on the second pass.
+        String fieldType = field.getType();
 
-                boolean process = pass == 0 ? annotation.principal() : true;
+        String parameterName = getParameterName(field.getName(), annotation.name());
 
-                if (process)
-                {
-                    convertFieldIntoParameter(fieldName, annotation, transformation, model);
+        field.claim(annotation);
 
-                    i.remove();
-                }
-            }
-        }
+        model.addParameter(parameterName, annotation.required(), annotation.allowNull(), annotation.defaultPrefix(),
+                annotation.cache());
+
+        ComponentValueProvider<ParameterConduit> provider = createParameterConduitProvider(parameterName, fieldType,
+                annotation);
+
+        TransformField conduitField = transformation.addIndirectInjectedField(ParameterConduit.class, parameterName
+                + "$conduit", provider);
+
+        FieldAccess conduitAccess = conduitField.getAccess();
 
+        addCodeForParameterDefaultMethod(transformation, parameterName, conduitAccess);
+
+        field.replaceAccess(conduitField);
+
+        invokeLoadOnParameterConduitAtPageLoad(transformation, conduitAccess);
+
+        invokeResetOnParameterConduitAtPostRenderCleanup(transformation, conduitAccess);
     }
 
-    private void convertFieldIntoParameter(String fieldName, final Parameter annotation,
-            ClassTransformation transformation, MutableComponentModel model)
+    private void invokeResetOnParameterConduitAtPostRenderCleanup(ClassTransformation transformation,
+            final FieldAccess conduitAccess)
     {
-        final String fieldTypeName = transformation.getFieldType(fieldName);
+        ComponentMethodAdvice advice = new InvokeResetOnParameterConduit(conduitAccess);
 
-        final String parameterName = getParameterName(fieldName, annotation.name());
+        addMethodAdvice(transformation, TransformConstants.POST_RENDER_CLEANUP_SIGNATURE, advice);
+    }
 
-        final boolean enableCaching = annotation.cache();
+    private void addMethodAdvice(ClassTransformation transformation, TransformMethodSignature methodSignature,
+            ComponentMethodAdvice advice)
+    {
+        transformation.getOrCreateMethod(methodSignature).addAdvice(advice);
+    }
 
-        model.addParameter(parameterName, annotation.required(), annotation.allowNull(), annotation
-                .defaultPrefix(), enableCaching);
+    private void invokeLoadOnParameterConduitAtPageLoad(ClassTransformation transformation, FieldAccess conduitAccess)
+    {
+        ComponentMethodAdvice pageLoadAdvice = new InvokeLoadOnParmeterConduit(conduitAccess);
 
-        transformation.claimField(fieldName, annotation);
+        addPageLoadAdvice(transformation, pageLoadAdvice);
+    }
 
-        ComponentValueProvider<ParameterConduit> provider = new ComponentValueProvider<ParameterConduit>()
+    private ComponentValueProvider<ParameterConduit> createParameterConduitProvider(final String parameterName,
+            final String fieldTypeName, final Parameter annotation)
+    {
+        return new ComponentValueProvider<ParameterConduit>()
         {
-            // Invoked from the components' constructor. This causes a few issues (it would be
-            // better
-            // if there was a way to defer until the component's page loaded lifecycle method). The
-            // issues
-            // are addressed by deferring some behaviors until the load() method.
-
             public ParameterConduit get(ComponentResources resources)
             {
                 final InternalComponentResources icr = (InternalComponentResources) resources;
@@ -130,7 +220,7 @@
                     // Default value for parameter, computed *once* at
                     // page load time.
 
-                    private Object defaultValue;
+                    private Object defaultValue = classCache.defaultValueForType(fieldTypeName);
 
                     private Binding parameterBinding;
 
@@ -142,17 +232,9 @@
                     // value field?
                     private boolean cached = false;
 
-                    // If the field is a primitive type, set its default value to false
-                    // or zero. For non-primitives, null until we know better.
-
                     {
-                        Class javaType = classCache.forName(fieldTypeName);
-
-                        if (javaType.isPrimitive())
-                        {
-                            // Reminder: 0 coerces to false
-                            defaultValue = typeCoercer.coerce(0l, javaType);
-                        }
+                        // Inform the ComponentResources about the parameter conduit, so it can be
+                        // shared with mixins.
 
                         icr.setParameterConduit(parameterName, this);
                     }
@@ -170,6 +252,7 @@
 
                         if (!loaded)
                         {
+                            value = newValue;
                             defaultValue = newValue;
                             return;
                         }
@@ -182,10 +265,10 @@
 
                         // If caching is enabled for the parameter (the typical case) and the
                         // component is currently rendering, then the result
-                        // can be cached in the ParameterConduit (until the component finishes
+                        // can be cached in this ParameterConduit (until the component finishes
                         // rendering).
 
-                        cached = enableCaching && icr.isRendering();
+                        cached = annotation.cache() && icr.isRendering();
                     }
 
                     private Object readFromBinding()
@@ -200,10 +283,9 @@
                         }
                         catch (RuntimeException ex)
                         {
-                            throw new TapestryException(String
-                                    .format("Failure reading parameter '%s' of component %s: %s",
-                                            parameterName, icr.getCompleteId(), InternalUtils
-                                                    .toMessage(ex)), parameterBinding, ex);
+                            throw new TapestryException(String.format(
+                                    "Failure reading parameter '%s' of component %s: %s", parameterName, icr
+                                            .getCompleteId(), InternalUtils.toMessage(ex)), parameterBinding, ex);
                         }
 
                         if (result != null || annotation.allowNull())
@@ -213,8 +295,7 @@
                                 String
                                         .format(
                                                 "Parameter '%s' of component %s is bound to null. This parameter is not allowed to be null.",
-                                                parameterName, icr.getCompleteId()),
-                                parameterBinding, null);
+                                                parameterName, icr.getCompleteId()), parameterBinding, null);
                     }
 
                     @SuppressWarnings("unchecked")
@@ -228,17 +309,15 @@
 
                         try
                         {
-                            Object coerced = typeCoercer.coerce(newValue, parameterBinding
-                                    .getBindingType());
+                            Object coerced = typeCoercer.coerce(newValue, parameterBinding.getBindingType());
 
                             parameterBinding.set(coerced);
                         }
                         catch (RuntimeException ex)
                         {
-                            throw new TapestryException(String
-                                    .format("Failure writing parameter '%s' of component %s: %s",
-                                            parameterName, icr.getCompleteId(), InternalUtils
-                                                    .toMessage(ex)), icr, ex);
+                            throw new TapestryException(String.format(
+                                    "Failure writing parameter '%s' of component %s: %s", parameterName, icr
+                                            .getCompleteId(), InternalUtils.toMessage(ex)), icr, ex);
                         }
                     }
 
@@ -253,16 +332,24 @@
 
                     public void load()
                     {
+                        logger.debug(String.format("%s loading parameter %s", icr.getCompleteId(), parameterName));
+
                         // If it's bound at this point, that's because of an explicit binding
                         // in the template or @Component annotation.
 
                         if (!icr.isBound(parameterName))
                         {
+                            logger.debug(String.format("%s parameter %s not yet bound", icr.getCompleteId(),
+                                    parameterName));
+
                             // Otherwise, construct a default binding, or use one provided from
                             // the component.
 
                             Binding binding = getDefaultBindingForParameter();
 
+                            logger.debug(String.format("%s parameter %s bound to default %s", icr.getCompleteId(),
+                                    parameterName, binding));
+
                             if (binding != null)
                                 icr.bindParameter(parameterName, binding);
                         }
@@ -276,22 +363,6 @@
                         value = defaultValue;
                     }
 
-                    private Binding getDefaultBindingForParameter()
-                    {
-                        if (InternalUtils.isNonBlank(annotation.value()))
-                            return bindingSource.newBinding("default " + parameterName, icr,
-                                    annotation.defaultPrefix(), annotation.value());
-
-                        if (annotation.autoconnect())
-                            return defaultProvider.defaultBinding(parameterName, icr);
-
-                        // Return (if not null) the binding from the setDefault() method which is
-                        // set via a default method on the component, or from the field's initial
-                        // value.
-
-                        return parameterBinding;
-                    }
-
                     public boolean isBound()
                     {
                         return parameterBinding != null;
@@ -313,7 +384,7 @@
                         // we may want to cache it for the remainder of the component render (if the
                         // component is currently rendering).
 
-                        if (invariant || (enableCaching && icr.isRendering()))
+                        if (invariant || (annotation.cache() && icr.isRendering()))
                         {
                             value = result;
                             cached = true;
@@ -322,6 +393,22 @@
                         return result;
                     }
 
+                    private Binding getDefaultBindingForParameter()
+                    {
+                        if (InternalUtils.isNonBlank(annotation.value()))
+                            return bindingSource.newBinding("default " + parameterName, icr,
+                                    annotation.defaultPrefix(), annotation.value());
+
+                        if (annotation.autoconnect())
+                            return defaultProvider.defaultBinding(parameterName, icr);
+
+                        // Return (if not null) the binding from the setDefault() method which is
+                        // set via a default method on the component, or from the field's initial
+                        // value.
+
+                        return parameterBinding;
+                    }
+
                     public void setDefault(Object value)
                     {
                         if (value == null)
@@ -333,59 +420,58 @@
                             return;
                         }
 
-                        parameterBinding = new LiteralBinding(null, "default " + parameterName,
-                                value);
+                        parameterBinding = new LiteralBinding(null, "default " + parameterName, value);
                     }
                 };
             }
-
         };
+    }
 
-        // This has to be done in the constructor, to handle any field initializations
-
-        TransformField conduitField = transformation.addIndirectInjectedField(
-                ParameterConduit.class, parameterName + "$conduit", provider);
-
-        String conduitFieldName = conduitField.getName();
-
-        addCodeForParameterDefaultMethod(transformation, parameterName, conduitFieldName);
-
-        transformation.getField(fieldName).replaceAccess(conduitField);
-
-        transformation.extendMethod(TransformConstants.CONTAINING_PAGE_DID_LOAD_SIGNATURE, String
-                .format("%s.load();", conduitFieldName));
-
-        transformation.extendMethod(TransformConstants.POST_RENDER_CLEANUP_SIGNATURE, String
-                .format("%s.reset();", conduitFieldName));
-
+    private ParameterConduit getConduit(ComponentMethodInvocation invocation, FieldAccess access)
+    {
+        return (ParameterConduit) access.read(invocation.getInstance());
     }
 
-    private void addCodeForParameterDefaultMethod(ClassTransformation transformation,
-            final String parameterName, String conduitFieldName)
+    private void addCodeForParameterDefaultMethod(ClassTransformation transformation, final String parameterName,
+            final FieldAccess conduitAccess)
     {
         final String methodName = "default" + parameterName;
 
-        MethodFilter filter = new MethodFilter()
+        Predicate<TransformMethod> predicate = new Predicate<TransformMethod>()
         {
-            public boolean accept(TransformMethodSignature signature)
+            public boolean accept(TransformMethod method)
             {
-                return signature.getParameterTypes().length == 0
-                        && signature.getMethodName().equalsIgnoreCase(methodName);
+                return method.getSignature().getParameterTypes().length == 0
+                        && method.getName().equalsIgnoreCase(methodName);
             }
         };
 
-        // This will match exactly 0 or 1 methods, and if it matches, we know the name
-        // of the method.
+        List<TransformMethod> matches = transformation.matchMethods(predicate);
 
-        List<TransformMethodSignature> signatures = transformation.findMethods(filter);
+        // This will match exactly 0 or 1 (unless the user does something really silly)
+        // methods, and if it matches, we know the name of the method.
 
-        if (signatures.isEmpty())
+        if (matches.isEmpty())
             return;
 
-        String actualMethodName = signatures.get(0).getMethodName();
+        TransformMethod defaultMethod = matches.get(0);
 
-        transformation.extendExistingMethod(TransformConstants.CONTAINING_PAGE_DID_LOAD_SIGNATURE,
-                String.format("%s.setDefault(($w) %s());", conduitFieldName, actualMethodName));
+        captureDefaultValueFromDefaultMethod(transformation, defaultMethod, conduitAccess);
+    }
+
+    private void captureDefaultValueFromDefaultMethod(ClassTransformation transformation,
+            TransformMethod defaultMethod, final FieldAccess conduitAccess)
+    {
+        final MethodAccess access = defaultMethod.getAccess();
+
+        ComponentMethodAdvice advice = new InvokeParameterDefaultMethod(conduitAccess, access);
+
+        addPageLoadAdvice(transformation, advice);
+    }
+
+    private void addPageLoadAdvice(ClassTransformation transformation, ComponentMethodAdvice advice)
+    {
+        addMethodAdvice(transformation, TransformConstants.CONTAINING_PAGE_DID_LOAD_SIGNATURE, advice);
     }
 
     private static String getParameterName(String fieldName, String annotatedName)

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/transform/PersistWorker.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/transform/PersistWorker.java?rev=911931&r1=911930&r2=911931&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/transform/PersistWorker.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/transform/PersistWorker.java Fri Feb 19 18:54:27 2010
@@ -136,8 +136,6 @@
     @SuppressWarnings("unchecked")
     private Object determineDefaultValueFromFieldType(TransformField field)
     {
-        Class javaType = classCache.forName(field.getType());
-
-        return javaType.isPrimitive() ? typeCoercer.coerce(0, javaType) : null;
+        return classCache.defaultValueForType(field.getType());
     }
 }

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/transform/PropertyWorker.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/transform/PropertyWorker.java?rev=911931&r1=911930&r2=911931&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/transform/PropertyWorker.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/transform/PropertyWorker.java Fri Feb 19 18:54:27 2010
@@ -63,9 +63,11 @@
                 new String[]
                 { field.getType() }, null);
 
+        ensureNotOverride(transformation, setter);
+
         final FieldAccess access = field.getAccess();
 
-        transformation.createMethod(setter).addAdvice(new ComponentMethodAdvice()
+        transformation.getOrCreateMethod(setter).addAdvice(new ComponentMethodAdvice()
         {
             public void advise(ComponentMethodInvocation invocation)
             {
@@ -74,14 +76,24 @@
         });
     }
 
+    private void ensureNotOverride(ClassTransformation transformation, TransformMethodSignature signature)
+    {
+        if (transformation.isDeclaredMethod(signature))
+            throw new RuntimeException(String.format(
+                    "Unable to create new method %s as it already exists in class %s.", signature, transformation
+                            .getClassName()));
+    }
+
     private void addGetter(ClassTransformation transformation, TransformField field, String propertyName)
     {
         TransformMethodSignature getter = new TransformMethodSignature(Modifier.PUBLIC, field.getType(), "get"
                 + propertyName, null, null);
 
+        ensureNotOverride(transformation, getter);
+
         final FieldAccess access = field.getAccess();
 
-        transformation.createMethod(getter).addAdvice(new ComponentMethodAdvice()
+        transformation.getOrCreateMethod(getter).addAdvice(new ComponentMethodAdvice()
         {
             public void advise(ComponentMethodInvocation invocation)
             {

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/transform/RenderCommandWorker.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/transform/RenderCommandWorker.java?rev=911931&r1=911930&r2=911931&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/transform/RenderCommandWorker.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/transform/RenderCommandWorker.java Fri Feb 19 18:54:27 2010
@@ -58,6 +58,6 @@
 
         transformation.addImplementedInterface(RenderCommand.class);
 
-        transformation.getMethod(RENDER_SIGNATURE).addAdvice(advice);
+        transformation.getOrCreateMethod(RENDER_SIGNATURE).addAdvice(advice);
     }
 }

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=911931&r1=911930&r2=911931&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 Fri Feb 19 18:54:27 2010
@@ -15,7 +15,7 @@
 package org.apache.tapestry5.internal.transform;
 
 import java.lang.annotation.Annotation;
-import java.util.Iterator;
+import java.util.Collections;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -30,15 +30,19 @@
 import org.apache.tapestry5.annotations.BeginRender;
 import org.apache.tapestry5.annotations.CleanupRender;
 import org.apache.tapestry5.annotations.SetupRender;
-import org.apache.tapestry5.internal.util.MethodInvocationBuilder;
+import org.apache.tapestry5.ioc.Predicate;
 import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
 import org.apache.tapestry5.ioc.internal.util.InternalUtils;
-import org.apache.tapestry5.ioc.util.BodyBuilder;
 import org.apache.tapestry5.model.MutableComponentModel;
+import org.apache.tapestry5.runtime.Event;
 import org.apache.tapestry5.services.ClassTransformation;
 import org.apache.tapestry5.services.ComponentClassTransformWorker;
-import org.apache.tapestry5.services.MethodFilter;
+import org.apache.tapestry5.services.ComponentMethodAdvice;
+import org.apache.tapestry5.services.ComponentMethodInvocation;
+import org.apache.tapestry5.services.MethodAccess;
+import org.apache.tapestry5.services.MethodInvocationResult;
 import org.apache.tapestry5.services.TransformConstants;
+import org.apache.tapestry5.services.TransformMethod;
 import org.apache.tapestry5.services.TransformMethodSignature;
 
 /**
@@ -50,33 +54,92 @@
 @SuppressWarnings("unchecked")
 public class RenderPhaseMethodWorker implements ComponentClassTransformWorker
 {
-    private static final String CHECK_ABORT_FLAG = "if ($2.isAborted()) return;";
+    private final class RenderPhaseMethodAdvice implements ComponentMethodAdvice
+    {
+        private final boolean reverse;
+
+        private final List<Invoker> invokers;
+
+        private RenderPhaseMethodAdvice(boolean reverse, List<Invoker> invokers)
+        {
+            this.reverse = reverse;
+            this.invokers = invokers;
+        }
+
+        public void advise(ComponentMethodInvocation invocation)
+        {
+            if (!reverse)
+                invocation.proceed();
+
+            // All render phase methods take the same two parameters (writer and event)
+
+            Event event = (Event) invocation.getParameter(1);
+
+            if (event.isAborted())
+                return;
+
+            Object instance = invocation.getInstance();
+            MarkupWriter writer = (MarkupWriter) invocation.getParameter(0);
+
+            for (Invoker invoker : invokers)
+            {
+                invoker.invoke(instance, writer, event);
+
+                if (event.isAborted())
+                    return;
+            }
+
+            // Parent class implementation goes last.
+
+            if (reverse)
+                invocation.proceed();
+        }
+    }
 
-    private final MethodInvocationBuilder invocationBuilder = new MethodInvocationBuilder();
+    private class Invoker
+    {
+        private final String methodIdentifier;
+
+        private final MethodAccess access;
+
+        Invoker(String methodIdentifier, MethodAccess access)
+        {
+            this.methodIdentifier = methodIdentifier;
+            this.access = access;
+        }
+
+        void invoke(Object instance, MarkupWriter writer, Event event)
+        {
+            event.setMethodDescription(methodIdentifier);
+
+            // As currently implemented, MethodAccess objects ignore excess parameters.
+
+            MethodInvocationResult result = access.invoke(instance, writer);
+
+            result.rethrow();
+
+            event.storeResult(result.getReturnValue());
+        }
+
+    }
 
     private final Map<Class<? extends Annotation>, TransformMethodSignature> annotationToSignature = CollectionFactory
             .newMap();
 
-    private final Map<String, Class<? extends Annotation>> nameToAnnotation = CollectionFactory
-            .newCaseInsensitiveMap();
+    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<Class<? extends Annotation>> reverseAnnotations = CollectionFactory.newSet(AfterRenderBody.class,
+            AfterRenderTemplate.class, AfterRender.class, CleanupRender.class);
 
     private final Set<TransformMethodSignature> lifecycleMethods = CollectionFactory.newSet();
 
     {
         annotationToSignature.put(SetupRender.class, TransformConstants.SETUP_RENDER_SIGNATURE);
         annotationToSignature.put(BeginRender.class, TransformConstants.BEGIN_RENDER_SIGNATURE);
-        annotationToSignature.put(BeforeRenderTemplate.class,
-                TransformConstants.BEFORE_RENDER_TEMPLATE_SIGNATURE);
-        annotationToSignature.put(BeforeRenderBody.class,
-                TransformConstants.BEFORE_RENDER_BODY_SIGNATURE);
-        annotationToSignature.put(AfterRenderBody.class,
-                TransformConstants.AFTER_RENDER_BODY_SIGNATURE);
-        annotationToSignature.put(AfterRenderTemplate.class,
-                TransformConstants.AFTER_RENDER_TEMPLATE_SIGNATURE);
+        annotationToSignature.put(BeforeRenderTemplate.class, TransformConstants.BEFORE_RENDER_TEMPLATE_SIGNATURE);
+        annotationToSignature.put(BeforeRenderBody.class, TransformConstants.BEFORE_RENDER_BODY_SIGNATURE);
+        annotationToSignature.put(AfterRenderBody.class, TransformConstants.AFTER_RENDER_BODY_SIGNATURE);
+        annotationToSignature.put(AfterRenderTemplate.class, TransformConstants.AFTER_RENDER_TEMPLATE_SIGNATURE);
         annotationToSignature.put(AfterRender.class, TransformConstants.AFTER_RENDER_SIGNATURE);
         annotationToSignature.put(CleanupRender.class, TransformConstants.CLEANUP_RENDER_SIGNATURE);
 
@@ -85,145 +148,128 @@
             nameToAnnotation.put(me.getValue().getMethodName(), me.getKey());
             lifecycleMethods.add(me.getValue());
         }
-
-        // If we ever add more parameters to the methods, then we can add more to the invocation
-        // builder. *Never* expose the Event parameter ($2), it is for internal use only.
-
-        invocationBuilder.addParameter(MarkupWriter.class.getName(), "$1");
     }
 
-    public void transform(final ClassTransformation transformation, MutableComponentModel model)
+    public void transform(ClassTransformation transformation, MutableComponentModel model)
     {
-        Map<Class, List<TransformMethodSignature>> methods = CollectionFactory.newMap();
-
-        MethodFilter filter = new MethodFilter()
-        {
-            public boolean accept(TransformMethodSignature signature)
-            {
-                return !transformation.isMethodOverride(signature)
-                        && !lifecycleMethods.contains(signature);
-            }
-        };
+        Map<Class, List<TransformMethod>> methods = mapRenderPhaseAnnotationToMethods(transformation);
 
-        for (TransformMethodSignature sig : transformation.findMethods(filter))
+        for (Class renderPhaseAnnotation : methods.keySet())
         {
-            Class categorized = null;
+            mapMethodsToRenderPhase(transformation, model, renderPhaseAnnotation, methods.get(renderPhaseAnnotation));
+        }
+    }
 
-            for (Class annotationClass : annotationToSignature.keySet())
-            {
-                if (transformation.getMethodAnnotation(sig, annotationClass) != null)
-                {
-                    categorized = annotationClass;
-                    break;
-                }
-            }
+    private void mapMethodsToRenderPhase(ClassTransformation transformation, MutableComponentModel model,
+            Class annotationType, List<TransformMethod> methods)
+    {
+        ComponentMethodAdvice renderPhaseAdvice = createAdviceForMethods(annotationType, methods);
 
-            // If no annotation, see if the method name maps to an annotation class
-            // and use that. Thus explicit annotations always override method name matching
-            // as per TAP5-266
+        TransformMethodSignature renderPhaseSignature = annotationToSignature.get(annotationType);
 
-            if (categorized == null)
-                categorized = nameToAnnotation.get(sig.getMethodName());
+        transformation.getOrCreateMethod(renderPhaseSignature).addAdvice(renderPhaseAdvice);
 
-            if (categorized != null)
-            {
-                InternalUtils.addToMapList(methods, categorized, sig);
-            }
-        }
-
-        if (methods.isEmpty())
-            return;
+        model.addRenderPhase(annotationType);
+    }
 
-        for (Map.Entry<Class, List<TransformMethodSignature>> me : methods.entrySet())
-        {
-            Class annotationClass = me.getKey();
+    private ComponentMethodAdvice createAdviceForMethods(Class annotationType, List<TransformMethod> methods)
+    {
+        boolean reverse = reverseAnnotations.contains(annotationType);
 
-            model.addRenderPhase(annotationClass);
+        List<Invoker> invokers = toInvokers(annotationType, methods, reverse);
 
-            linkMethodsToRenderPhase(transformation, model, annotationToSignature
-                    .get(annotationClass), reverseAnnotations.contains(annotationClass), me
-                    .getValue());
-        }
+        return new RenderPhaseMethodAdvice(reverse, invokers);
     }
 
-    public void linkMethodsToRenderPhase(ClassTransformation transformation,
-            MutableComponentModel model, TransformMethodSignature lifecycleMethodSignature,
-            boolean reverse, List<TransformMethodSignature> methods)
+    private List<Invoker> toInvokers(Class annotationType, List<TransformMethod> methods, boolean reverse)
     {
-        String lifecycleMethodName = lifecycleMethodSignature.getMethodName();
+        List<Invoker> result = CollectionFactory.newList();
 
-        BodyBuilder builder = new BodyBuilder();
-        builder.begin();
+        for (TransformMethod method : methods)
+        {
+            MethodAccess methodAccess = toMethodAccess(method);
 
-        // If in a subclass, and in normal order mode, invoke the super class version first.
+            Invoker invoker = new Invoker(method.getMethodIdentifier(), methodAccess);
 
-        if (!(reverse || model.isRootClass()))
-        {
-            builder.addln("super.%s($$);", lifecycleMethodName);
-            builder.addln(CHECK_ABORT_FLAG);
+            result.add(invoker);
         }
 
-        Iterator<TransformMethodSignature> i = reverse ? InternalUtils.reverseIterator(methods)
-                : methods.iterator();
+        if (reverse)
+            Collections.reverse(result);
 
-        builder.addln("try");
-        builder.begin();
+        return result;
+    }
 
-        while (i.hasNext())
-            addMethodCallToBody(builder, i.next(), transformation);
+    private MethodAccess toMethodAccess(TransformMethod method)
+    {
+        validateAsRenderPhaseMethod(method);
 
-        // In reverse order in a a subclass, invoke the super method last.
+        return method.getAccess();
+    }
 
-        if (reverse && !model.isRootClass())
-            builder.addln("super.%s($$);", lifecycleMethodName);
+    private void validateAsRenderPhaseMethod(TransformMethod method)
+    {
+        String[] parameterTypes = method.getSignature().getParameterTypes();
 
-        builder.end(); // try
+        switch (parameterTypes.length)
+        {
+            case 0:
+                break;
 
-        // Let runtime exceptions work up (they'll be caught at a higher level.
-        // Wrap checked exceptions for later reporting.
+            case 1:
+                if (parameterTypes[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.getMethodIdentifier()));
+        }
+    }
 
-        builder.addln("catch (RuntimeException ex) { throw ex; }");
-        builder.addln("catch (Exception ex) { throw new RuntimeException(ex); }");
+    private Map<Class, List<TransformMethod>> mapRenderPhaseAnnotationToMethods(final ClassTransformation transformation)
+    {
+        Map<Class, List<TransformMethod>> map = CollectionFactory.newMap();
 
-        builder.end();
+        List<TransformMethod> matches = matchAllMethodsNotOverriddenFromBaseClass(transformation);
 
-        // Let's see if this works; for base classes, we are adding an empty method then adding a
-        // non-empty method "on top of it".
+        for (TransformMethod method : matches)
+        {
+            addMethodToRenderPhaseCategoryMap(map, method);
+        }
 
-        transformation.addMethod(lifecycleMethodSignature, builder.toString());
+        return map;
     }
 
-    private void addMethodCallToBody(BodyBuilder builder, TransformMethodSignature sig,
-            ClassTransformation transformation)
+    private void addMethodToRenderPhaseCategoryMap(Map<Class, List<TransformMethod>> map, TransformMethod method)
     {
-        boolean isVoid = sig.getReturnType().equals("void");
+        Class categorized = categorizeMethod(method);
 
-        builder.addln("$2.setMethodDescription(\"%s\");", transformation.getMethodIdentifier(sig));
+        if (categorized != null)
+            InternalUtils.addToMapList(map, categorized, method);
+    }
 
-        if (!isVoid)
+    private Class categorizeMethod(TransformMethod method)
+    {
+        for (Class annotationClass : annotationToSignature.keySet())
         {
-            // If we're not going to invoke storeResult(), then there's no reason to invoke
-            // setMethodDescription().
-
-            builder.add("if ($2.storeResult(($w) ");
+            if (method.getAnnotation(annotationClass) != null)
+                return annotationClass;
         }
 
-        // This is the best part; the method can even be private and this still works. It's a lot
-        // like how javac enables access to private members for inner classes (by introducing
-        // synthetic, static methods).
-
-        builder.add(invocationBuilder.buildMethodInvocation(sig, transformation));
-
-        // Now, if non void ...
+        return nameToAnnotation.get(method.getName());
+    }
 
-        if (!isVoid)
+    private List<TransformMethod> matchAllMethodsNotOverriddenFromBaseClass(final ClassTransformation transformation)
+    {
+        return transformation.matchMethods(new Predicate<TransformMethod>()
         {
-            // Complete the call to storeResult(). If storeResult() returns true, then
-            // the event is aborted and no further processing is required.
+            public boolean accept(TransformMethod method)
+            {
+                return !method.isOverride() && !lifecycleMethods.contains(method.getSignature());
+            }
+        });
 
-            builder.addln(")) return;");
-        }
-        else
-            builder.addln(";");
     }
 }

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/transform/UnclaimedFieldWorker.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/transform/UnclaimedFieldWorker.java?rev=911931&r1=911930&r2=911931&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/transform/UnclaimedFieldWorker.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/transform/UnclaimedFieldWorker.java Fri Feb 19 18:54:27 2010
@@ -1,10 +1,10 @@
-// Copyright 2006, 2007 The Apache Software Foundation
+// Copyright 2006, 2007, 2010 The Apache Software Foundation
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
 // You may obtain a copy of the License at
 //
-//     http://www.apache.org/licenses/LICENSE-2.0
+// http://www.apache.org/licenses/LICENSE-2.0
 //
 // Unless required by applicable law or agreed to in writing, software
 // distributed under the License is distributed on an "AS IS" BASIS,
@@ -14,53 +14,107 @@
 
 package org.apache.tapestry5.internal.transform;
 
+import java.lang.reflect.Modifier;
+
+import org.apache.tapestry5.ComponentResources;
+import org.apache.tapestry5.internal.InternalComponentResources;
+import org.apache.tapestry5.internal.services.ComponentClassCache;
+import org.apache.tapestry5.ioc.services.FieldValueConduit;
 import org.apache.tapestry5.model.MutableComponentModel;
+import org.apache.tapestry5.runtime.PageLifecycleAdapter;
 import org.apache.tapestry5.services.ClassTransformation;
 import org.apache.tapestry5.services.ComponentClassTransformWorker;
-import static org.apache.tapestry5.services.TransformConstants.CONTAINING_PAGE_DID_DETACH_SIGNATURE;
-import static org.apache.tapestry5.services.TransformConstants.CONTAINING_PAGE_DID_LOAD_SIGNATURE;
-
-import java.lang.reflect.Modifier;
-import java.util.List;
+import org.apache.tapestry5.services.ComponentValueProvider;
+import org.apache.tapestry5.services.TransformField;
 
 /**
  * Designed to be just about the last worker in the pipeline. Its job is to add cleanup code that restores transient
- * fields back to their initial (null) value. Fields that have been previously {@link
- * org.apache.tapestry5.services.ClassTransformation#claimField(String, Object) claimed} are ignored, as are fields that
- * are final.
+ * fields back to their initial (null) value. Fields that have been previously {@linkplain TransformField#claim(Object)
+ * claimed} are ignored, as are fields that are final.
  */
 public final class UnclaimedFieldWorker implements ComponentClassTransformWorker
 {
+    private final ComponentClassCache classCache;
 
-    public void transform(ClassTransformation transformation, MutableComponentModel model)
+    public class UnclaimedFieldConduit implements FieldValueConduit
     {
-        List<String> fieldNames = transformation.findUnclaimedFields();
+        private final InternalComponentResources resources;
+
+        private Object fieldValue, fieldDefaultValue;
+
+        private UnclaimedFieldConduit(InternalComponentResources resources, Object fieldDefaultValue)
+        {
+            this.resources = resources;
 
-        for (String fieldName : fieldNames)
+            this.fieldValue = fieldDefaultValue;
+            this.fieldDefaultValue = fieldDefaultValue;
+
+            resources.addPageLifecycleListener(new PageLifecycleAdapter()
+            {
+                @Override
+                public void containingPageDidDetach()
+                {
+                    reset();
+                }
+            });
+        }
+
+        public Object get()
+        {
+            return fieldValue;
+        }
+
+        public void set(Object newValue)
         {
-            transformField(fieldName, transformation);
+            fieldValue = newValue;
+
+            if (!resources.isLoaded())
+                fieldDefaultValue = newValue;
+        }
+
+        public void reset()
+        {
+            fieldValue = fieldDefaultValue;
         }
     }
 
-    private void transformField(String fieldName, ClassTransformation transformation)
+    public UnclaimedFieldWorker(ComponentClassCache classCache)
     {
-        int modifiers = transformation.getFieldModifiers(fieldName);
+        this.classCache = classCache;
+    }
 
-        if (Modifier.isFinal(modifiers))
-            return;
+    public void transform(ClassTransformation transformation, MutableComponentModel model)
+    {
+        for (TransformField field : transformation.matchUnclaimedFields())
+        {
+            transformField(field);
+        }
+    }
 
-        String type = transformation.getFieldType(fieldName);
+    private void transformField(TransformField field)
+    {
+        int modifiers = field.getModifiers();
 
-        String defaultFieldName = transformation.addField(Modifier.PRIVATE, type, fieldName
-                + "_default");
+        if (Modifier.isFinal(modifiers) || Modifier.isStatic(modifiers))
+            return;
 
-        transformation.extendMethod(CONTAINING_PAGE_DID_LOAD_SIGNATURE, defaultFieldName + " = "
-                + fieldName + ";");
+        ComponentValueProvider<FieldValueConduit> provider = createFieldValueConduitProvider(field);
 
-        // At the end of the request, we want to move the default value back over the
-        // active field value. This will most often be null.
+        field.replaceAccess(provider);
+    }
 
-        transformation.extendMethod(CONTAINING_PAGE_DID_DETACH_SIGNATURE, fieldName + " = "
-                + defaultFieldName + ";");
+    private ComponentValueProvider<FieldValueConduit> createFieldValueConduitProvider(TransformField field)
+    {
+        final String fieldType = field.getType();
+
+        return new ComponentValueProvider<FieldValueConduit>()
+        {
+            public FieldValueConduit get(ComponentResources resources)
+            {
+                Object fieldDefaultValue = classCache.defaultValueForType(fieldType);
+
+                return new UnclaimedFieldConduit((InternalComponentResources) resources, fieldDefaultValue);
+            }
+        };
     }
 }

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/ClassTransformation.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/ClassTransformation.java?rev=911931&r1=911930&r2=911931&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/ClassTransformation.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/ClassTransformation.java Fri Feb 19 18:54:27 2010
@@ -20,12 +20,11 @@
 import javassist.CtBehavior;
 
 import org.apache.tapestry5.ComponentResources;
+import org.apache.tapestry5.internal.transform.ReadOnlyFieldValueConduit;
 import org.apache.tapestry5.ioc.AnnotationProvider;
 import org.apache.tapestry5.ioc.Predicate;
 import org.slf4j.Logger;
 
-import sun.awt.ComponentFactory;
-
 /**
  * Contains class-specific information used when transforming a raw component class into an
  * executable component class.
@@ -37,6 +36,8 @@
  * {@link ComponentClassTransformWorker}.
  * <p/>
  * Much of this information is somewhat like ordinary reflection, but applies to a class that has not yet been loaded.
+ * Field types, return types, parameter types and exception types are represented as string names, since any of them may
+ * be a class that has not yet been loaded and transformed as well.
  * <p/>
  * Transformation is primarily about identifying annotations on fields and on methods and changing the class, adding new
  * interfaces, fields and methods, and deleting some existing fields.
@@ -81,7 +82,7 @@
      * @param prefix
      *            for the generated name
      * @param baseName
-     *            an name, often of an existing field or method
+     *            a name, often of an existing field or method
      * @return a unique name
      */
     String newMemberName(String prefix, String baseName);
@@ -206,6 +207,7 @@
      * @return the annotation if present, or null otherwise
      * @throws IllegalArgumentException
      *             if the method signature does not correspond to a declared method
+     * @deprecated Use {@link TransformMethod#getAnnotation(Class)} instead
      */
     <T extends Annotation> T getMethodAnnotation(TransformMethodSignature method, Class<T> annotationClass);
 
@@ -228,6 +230,7 @@
      *             if the fieldName does not correspond to a declared instance field
      * @throws IllegalStateException
      *             if the field is already claimed for some other tag
+     * @deprecated Use {@link TransformField#claim(Object)} instead
      */
     void claimField(String fieldName, Object tag);
 
@@ -237,21 +240,25 @@
      * 
      * @param fieldName
      *            name of field to so change
+     * @deprecated Use {@link TransformField#replaceAccess(TransformField)} instead
+     * @see ReadOnlyFieldValueConduit
      */
     void makeReadOnly(String fieldName);
 
     /**
      * Finds any declared <em>instance</em> fields that have not been claimed (via {@link #claimField(String, Object)})
-     * and have not been either added or deleted, and returns the names of those fields. May return an empty array.
+     * and have not been added , and returns the names of those fields. May return an empty array.
      * 
      * @deprecated Use {@link #matchUnclaimedFields()} instead
      */
     List<String> findUnclaimedFields();
 
     /**
-     * Matches all fields that are not claimed (or added or removed).
+     * Matches all fields that are not claimed. This may include static fields and final fields, but will not
+     * include fields that have been added as part of the transformation.
      * 
      * @since 5.2.0
+     * @return sorted list of unclaimed fields
      */
     List<TransformField> matchUnclaimedFields();
 
@@ -339,7 +346,7 @@
      * @param provider
      *            injected into the component to provide the value
      * @return the actual name of the injected field
-     * @since 5.2
+     * @since 5.2.0
      */
     <T> TransformField addIndirectInjectedField(Class<T> type, String suggestedName, ComponentValueProvider<T> provider);
 
@@ -394,7 +401,7 @@
      *            the body of code
      * @throws org.apache.tapestry5.internal.services.MethodCompileException
      *             if the provided Javassist method body can not be compiled
-     * @deprecated Use {@link TransformMethod#extend(String)} instead
+     * @deprecated Use {@link TransformMethod#extend(String)} instead. This method is non-functional as of Tapestry 5.2.
      */
     void extendMethod(TransformMethodSignature methodSignature, String methodBody);
 
@@ -411,7 +418,7 @@
      * @throws org.apache.tapestry5.internal.services.MethodCompileException
      *             if the provided method body can not be compiled
      * @see #prefixMethod(TransformMethodSignature, String)
-     * @deprecated Use {@link TransformMethod#extend(String) instead}
+     * @deprecated Use {@link TransformMethod#extend(String) instead}. This method is non-functional as of Tapestry 5.2.
      */
     void extendExistingMethod(TransformMethodSignature methodSignature, String methodBody);
 
@@ -422,7 +429,6 @@
      * is added that first invokes the super implementation. Use {@link #addMethod(TransformMethodSignature, String)}
      * when it is necessary to control when the super-class method is invoked.
      * <p/>
-     * <p/>
      * Like {@link #extendExistingMethod(TransformMethodSignature, String)}, this method is generally used to "wrap" an
      * existing method adding additional functionality such as caching or transaction support.
      * 
@@ -430,6 +436,8 @@
      * @param methodBody
      * @throws org.apache.tapestry5.internal.services.MethodCompileException
      *             if the provided method body can not be compiled
+     * @deprecated Use {@link TransformMethod#addAdvice(ComponentMethodAdvice)} instead. This method is non-functional
+     *             as of Tapestry 5.2.
      */
     void prefixMethod(TransformMethodSignature methodSignature, String methodBody);
 
@@ -452,22 +460,17 @@
      * the super-class
      * implementation is invoked.
      * 
-     * @deprecated Use {@link #createMethod(TransformMethodSignature)} instead
+     * @deprecated Use {@link #getOrCreateMethod(TransformMethodSignature)} instead. This method is non-functional as of
+     *             Tapestry 5.2.
      */
     void addMethod(TransformMethodSignature signature, String methodBody);
 
     /**
-     * Creates a new method as a declared method of the class, with an empty (default) body that
-     * does nothing. Non-void methods will return null, false or 0. The method must not yet exist.
-     * 
-     * @param signature
-     *            defines the method to create
-     */
-    TransformMethod createMethod(TransformMethodSignature signature);
-
-    /**
      * As with {@link #addMethod(TransformMethodSignature, String)}, but field references inside the
      * method <em>will</em> be transformed, and the method <em>must not already exist</em>.
+     * 
+     * @deprecated Use {@link #getOrCreateMethod(TransformMethodSignature)} instead. This method is non-functional as of
+     *             Tapestry 5.2.
      */
     void addTransformedMethod(TransformMethodSignature methodSignature, String methodBody);
 
@@ -476,6 +479,8 @@
      * 
      * @param statement
      *            the statement to add, which should end with a semicolon
+     * @deprecated Use methods that create or inject fields (directly or indirectly)
+     * @see ComponentValueProvider
      */
     void extendConstructor(String statement);
 
@@ -508,7 +513,7 @@
      *            the name of the field to remove
      * @see #replaceReadAccess(String, String)
      * @see #replaceWriteAccess(String, String)
-     * @deprecated Use {@link TransformField#remove()} instead
+     * @deprecated This method is non-functional as of Tapestry 5.2
      */
     void removeField(String fieldName);
 
@@ -564,6 +569,8 @@
      *            fully qualified class name of exception
      * @param body
      *            code to execute
+     * @deprecated Use {@link TransformMethod#addAdvice(ComponentMethodAdvice)} instead. This method is non-functional
+     *             as of Tapestry 5.2.
      */
     void addCatch(TransformMethodSignature methodSignature, String exceptionType, String body);
 
@@ -585,16 +592,26 @@
     boolean isMethodOverride(TransformMethodSignature methodSignature);
 
     /**
-     * Locates and returns the method if declared in this class; if not, locates
-     * a super-class method that is implemented into this class. In the latter
-     * case, the method will be considered "new" (i.e., no field transformations),
-     * as with {@link #extendMethod(TransformMethodSignature, String)}).
+     * Locates and returns the method if declared in this class; If not,
+     * the method is added to the class. If the method is an override
+     * of a base class method, then the method will delegate to the base
+     * class method (invoke it, return its value). If the method is entirely
+     * new, it will ignore its parameters and return a default value (null, 0 or false).
      * 
      * @param signature
-     *            identifies the method to obtain
-     * @throw RuntimeException if the signature does not match a declared method of this
-     *        class, or a overridable method of a superclass
+     *            identifies the method to locate, override or create
      * @since 5.2.0
      */
-    TransformMethod getMethod(TransformMethodSignature signature);
+    TransformMethod getOrCreateMethod(TransformMethodSignature signature);
+
+    /**
+     * Determines if the class being transformed includes a declared (not inherited) method
+     * with the provided signature.
+     * 
+     * @since 5.2.0
+     * @param signature
+     *            identifies method to search for
+     * @return true if a such a method exists
+     */
+    boolean isDeclaredMethod(TransformMethodSignature signature);
 }

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=911931&r1=911930&r2=911931&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 Fri Feb 19 18:54:27 2010
@@ -607,7 +607,7 @@
         // annotated will
         // be converted to clear out at the end of the request.
 
-        configuration.add("UnclaimedField", new UnclaimedFieldWorker(), "after:*");
+        configuration.addInstance("UnclaimedField",  UnclaimedFieldWorker.class, "after:*");
 
         configuration.add("PageActivationContext", new PageActivationContextWorker(), "before:OnEvent");
 

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TransformField.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TransformField.java?rev=911931&r1=911930&r2=911931&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TransformField.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TransformField.java Fri Feb 19 18:54:27 2010
@@ -83,35 +83,6 @@
      */
     void replaceAccess(FieldValueConduit conduit);
 
-    /**
-     * Extends the indicated method to add an assignment of the field with
-     * the value obtained by the provider. This is used when a value
-     * to be provided can not be provided from within the transformed class'
-     * constructor.
-     * 
-     * @param <T>
-     * @param method
-     *            identifies the method where the assignment will occur, often this is
-     *            {@link TransformConstants#CONTAINING_PAGE_DID_LOAD_SIGNATURE}
-     * @param provider
-     *            provides the value of the field
-     */
-    <T> void assignIndirect(TransformMethod method, ComponentValueProvider<T> provider);
-
-    /**
-     * Alternate version of {@link #assignIndirect(TransformMethod, ComponentValueProvider)} that operates using a
-     * method signature.
-     */
-    <T> void assignIndirect(TransformMethodSignature signature, ComponentValueProvider<T> provider);
-
-    /**
-     * Marks the field for removal (at the end of the class transformation). Often, a field is deleted
-     * after access to the field is {@linkplain #replaceAccess(ComponentValueProvider) replaced}.
-     * 
-     * @throws IllegalStateException
-     *             if the field has already been marked for deletion
-     */
-    void remove();
 
     /** Returns the modifiers for the field. */
     int getModifiers();

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TransformMethod.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TransformMethod.java?rev=911931&r1=911930&r2=911931&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TransformMethod.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TransformMethod.java Fri Feb 19 18:54:27 2010
@@ -36,28 +36,6 @@
     String getName();
 
     /**
-     * Extends an existing method. The provided method body is inserted at the end of the existing
-     * method (i.e. {@link javassist.CtBehavior#insertAfter(java.lang.String)}). To access or change
-     * the return value, use the <code>$_</code> pseudo variable.
-     * <p/>
-     * The method may be declared in the class, or may be inherited from a super-class. For inherited methods, a method
-     * body is added that first invokes the super implementation.
-     * <p/>
-     * The extended method is considered <em>new</em>. New methods <em>are not</em> scanned for removed fields, field
-     * access changes, etc.
-     * <p>
-     * This method will eventually be removed, using {@link #addAdvice(ComponentMethodAdvice)} or some other alternative
-     * is preferred.
-     * 
-     * @param body
-     *            the body of Javassist psuedo-code
-     * @throws RuntimeException
-     *             if the provided Javassist method body can not be compiled
-     * @deprecated Use {@link #addAdvice(ComponentMethodAdvice)} instead
-     */
-    void extend(String body);
-
-    /**
      * Returns an object that can be used to invoke the method on an instance of the component class (regardless
      * of the actual visibility of the method).
      */

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/test/TapestryTestCase.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/test/TapestryTestCase.java?rev=911931&r1=911930&r2=911931&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/test/TapestryTestCase.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/test/TapestryTestCase.java Fri Feb 19 18:54:27 2010
@@ -4,7 +4,7 @@
 // you may not use this file except in compliance with the License.
 // You may obtain a copy of the License at
 //
-//     http://www.apache.org/licenses/LICENSE-2.0
+// http://www.apache.org/licenses/LICENSE-2.0
 //
 // Unless required by applicable law or agreed to in writing, software
 // distributed under the License is distributed on an "AS IS" BASIS,
@@ -353,7 +353,8 @@
 
             long newModified = f.lastModified();
 
-            if (newModified != startModified) return;
+            if (newModified != startModified)
+                return;
 
             // Sleep 1/20 second and try again
 
@@ -362,25 +363,19 @@
     }
 
     protected final void train_addField(ClassTransformation transformation, int modifiers, String type,
-                                        String suggestedName, String actualName)
+            String suggestedName, String actualName)
     {
         expect(transformation.addField(modifiers, type, suggestedName)).andReturn(actualName);
     }
 
     protected final void train_addInjectedField(ClassTransformation ct, Class type, String suggestedName, Object value,
-                                                String fieldName)
+            String fieldName)
     {
         expect(ct.addInjectedField(type, suggestedName, value)).andReturn(fieldName);
     }
 
-    protected final void train_addMethod(ClassTransformation transformation, TransformMethodSignature signature,
-                                         String... body)
-    {
-        transformation.addMethod(eq(signature), codeEq(join(body)));
-    }
-
     protected final void train_buildConstraints(ValidationConstraintGenerator generator, Class propertyType,
-                                                AnnotationProvider provider, String... constraints)
+            AnnotationProvider provider, String... constraints)
     {
         expect(generator.buildConstraints(propertyType, provider)).andReturn(Arrays.asList(constraints));
     }
@@ -396,11 +391,10 @@
     }
 
     protected final void train_createValidator(FieldValidatorSource source, Field field, String validatorType,
-                                               String constraintValue, String overrideId, Messages overrideMessages,
-                                               Locale locale, FieldValidator result)
+            String constraintValue, String overrideId, Messages overrideMessages, Locale locale, FieldValidator result)
     {
-        expect(source.createValidator(field, validatorType, constraintValue, overrideId, overrideMessages,
-                                      locale)).andReturn(result);
+        expect(source.createValidator(field, validatorType, constraintValue, overrideId, overrideMessages, locale))
+                .andReturn(result);
     }
 
     protected final void train_encodeRedirectURL(Response response, String URI, String encoded)
@@ -414,43 +408,30 @@
     }
 
     protected final <T> void train_exists(ApplicationStatePersistenceStrategy strategy, Class<T> asoClass,
-                                          boolean exists)
+            boolean exists)
     {
         expect(strategy.exists(asoClass)).andReturn(exists);
     }
 
-    protected final void train_extendConstructor(ClassTransformation transformation, String... body)
-    {
-        transformation.extendConstructor(codeEq(join(body)));
-    }
-
-    protected final void train_extendMethod(ClassTransformation transformation, TransformMethodSignature signature,
-                                            String... body)
-    {
-        transformation.extendMethod(eq(signature), codeEq(join(body)));
-    }
-
     protected final void train_getAsset(AssetSource source, Resource root, String path, Locale locale, Asset asset)
     {
         expect(source.getAsset(root, path, locale)).andReturn(asset);
     }
 
     protected final void train_findFieldsWithAnnotation(ClassTransformation transformation,
-                                                        Class<? extends Annotation> annotationClass,
-                                                        List<String> fieldNames)
+            Class<? extends Annotation> annotationClass, List<String> fieldNames)
     {
         expect(transformation.findFieldsWithAnnotation(annotationClass)).andReturn(fieldNames);
     }
 
     protected final void train_findFieldsWithAnnotation(ClassTransformation transformation,
-                                                        Class<? extends Annotation> annotationClass,
-                                                        String... fieldNames)
+            Class<? extends Annotation> annotationClass, String... fieldNames)
     {
         train_findFieldsWithAnnotation(transformation, annotationClass, Arrays.asList(fieldNames));
     }
 
     protected final void train_findMethods(ClassTransformation transformation,
-                                           final TransformMethodSignature... signatures)
+            final TransformMethodSignature... signatures)
     {
         IAnswer<List<TransformMethodSignature>> answer = new IAnswer<List<TransformMethodSignature>>()
         {
@@ -464,7 +445,8 @@
 
                 for (TransformMethodSignature sig : signatures)
                 {
-                    if (filter.accept(sig)) result.add(sig);
+                    if (filter.accept(sig))
+                        result.add(sig);
                 }
 
                 // We don't have to sort them for testing purposes. Usually there's just going to be
@@ -478,8 +460,7 @@
     }
 
     protected final void train_findMethodsWithAnnotation(ClassTransformation tf,
-                                                         Class<? extends Annotation> annotationType,
-                                                         List<TransformMethodSignature> sigs)
+            Class<? extends Annotation> annotationType, List<TransformMethodSignature> sigs)
     {
         expect(tf.findMethodsWithAnnotation(annotationType)).andReturn(sigs);
     }
@@ -495,13 +476,13 @@
     }
 
     protected final <T> void train_get(ApplicationStatePersistenceStrategy strategy, Class<T> asoClass,
-                                       ApplicationStateCreator<T> creator, T aso)
+            ApplicationStateCreator<T> creator, T aso)
     {
         expect(strategy.get(asoClass, creator)).andReturn(aso);
     }
 
     protected final void train_get(ApplicationStatePersistenceStrategySource source, String strategyName,
-                                   ApplicationStatePersistenceStrategy strategy)
+            ApplicationStatePersistenceStrategy strategy)
     {
         expect(source.get(strategyName)).andReturn(strategy).atLeastOnce();
     }
@@ -586,8 +567,7 @@
         expect(resources.getContainerMessages()).andReturn(containerMessages).atLeastOnce();
     }
 
-    protected final void train_getContainerResources(ComponentResources resources,
-                                                     ComponentResources containerResources)
+    protected final void train_getContainerResources(ComponentResources resources, ComponentResources containerResources)
     {
         expect(resources.getContainerResources()).andReturn(containerResources).atLeastOnce();
     }
@@ -598,8 +578,7 @@
     }
 
     protected final <T extends Annotation> void train_getFieldAnnotation(ClassTransformation transformation,
-                                                                         String fieldName, Class<T> annotationClass,
-                                                                         T annotation)
+            String fieldName, Class<T> annotationClass, T annotation)
     {
         expect(transformation.getFieldAnnotation(fieldName, annotationClass)).andReturn(annotation);
     }
@@ -650,15 +629,13 @@
     }
 
     protected final <T extends Annotation> void train_getMethodAnnotation(ClassTransformation ct,
-                                                                          TransformMethodSignature signature,
-                                                                          Class<T> annotationClass, T annotation)
+            TransformMethodSignature signature, Class<T> annotationClass, T annotation)
     {
-        expect(ct.getMethodAnnotation(signature, annotationClass)).andReturn(annotation)
-                .atLeastOnce();
+        expect(ct.getMethodAnnotation(signature, annotationClass)).andReturn(annotation).atLeastOnce();
     }
 
     protected final void train_getMethodIdentifier(ClassTransformation transformation,
-                                                   TransformMethodSignature signature, String id)
+            TransformMethodSignature signature, String id)
     {
         expect(transformation.getMethodIdentifier(signature)).andReturn(id);
     }
@@ -681,7 +658,7 @@
     }
 
     protected final void train_getParameterModel(ComponentModel model, String parameterName,
-                                                 ParameterModel parameterModel)
+            ParameterModel parameterModel)
     {
         expect(model.getParameterModel(parameterName)).andReturn(parameterModel).atLeastOnce();
     }
@@ -732,7 +709,7 @@
     }
 
     protected final void train_getValidationMessages(ValidationMessagesSource messagesSource, Locale locale,
-                                                     Messages messages)
+            Messages messages)
     {
         expect(messagesSource.getValidationMessages(locale)).andReturn(messages).atLeastOnce();
     }
@@ -743,8 +720,7 @@
     }
 
     @SuppressWarnings("unchecked")
-    protected final void train_handleResult(ComponentEventCallback handler, Object result,
-                                            boolean abort)
+    protected final void train_handleResult(ComponentEventCallback handler, Object result, boolean abort)
     {
         expect(handler.handleResult(result)).andReturn(abort);
     }
@@ -780,14 +756,13 @@
     }
 
     protected final void train_newBinding(BindingFactory factory, String description, ComponentResources container,
-                                          ComponentResources component, String expression, Location l, Binding binding)
+            ComponentResources component, String expression, Location l, Binding binding)
     {
         expect(factory.newBinding(description, container, component, expression, l)).andReturn(binding);
     }
 
     protected void train_newBinding(BindingSource bindingSource, String description,
-                                    ComponentResources componentResources, String defaultBindingPrefix,
-                                    String expression, Binding binding)
+            ComponentResources componentResources, String defaultBindingPrefix, String expression, Binding binding)
     {
         expect(bindingSource.newBinding(description, componentResources, defaultBindingPrefix, expression)).andReturn(
                 binding);
@@ -799,7 +774,7 @@
     }
 
     protected final void train_newMemberName(ClassTransformation transformation, String prefix, String baseName,
-                                             String name)
+            String name)
     {
         expect(transformation.newMemberName(prefix, baseName)).andReturn(name);
     }
@@ -815,16 +790,14 @@
     }
 
     protected final void train_provideInjection(InjectionProvider provider, String fieldName, Class fieldType,
-                                                ObjectLocator locator, ClassTransformation transformation,
-                                                MutableComponentModel model, boolean result)
+            ObjectLocator locator, ClassTransformation transformation, MutableComponentModel model, boolean result)
     {
-        expect(provider.provideInjection(fieldName, fieldType, locator, transformation, model))
-                .andReturn(result);
+        expect(provider.provideInjection(fieldName, fieldType, locator, transformation, model)).andReturn(result);
     }
 
     @SuppressWarnings("unchecked")
     protected final void train_renderInformalParameters(ComponentResources resources, final MarkupWriter writer,
-                                                        final Object... informals)
+            final Object... informals)
     {
         resources.renderInformalParameters(writer);
         IAnswer answer = new IAnswer()
@@ -902,7 +875,7 @@
     }
 
     protected final void train_create(BeanModelSource source, Class beanClass, boolean filterReadOnly,
-                                      Messages messages, BeanModel model)
+            Messages messages, BeanModel model)
     {
         expect(source.create(beanClass, filterReadOnly, messages)).andReturn(model);
     }
@@ -955,8 +928,9 @@
     /**
      * Provides access to component messages, suitable for testing. Reads the associated .properties file for the class
      * (NOT any localization of it). Only the messages directly in the .properties file is available.
-     *
-     * @param componentClass component class whose messages are needed *
+     * 
+     * @param componentClass
+     *            component class whose messages are needed *
      * @return the Messages instance
      */
     protected final Messages messagesFor(Class componentClass) throws IOException
@@ -971,8 +945,9 @@
         {
             is = componentClass.getResourceAsStream(file);
 
-            if (is == null) throw new RuntimeException(
-                    String.format("Class %s does not have a message catalog.", componentClass.getName()));
+            if (is == null)
+                throw new RuntimeException(String.format("Class %s does not have a message catalog.", componentClass
+                        .getName()));
 
             properties.load(is);
         }
@@ -1035,7 +1010,7 @@
     }
 
     protected final void train_service(HttpServletRequestHandler handler, HttpServletRequest request,
-                                       HttpServletResponse response, boolean result) throws IOException
+            HttpServletResponse response, boolean result) throws IOException
     {
         expect(handler.service(request, response)).andReturn(result);
     }
@@ -1080,8 +1055,8 @@
         expect(valueEncoder.toValue(clientValue)).andReturn(value);
     }
 
-    protected <T> void train_findMeta(MetaDataLocator locator, String key,
-                                      ComponentResources resources, Class<T> expectedType, T value)
+    protected <T> void train_findMeta(MetaDataLocator locator, String key, ComponentResources resources,
+            Class<T> expectedType, T value)
     {
         expect(locator.findMeta(key, resources, expectedType)).andReturn(value).atLeastOnce();
     }
@@ -1156,7 +1131,6 @@
         return newMock(FieldTranslator.class);
     }
 
-
     protected final Translator mockTranslator(String name, Class type)
     {
         Translator translator = mockTranslator();
@@ -1178,7 +1152,7 @@
     }
 
     protected final void train_createDefaultTranslator(FieldTranslatorSource source, ComponentResources resources,
-                                                       String parameterName, FieldTranslator translator)
+            String parameterName, FieldTranslator translator)
     {
         expect(source.createDefaultTranslator(resources, parameterName)).andReturn(translator);
     }
@@ -1209,7 +1183,7 @@
     }
 
     protected final void train_createEditModel(BeanModelSource source, Class beanClass, Messages messages,
-                                               BeanModel model)
+            BeanModel model)
     {
         expect(source.createEditModel(beanClass, messages)).andReturn(model);
     }
@@ -1278,18 +1252,18 @@
     protected final Asset mockAsset(String assetURL)
     {
         Asset asset = mockAsset();
-    
+
         train_toClientURL(asset, assetURL);
-    
+
         return asset;
     }
 
     protected final Link mockLink(String absoluteURI)
     {
         Link link = mockLink();
-    
+
         expect(link.toAbsoluteURI()).andReturn(absoluteURI).atLeastOnce();
-    
+
         return link;
     }
 }

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/corelib/components/linksubmit.js
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/corelib/components/linksubmit.js?rev=911931&r1=911930&r2=911931&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/corelib/components/linksubmit.js (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/corelib/components/linksubmit.js Fri Feb 19 18:54:27 2010
@@ -1,4 +1,4 @@
-//  Copyright 2008 The Apache Software Foundation
+//  Copyright 2008, 2010 The Apache Software Foundation
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
@@ -14,10 +14,10 @@
 
 Tapestry.LinkSubmit = Class.create({
 
-    initialize: function(formId, clientId)
+    initialize: function(spec)
     {
-        this.form = $(formId);
-        this.element = $(clientId);
+        this.form = $(spec.form);
+        this.element = $(spec.clientId);
 
         this.element.observe("click", this.onClick.bindAsEventListener(this));
     },
@@ -52,7 +52,7 @@
     }
 });
 
-Tapestry.Initializer.linkSubmit = function(formId, clientId)
+Tapestry.Initializer.linkSubmit = function(spec)
 {
-    new Tapestry.LinkSubmit(formId, clientId);
+    new Tapestry.LinkSubmit(spec);
 }
\ No newline at end of file

Modified: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/FormTests.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/FormTests.java?rev=911931&r1=911930&r2=911931&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/FormTests.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/FormTests.java Fri Feb 19 18:54:27 2010
@@ -4,7 +4,7 @@
 // you may not use this file except in compliance with the License.
 // You may obtain a copy of the License at
 //
-//     http://www.apache.org/licenses/LICENSE-2.0
+// http://www.apache.org/licenses/LICENSE-2.0
 //
 // Unless required by applicable law or agreed to in writing, software
 // distributed under the License is distributed on an "AS IS" BASIS,
@@ -37,17 +37,13 @@
     {
         clickThru("Page Context in Form");
 
-        assertTextSeries("//li[%d]", 1, "betty", "wilma", "context with spaces",
-                "context/with/slashes");
-        assertFieldValue("t:ac",
-                "betty/wilma/context$0020with$0020spaces/context$002fwith$002fslashes");
+        assertTextSeries("//li[%d]", 1, "betty", "wilma", "context with spaces", "context/with/slashes");
+        assertFieldValue("t:ac", "betty/wilma/context$0020with$0020spaces/context$002fwith$002fslashes");
 
         clickAndWait(SUBMIT);
 
-        assertTextSeries("//li[%d]", 1, "betty", "wilma", "context with spaces",
-                "context/with/slashes");
-        assertFieldValue("t:ac",
-                "betty/wilma/context$0020with$0020spaces/context$002fwith$002fslashes");
+        assertTextSeries("//li[%d]", 1, "betty", "wilma", "context with spaces", "context/with/slashes");
+        assertFieldValue("t:ac", "betty/wilma/context$0020with$0020spaces/context$002fwith$002fslashes");
     }
 
     @Test
@@ -153,7 +149,7 @@
 
         assertTextPresent("Howard", "Lewis Ship", "1966", "U.S. Citizen");
     }
-    
+
     @Test
     public void cancel_button()
     {
@@ -165,7 +161,7 @@
         clickAndWait("link=Clear Data");
 
         clickAndWait("//input[@value='Cancel']");
-        
+
         assertText("message", "Form was cancelled.");
     }
 
@@ -226,8 +222,7 @@
 
         click("birthday-trigger");
 
-        waitForCondition(
-                "selenium.browserbot.getCurrentWindow().$$('DIV.datePicker').first().isDeepVisible() == true",
+        waitForCondition("selenium.browserbot.getCurrentWindow().$$('DIV.datePicker').first().isDeepVisible() == true",
                 PAGE_LOAD_TIMEOUT);
 
         assertText("//A[@class='topLabel']", "1966 d\u00e9cembre");
@@ -457,8 +452,7 @@
         waitForElementToAppear("amount:errorpopup");
         waitForElementToAppear("quantity:errorpopup");
 
-        assertText("//div[@id='amount:errorpopup']/span",
-                "You must provide a numeric value for Amount.");
+        assertText("//div[@id='amount:errorpopup']/span", "You must provide a numeric value for Amount.");
         assertText("//div[@id='quantity:errorpopup']/span", "Provide quantity as a number.");
     }
 
@@ -635,8 +629,7 @@
 
         waitForElementToAppear("longValue:errorpopup");
 
-        assertText("//div[@id='longValue:errorpopup']/span",
-                "You must provide an integer value for Long Value.");
+        assertText("//div[@id='longValue:errorpopup']/span", "You must provide an integer value for Long Value.");
 
         type("longValue", "37");
 
@@ -689,11 +682,15 @@
     public void link_submit_component()
     {
         clickThru("LinkSubmit Demo");
-
+        
+        // Wait a moment for the page to initialize.
+        
+        sleep(250);
+        
+        // 
         click("link=Fred");
 
-        waitForCondition("selenium.browserbot.getCurrentWindow().$('name:errorpopup')",
-                PAGE_LOAD_TIMEOUT);
+        waitForCondition("selenium.browserbot.getCurrentWindow().$('name:errorpopup')", PAGE_LOAD_TIMEOUT);
 
         assertTextPresent("You must provide a value for Name.");
 
@@ -782,13 +779,12 @@
         // Tried to use "email:" and "exact:email:" but Selenium 0.8.1 doesn't
         // seem to accept that.
 
-        assertTextPresent("[foo@bar.baz]", "[Message for you, sir!]", "[false]", "[winnt]",
-                "[RESEARCH_AND_DESIGN]");
+        assertTextPresent("[foo@bar.baz]", "[Message for you, sir!]", "[false]", "[winnt]", "[RESEARCH_AND_DESIGN]");
 
         // Haven't figured out how to get selenium to check that fields are
         // disabled.
     }
-    
+
     /**
      * TAP5-915
      */
@@ -798,12 +794,12 @@
         open(getBaseURL() + "overridedatefieldmessagecatalogdemo");
 
         type("birthday", "aaaaa");
-        
+
         clickAndWait("//input[@type='submit' and @value='Go']");
-       
+
         assertTextPresent("The input 'aaaaa' is not a valid date");
     }
-    
+
     /**
      * TAP5-52.
      */
@@ -811,23 +807,23 @@
     public void single_error_message()
     {
         open(getBaseURL() + "singleerrordemo");
-        
+
         clickAndWait(SUBMIT);
-        
+
         assertTextPresent("You must provide a value for Username");
         assertTextPresent("You must provide a value for Password");
 
         type("username", "Igor");
-        
+
         clickAndWait(SUBMIT);
-        
+
         assertFalse(isTextPresent("You must provide a value for Username"));
         assertTextPresent("You must provide a value for Password");
-        
+
         type("password", "secret");
-        
+
         clickAndWait(SUBMIT);
-        
+
         assertFalse(isTextPresent("You must provide a value for Username"));
         assertFalse(isTextPresent("You must provide a value for Password"));
     }