You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tapestry.apache.org by hl...@apache.org on 2010/01/22 17:31:49 UTC

svn commit: r902157 [2/2] - in /tapestry/tapestry5/trunk/tapestry-core/src: main/java/org/apache/tapestry5/ main/java/org/apache/tapestry5/annotations/ main/java/org/apache/tapestry5/internal/ main/java/org/apache/tapestry5/internal/model/ main/java/or...

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=902157&r1=902156&r2=902157&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 Jan 22 16:31:47 2010
@@ -14,29 +14,27 @@
 
 package org.apache.tapestry5.internal.transform;
 
-import java.lang.reflect.Modifier;
 import java.util.Iterator;
 import java.util.List;
 
 import org.apache.tapestry5.Binding;
+import org.apache.tapestry5.ComponentResources;
 import org.apache.tapestry5.annotations.Parameter;
 import org.apache.tapestry5.internal.InternalComponentResources;
 import org.apache.tapestry5.internal.ParameterAccess;
-import org.apache.tapestry5.internal.ParameterChangeListener;
-import org.apache.tapestry5.internal.ParameterChangedEvent;
-import org.apache.tapestry5.internal.TapestryInternalUtils;
 import org.apache.tapestry5.internal.bindings.LiteralBinding;
+import org.apache.tapestry5.internal.services.ComponentClassCache;
 import org.apache.tapestry5.ioc.internal.util.InternalUtils;
-import org.apache.tapestry5.ioc.util.BodyBuilder;
+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.TransformMethodSignature;
-import org.apache.tapestry5.services.TransformUtils;
 
 /**
  * Responsible for identifying parameters via the {@link org.apache.tapestry5.annotations.Parameter} annotation on
@@ -44,20 +42,25 @@
  */
 public class ParameterWorker implements ComponentClassTransformWorker
 {
-    private static final String BIND_METHOD_NAME = ParameterWorker.class.getName() + ".bind";
-    private static final String EQUAL_METHOD_NAME = ParameterWorker.class.getName() + ".equal";
+    private final ComponentClassCache classCache;
 
     private final BindingSource bindingSource;
 
-    private ComponentDefaultProvider defaultProvider;
+    private final ComponentDefaultProvider defaultProvider;
 
-    public ParameterWorker(BindingSource bindingSource, ComponentDefaultProvider defaultProvider)
+    private final TypeCoercer typeCoercer;
+
+    public ParameterWorker(ComponentClassCache classCache, BindingSource bindingSource,
+            ComponentDefaultProvider defaultProvider, TypeCoercer typeCoercer)
     {
+        this.classCache = classCache;
         this.bindingSource = bindingSource;
         this.defaultProvider = defaultProvider;
+        this.typeCoercer = typeCoercer;
     }
 
-    public void transform(final ClassTransformation transformation, MutableComponentModel model)
+    @Override
+    public void transform(ClassTransformation transformation, MutableComponentModel model)
     {
         List<String> fieldNames = transformation.findFieldsWithAnnotation(Parameter.class);
 
@@ -69,14 +72,13 @@
             {
                 String fieldName = i.next();
 
-                Parameter annotation = transformation.getFieldAnnotation(fieldName, Parameter.class);
+                Parameter annotation = transformation
+                        .getFieldAnnotation(fieldName, Parameter.class);
 
                 // Process the principal annotations on the first pass, handle the others
                 // on the second pass.
 
-                boolean process = pass == 0
-                                  ? annotation.principal()
-                                  : true;
+                boolean process = pass == 0 ? annotation.principal() : true;
 
                 if (process)
                 {
@@ -86,135 +88,236 @@
                 }
             }
         }
-    }
-
-    private void convertFieldIntoParameter(String name, Parameter annotation, ClassTransformation transformation,
-                                           MutableComponentModel model)
-    {
-        transformation.claimField(name, annotation);
-
-        String parameterName = getParameterName(name, annotation.name());
-
-        boolean cache = annotation.cache();
-
-        model.addParameter(parameterName, annotation.required(), annotation.allowNull(), annotation.defaultPrefix(),cache);
-
-        String type = transformation.getFieldType(name);
-
-        String cachedFieldName = transformation.addField(Modifier.PRIVATE, "boolean", name + "_cached");
-
-        String resourcesFieldName = transformation.getResourcesFieldName();
-
-        String accessFieldName = addParameterSetup(name, annotation.defaultPrefix(), annotation.value(),
-                                                   parameterName, cachedFieldName, cache, type, resourcesFieldName,
-                                                   transformation, annotation.autoconnect());
-
-        addReaderMethod(name, cachedFieldName, accessFieldName, cache, parameterName, type, resourcesFieldName,
-                        transformation);
 
-        addWriterMethod(name, cachedFieldName, accessFieldName, cache, parameterName, type, resourcesFieldName,
-                        transformation);
     }
 
-    /**
-     * Returns the name of a field that stores whether the parameter binding is invariant.
-     */
-    private String addParameterSetup(String fieldName, String defaultPrefix, String defaultBinding,
-                                     String parameterName, String cachedFieldName, boolean cache, String fieldType,
-                                     String resourcesFieldName, ClassTransformation transformation, boolean autoconnect)
+    private void convertFieldIntoParameter(String fieldName, final Parameter annotation,
+            ClassTransformation transformation, MutableComponentModel model)
     {
+        final String fieldTypeName = transformation.getFieldType(fieldName);
 
-        String accessFieldName = transformation.addField(Modifier.PRIVATE, ParameterAccess.class.getName(),
-                                                         fieldName + "_access");
+        final String parameterName = getParameterName(fieldName, annotation.name());
 
-        String defaultFieldName = transformation.addField(Modifier.PRIVATE, fieldType, fieldName + "_default");
+        final boolean enableCaching = annotation.cache();
 
-        BodyBuilder builder = new BodyBuilder().begin();
+        model.addParameter(parameterName, annotation.required(), annotation.allowNull(), annotation
+                .defaultPrefix(), enableCaching);
 
-        addDefaultBindingSetup(parameterName, defaultPrefix, defaultBinding, resourcesFieldName,
-                               transformation,
-                               builder, autoconnect);
-
-        // Order is (alas) important here: must invoke getParameterAccess() after the binding setup, as
-        // that code may invoke InternalComponentResources.bindParameter().
+        transformation.claimField(fieldName, annotation);
+        
+        ComponentValueProvider<ParameterConduit> provider = 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.
 
-        builder.addln("%s = %s.getParameterAccess(\"%s\");", accessFieldName, resourcesFieldName, parameterName);
+            @Override
+            public ParameterConduit get(ComponentResources resources)
+            {
+                final InternalComponentResources icr = (InternalComponentResources) resources;
 
-        // Store the current value of the field into the default field. This value will
-        // be used to reset the field after rendering.
+                final Class fieldType = classCache.forName(fieldTypeName);
 
-        builder.addln("%s = %s;", defaultFieldName, fieldName);
+                // Rely on some code generation in the component to set the default binding from
+                // the field, or from a default method.
 
-        addListenerSetup(fieldName, fieldType, parameterName, accessFieldName, builder, transformation);
+                return new ParameterConduit()
+                {
+                    // Current cached value for the parameter.
+                    private Object value;
 
-        builder.end();
+                    // Default value for parameter, computed *once* at
+                    // page load time.
 
-        transformation.extendMethod(TransformConstants.CONTAINING_PAGE_DID_LOAD_SIGNATURE, builder
-                .toString());
+                    private Object defaultValue;
 
-        // Now, when the component completes rendering, ensure that any variant parameters are
-        // are returned to default value. This isn't necessary when the parameter is not cached,
-        // because (unless the binding is invariant), there's no value to get rid of (and if it is
-        // invariant, there's no need to get rid of it).
+                    private ParameterAccess parameterAccess;
+
+                    private Binding defaultBinding;
+
+                    boolean loaded = false;
+
+                    // Is the current value of the binding cached in the
+                    // 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);
+                        }
+
+                        icr.setParameterConduit(parameterName, this);
+                    }
+
+                    private boolean isInvariant()
+                    {
+                        return parameterAccess.isInvariant();
+                    }
+
+                    private boolean isLoaded()
+                    {
+                        return loaded;
+                    }
+
+                    @Override
+                    public void set(Object newValue)
+                    {
+                        // Assignments before the page is loaded ultimately exist to set the
+                        // default value for the field. Often this is from the (original)
+                        // constructor method,
+                        // which is converted to a real method as part of the transformation.
+
+                        if (!loaded)
+                        {
+                            defaultValue = newValue;
+                            return;
+                        }
+
+                        // This will catch read-only or unbound parameters.
+
+                        parameterAccess.write(newValue);
+
+                        value = newValue;
+
+                        // 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
+                        // rendering).
+
+                        cached = enableCaching && icr.isRendering();
+                    }
+
+                    @Override
+                    public void reset()
+                    {
+                        if (!isInvariant())
+                        {
+                            value = defaultValue;
+                            cached = false;
+                        }
+                    }
+
+                    @Override
+                    public void load()
+                    {
+                        // If it's bound at this point, that's because of an explicit binding
+                        // in the template or @Component annotation.
+
+                        if (!icr.isBound(parameterName))
+                        {
+                            // Otherwise, construct a default binding, or use one provided from
+                            // the component.
+
+                            Binding binding = getDefaultBindingForParameter();
+
+                            if (binding != null)
+                                icr.bindParameter(parameterName, binding);
+
+                            defaultBinding = null;
+                        }
+
+                        parameterAccess = icr.getParameterAccess(parameterName);
+
+                        loaded = true;
+
+                        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 defaultBinding;
+                    }
+
+                    @Override
+                    public boolean isBound()
+                    {
+                        return parameterAccess.isBound();
+                    }
+
+                    @SuppressWarnings("unchecked")
+                    @Override
+                    public Object get()
+                    {
+                        if (!isLoaded()) { return defaultValue; }
+
+                        if (cached || !isBound()) { return value; }
+
+                        // Read the parameter's binding and cast it to the
+                        // field's type.
+                        Object result = parameterAccess.read(fieldType);
+
+                        // If the value is invariant, we can cache it forever. Otherwise, we
+                        // we may want to cache it for the remainder of the component render (if the
+                        // component is currently rendering).
+
+                        if (isInvariant() || (enableCaching && icr.isRendering()))
+                        {
+                            value = result;
+                            cached = true;
+                        }
+
+                        return result;
+                    }
+
+                    @Override
+                    public void setDefault(Object value)
+                    {
+                        if (value == null)
+                            return;
+
+                        if (value instanceof Binding)
+                        {
+                            defaultBinding = (Binding) value;
+                            return;
+                        }
+
+                        defaultBinding = new LiteralBinding(null, "default " + parameterName, value);
+                    }
+                };
+            }
 
-        if (cache)
-        {
-            builder.clear();
+        };
 
-            builder.addln("if (! %s.isInvariant())", accessFieldName);
-            builder.begin();
-            builder.addln("%s = %s;", fieldName, defaultFieldName);
-            builder.addln("%s = false;", cachedFieldName);
-            builder.end();
+        // This has to be done in the constructor, to handle any field initializations
 
-            // Clean up after the component renders.
+        String conduitFieldName = transformation.addIndirectInjectedField(ParameterConduit.class,
+                parameterName + "$conduit", provider);
 
-            String body = builder.toString();
+        addCodeForParameterDefaultMethod(transformation, parameterName, conduitFieldName);
 
-            transformation.extendMethod(TransformConstants.POST_RENDER_CLEANUP_SIGNATURE, body);
+        transformation.replaceFieldAccess(fieldName, conduitFieldName);
 
-            // And again, when the page is detached (TAPESTRY-2460)
+        transformation.extendMethod(TransformConstants.CONTAINING_PAGE_DID_LOAD_SIGNATURE, String
+                .format("%s.load();", conduitFieldName));
 
-            transformation.extendMethod(TransformConstants.CONTAINING_PAGE_DID_DETACH_SIGNATURE, builder.toString());
-        }
+        transformation.extendMethod(TransformConstants.POST_RENDER_CLEANUP_SIGNATURE, String
+                .format("%s.reset();", conduitFieldName));
 
-        return accessFieldName;
     }
 
-    private void addDefaultBindingSetup(String parameterName, String defaultPrefix, String defaultBinding,
-                                        String resourcesFieldName,
-                                        ClassTransformation transformation,
-                                        BodyBuilder builder, boolean autoconnect)
+    private void addCodeForParameterDefaultMethod(ClassTransformation transformation,
+            final String parameterName, String conduitFieldName)
     {
-        if (InternalUtils.isNonBlank(defaultBinding))
-        {
-            builder.addln("if (! %s.isBound(\"%s\"))", resourcesFieldName, parameterName);
-
-            String bindingFactoryFieldName = transformation.addInjectedField(BindingSource.class, "bindingSource",
-                                                                             bindingSource);
-
-            builder
-                    .addln("  %s.bindParameter(\"%s\", %s.newBinding(\"default %2$s\", %1$s, \"%s\", \"%s\"));",
-                           resourcesFieldName, parameterName, bindingFactoryFieldName, defaultPrefix, defaultBinding);
-
-            return;
-        }
-
-        if (autoconnect)
-        {
-            String defaultProviderFieldName = transformation.addInjectedField(ComponentDefaultProvider.class,
-                                                                              "defaultProvider", defaultProvider);
-
-            builder.addln("if (! %s.isBound(\"%s\"))", resourcesFieldName, parameterName);
-
-            builder.addln("  %s.bindParameter(\"%s\", %s.defaultBinding(\"%s\", %s));", resourcesFieldName,
-                          parameterName, defaultProviderFieldName, parameterName, resourcesFieldName);
-            return;
-        }
-
-        // If no default binding expression provided in the annotation, then look for a default
-        // binding method to provide the binding.
-
         final String methodName = "default" + parameterName;
 
         MethodFilter filter = new MethodFilter()
@@ -231,187 +334,20 @@
 
         List<TransformMethodSignature> signatures = transformation.findMethods(filter);
 
-        if (signatures.isEmpty()) return;
-
-        // Because the check was case-insensitive, we need to determine the actual
-        // name.
+        if (signatures.isEmpty())
+            return;
 
         String actualMethodName = signatures.get(0).getMethodName();
 
-        builder.addln("if (! %s.isBound(\"%s\"))", resourcesFieldName, parameterName);
-        builder.addln("  %s(\"%s\", %s, ($w) %s());",
-                      BIND_METHOD_NAME,
-                      parameterName,
-                      resourcesFieldName,
-                      actualMethodName);
-    }
-
-    private void addListenerSetup(
-            String fieldName,
-            String fieldType,
-            String parameterName,
-            String accessFieldName,
-            BodyBuilder builder,
-            ClassTransformation transformation)
-    {
-        transformation.addImplementedInterface(ParameterChangeListener.class);
-        builder.addln("%s.registerParameterChangeListener($0);",accessFieldName);
-
-        TransformMethodSignature signature = new TransformMethodSignature(Modifier.PUBLIC, "void", "parameterChanged",
-                new String[] {ParameterChangedEvent.class.getName()}, null);
-
-        BodyBuilder changedBody = new BodyBuilder();
-        changedBody.begin();
-
-        changedBody.addln("if (%s($1, \"%s\"))",EQUAL_METHOD_NAME,parameterName);
-        changedBody.begin();
-
-        String cast = TransformUtils.getWrapperTypeName(fieldType);
-
-        if (TransformUtils.isPrimitive(fieldType))
-            changedBody.addln("%s = ((%s) $1.getNewValue()).%s();",
-                                fieldName, cast, TransformUtils.getUnwrapperMethodName(fieldType));
-        else
-            changedBody.addln("%s = (%s) $1.getNewValue();",fieldName, cast);
-
-        changedBody.addln("return;");
-        changedBody.end();
-
-        changedBody.end();
-        
-        transformation.extendMethod(signature,changedBody.toString());
-
-    }
-
-    private void addWriterMethod(String fieldName, String cachedFieldName, String accessFieldName, boolean cache,
-                                 String parameterName, String fieldType, String resourcesFieldName,
-                                 ClassTransformation transformation)
-    {
-        BodyBuilder builder = new BodyBuilder();
-        builder.begin();
-
-        // Before the component is loaded, updating the property sets the default value
-        // for the parameter. The value is stored in the field, but will be
-        // rolled into default field inside containingPageDidLoad().
-
-        builder.addln("if (! %s.isLoaded())", resourcesFieldName);
-        builder.begin();
-        builder.addln("%s = $1;", fieldName);
-        builder.addln("return;");
-        builder.end();
-
-        // Always start by updating the parameter; this will implicitly check for
-        // read-only or unbound parameters. $1 is the single parameter
-        // to the method.
-        builder.addln("%s.unregisterParameterChangeListener($0);",accessFieldName);
-        builder.addln("%s.write(($w)$1);", accessFieldName);
-        builder.addln("%s.registerParameterChangeListener($0);",accessFieldName);
-        builder.addln("%s = $1;", fieldName);
-        if (cache) builder.addln("%s = %s.isRendering();", cachedFieldName, resourcesFieldName);
-
-        builder.end();
-
-        String methodName = transformation.newMemberName("update_parameter", parameterName);
-
-        TransformMethodSignature signature = new TransformMethodSignature(Modifier.PRIVATE, "void", methodName,
-                                                                          new String[] {fieldType}, null);
-
-        transformation.addMethod(signature, builder.toString());
-
-        builder.clear();
-
-        //add the catch because if we don't re-register the class as a parameter change listener, it's value
-        //could wind up stale, and write can throw an exception.
-        builder.begin();
-        builder.addln("%s.registerParameterChangeListener($0);",accessFieldName);
-        builder.addln("throw $e;");
-        builder.end();
-
-        transformation.addCatch(signature,Exception.class.getName(),builder.toString());
-
-        transformation.replaceWriteAccess(fieldName, methodName);
-    }
-
-    /**
-     * Adds a private method that will be the replacement for read-access to the field.
-     */
-    private void addReaderMethod(String fieldName, String cachedFieldName, String accessFieldName, boolean cache,
-                                 String parameterName, String fieldType, String resourcesFieldName,
-                                 ClassTransformation transformation)
-    {
-        BodyBuilder builder = new BodyBuilder();
-        builder.begin();
-
-        // While the component is still loading, or when the value for the component is cached,
-        // or if the value is not bound, then return the current value of the field.
-
-        builder.addln("if (%s || ! %s.isLoaded() || ! %s.isBound()) return %s;", cachedFieldName,
-                      resourcesFieldName, accessFieldName, fieldName);
-
-        String cast = TransformUtils.getWrapperTypeName(fieldType);
-
-        // The ($r) cast will convert the result to the method return type; generally
-        // this does nothing. but for primitive types, it will unwrap
-        // the wrapper type back to a primitive.  We pass the desired type name
-        // to readParameter(), since its easier to convert it properly to
-        // a type on that end than in the generated code.
-
-        builder.addln("%s result = ($r) ((%s) %s.read(\"%2$s\"));", fieldType, cast, accessFieldName);
-
-        // If the binding is invariant, then it's ok to cache. Othewise, its only
-        // ok to cache if a) the @Parameter says to cache and b) the component
-        // is rendering at the point when field is accessed.
-
-        builder.add("if (%s.isInvariant()", accessFieldName);
-
-        if (cache) builder.add(" || %s.isRendering()", resourcesFieldName);
-
-        builder.addln(")");
-        builder.begin();
-        builder.addln("%s = result;", fieldName);
-        builder.addln("%s = true;", cachedFieldName);
-        builder.end();
-
-        builder.addln("return result;");
-        builder.end();
-
-        String methodName = transformation.newMemberName("read_parameter", parameterName);
-
-        TransformMethodSignature signature = new TransformMethodSignature(Modifier.PRIVATE, fieldType, methodName, null,
-                                                                          null);
-
-        transformation.addMethod(signature, builder.toString());
-
-        transformation.replaceReadAccess(fieldName, methodName);
+        transformation.extendExistingMethod(TransformConstants.CONTAINING_PAGE_DID_LOAD_SIGNATURE,
+                String.format("%s.setDefault(($w) %s());", conduitFieldName, actualMethodName));
     }
 
-    private String getParameterName(String fieldName, String annotatedName)
+    private static String getParameterName(String fieldName, String annotatedName)
     {
-        if (InternalUtils.isNonBlank(annotatedName)) return annotatedName;
+        if (InternalUtils.isNonBlank(annotatedName))
+            return annotatedName;
 
         return InternalUtils.stripMemberName(fieldName);
     }
-
-    /**
-     * Invoked from generated code as part of the handling of parameter default methods.
-     */
-    public static void bind(String parameterName, InternalComponentResources resources, Object value)
-    {
-        if (value == null) return;
-
-        if (value instanceof Binding)
-        {
-            Binding binding = (Binding) value;
-
-            resources.bindParameter(parameterName, binding);
-            return;
-        }
-
-        resources.bindParameter(parameterName, new LiteralBinding(null, "default " + parameterName, value));
-    }
-
-    public static <T> boolean equal(T left, T right)
-    {
-        return TapestryInternalUtils.isEqual(left,right);
-    }
 }

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/transform/TransformMessages.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/transform/TransformMessages.java?rev=902157&r1=902156&r2=902157&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/transform/TransformMessages.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/transform/TransformMessages.java Fri Jan 22 16:31:47 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,
@@ -16,7 +16,9 @@
 
 import java.util.List;
 
+import org.apache.tapestry5.ComponentResources;
 import org.apache.tapestry5.annotations.MixinClasses;
+import org.apache.tapestry5.internal.structure.InternalComponentResourcesImpl;
 import org.apache.tapestry5.ioc.Messages;
 import org.apache.tapestry5.ioc.internal.util.InternalUtils;
 import org.apache.tapestry5.ioc.internal.util.MessagesImpl;
@@ -43,12 +45,22 @@
 
     static String illegalNumberOfPageActivationContextHandlers(List<String> fields)
     {
-        return MESSAGES.format("illegal-number-of-page-activation-context-handlers", InternalUtils.joinSorted(fields));
+        return MESSAGES.format("illegal-number-of-page-activation-context-handlers", InternalUtils
+                .joinSorted(fields));
     }
 
-
     public static String badMixinConstraintLength(MixinClasses mixin, String fieldName)
     {
-        return MESSAGES.format("bad-mixin-constraint-length",mixin.value().length,fieldName,mixin.order().length);
+        return MESSAGES.format("bad-mixin-constraint-length", mixin.value().length, fieldName,
+                mixin.order().length);
     }
+
+    /** @since 5.2.0 */
+    public static String bindParameterOnlyOnMixin(String boundParameterName,
+            ComponentResources resources)
+    {
+        return MESSAGES.format("bind-parameter-only-on-mixin", boundParameterName,
+                resources.getComponentModel().getComponentClassName());
+    }
+
 }

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/model/ComponentModel.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/model/ComponentModel.java?rev=902157&r1=902156&r2=902157&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/model/ComponentModel.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/model/ComponentModel.java Fri Jan 22 16:31:47 2010
@@ -1,4 +1,4 @@
-// Copyright 2006, 2007, 2008, 2009 The Apache Software Foundation
+// Copyright 2006, 2007, 2008, 2009, 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.
@@ -39,7 +39,7 @@
     Resource getBaseResource();
 
     /**
-     * The FQCN of the component.
+     * The fully qualified class name of the component.
      */
     String getComponentClassName();
 
@@ -79,13 +79,21 @@
     List<String> getMixinClassNames();
 
     /**
-     * Return a single parameter model by parameter name, or null if the parameter is not defined.
+     * Return a single parameter model by parameter name, or null if the parameter is not defined (is not 
+     * a formal parameter).
      *
      * @param parameterName the name of the parameter (case is ignored)
      */
     ParameterModel getParameterModel(String parameterName);
 
     /**
+     * Returns true if the named parameter is formally defined (there's a ParameterModel).
+     * @param parameterName name of the parameter (case is ignored)
+     * @since 5.2.0
+     */
+    boolean isFormalParameter(String parameterName);
+    
+    /**
      * Returns an alphabetically sorted list of the names of all formal parameters. This includes parameters defined by
      * a base class.
      */
@@ -171,7 +179,7 @@
     /**
      * @param mixinClassName class name of the mixin for which the ordering is desired
      * @return the ordering constraint(s) for the mixin, potentially null.
-     * @since 5.2.0.0
+     * @since 5.2.0
      */
     String[] getOrderForMixin(String mixinClassName);
 }

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/model/MutableComponentModel.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/model/MutableComponentModel.java?rev=902157&r1=902156&r2=902157&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/model/MutableComponentModel.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/model/MutableComponentModel.java Fri Jan 22 16:31:47 2010
@@ -1,4 +1,4 @@
-// Copyright 2006, 2007, 2008, 2009 The Apache Software Foundation
+// Copyright 2006, 2007, 2008, 2009, 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.

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=902157&r1=902156&r2=902157&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 Jan 22 16:31:47 2010
@@ -546,9 +546,8 @@
         // make sure
         // that Parameter fields are processed after injections.
 
-        // configuration.addInstance("Parameter", ParameterWorker.class, "after:Inject*");
-        configuration.addInstance("Parameter", ParameterWorker2.class, "after:Inject*");
-
+        configuration.addInstance("Parameter", ParameterWorker.class, "after:Inject*");
+        
         // bind parameter should always go after parameter to make sure all
         // parameters
         // have been properly setup.

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/internal/structure/StructureStrings.properties
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/internal/structure/StructureStrings.properties?rev=902157&r1=902156&r2=902157&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/internal/structure/StructureStrings.properties (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/internal/structure/StructureStrings.properties Fri Jan 22 16:31:47 2010
@@ -36,7 +36,3 @@
 render-variable-set-when-not-rendering=Component %s is not rendering, so render variable '%s' may not be updated.
 persist-change-before-load-complete=Persistent fields may not be updated until after the page has finished loading. \
   This may be due to a persistent field with a default value. The default value should be removed.
-no-such-core-component-parameter=Failed to BindParameter '%s' in mixin '%s': component '%s' does not provide a matching \
-  parameter (looking for: %s).  Available parameters: %s
-bind-parameter-only-on-mixin=@BindParameter was used on '%s' in component class '%s', but @BindParameter should \
-  only be used in mixins.

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/internal/transform/TransformStrings.properties
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/internal/transform/TransformStrings.properties?rev=902157&r1=902156&r2=902157&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/internal/transform/TransformStrings.properties (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/internal/transform/TransformStrings.properties Fri Jan 22 16:31:47 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.
@@ -18,3 +18,6 @@
 illegal-number-of-page-activation-context-handlers=Illegal number of fields annotated with @PageActivationContext: %s. Only one field is allowed.
 bad-mixin-constraint-length=%d mixins defined via @MixinClasses on field '%s', but %d ordering constraints \
  specified (expected 0 or %1$d).
+bind-parameter-only-on-mixin=@BindParameter was used on field '%s' of component class '%s', but @BindParameter should \
+  only be used in mixins.
+ 
\ No newline at end of file

Modified: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/CoreBehaviorsTests.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/CoreBehaviorsTests.java?rev=902157&r1=902156&r2=902157&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/CoreBehaviorsTests.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/CoreBehaviorsTests.java Fri Jan 22 16:31:47 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,
@@ -1321,10 +1321,8 @@
 
         assertTextPresent(
                 "An unexpected application exception has occurred.",
-                "Failed to BindParameter 'boundParameter' in mixin 'org.apache.tapestry5.integration.app1.mixins.EchoValue2': "
-                        + "component 'org.apache.tapestry5.corelib.components.Any' does not provide a matching parameter "
-                        + "(looking for: value). Available parameters: [clientId, element]");
 
+                "Failed to bind parameter of mixin BindParameterNoSuchParameter:throwexception$echovalue2 (type org.apache.tapestry5.integration.app1.mixins.EchoValue2). Containing component org.apache.tapestry5.corelib.components.Any does not contain a formal parameter matching any of boundParameter, value. Formal parameters: clientId, element.");
     }
 
     @Test
@@ -1334,7 +1332,7 @@
 
         assertTextPresent(
                 "An unexpected application exception has occurred.",
-                "@BindParameter was used on 'value' in component class 'org.apache.tapestry5.integration.app1.components.BindParameterComponent', but @BindParameter should only be used in mixins");
+                "@BindParameter was used on field 'value' of component class 'org.apache.tapestry5.integration.app1.components.BindParameterComponent', but @BindParameter should only be used in mixins.");
     }
 
     @Test
@@ -1364,8 +1362,7 @@
      * there's warnings that pop up about
      * certificates.
      * <p/>
-     * Verified: Selenium can't handle this, even with a user manually OK-ing the certificate
-     * warning dialogs.
+     * Verified: Selenium can't handle this, even with a user manually OK-ing the certificate warning dialogs.
      */
     @Test(enabled = false)
     public void secure_page_access()

Modified: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/mixins/TextOnlyOnDisabled.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/mixins/TextOnlyOnDisabled.java?rev=902157&r1=902156&r2=902157&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/mixins/TextOnlyOnDisabled.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/mixins/TextOnlyOnDisabled.java Fri Jan 22 16:31:47 2010
@@ -1,10 +1,10 @@
-// Copyright 2009 The Apache Software Foundation
+// Copyright 2009, 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,16 +14,17 @@
 
 package org.apache.tapestry5.integration.app1.mixins;
 
+import org.apache.tapestry5.ClientElement;
+import org.apache.tapestry5.ComponentResources;
+import org.apache.tapestry5.FieldTranslator;
+import org.apache.tapestry5.MarkupWriter;
 import org.apache.tapestry5.annotations.BindParameter;
 import org.apache.tapestry5.annotations.InjectContainer;
-import org.apache.tapestry5.*;
-import org.apache.tapestry5.internal.InternalComponentResources;
-import org.apache.tapestry5.internal.ParameterAccess;
 import org.apache.tapestry5.ioc.annotations.Inject;
 import org.apache.tapestry5.ioc.services.TypeCoercer;
 
 /**
- * Renders a plain-text version of a value where 
+ * Renders a plain-text version of a value where
  */
 public class TextOnlyOnDisabled
 {
@@ -33,7 +34,6 @@
     @BindParameter
     private boolean disabled;
 
-
     @BindParameter
     private FieldTranslator translate;
 
@@ -48,15 +48,14 @@
 
     Boolean beginRender(MarkupWriter writer)
     {
-        InternalComponentResources res = (InternalComponentResources) resources;
-        ParameterAccess acc = res.getContainerBoundParameterAccess("translate","translate");
         if (disabled)
         {
-            //We can short-circuit the text field's beginRender phase, but
-            //not it's afterRender phase, and TextField calls writer.end()
-            //in end render.  So we add a dummy element to provide an element to end.
-            writer.element("span","id",field.getClientId());
+            // We can short-circuit the text field's beginRender phase, but
+            // not it's afterRender phase, and TextField calls writer.end()
+            // in end render. So we add a dummy element to provide an element to end.
+            writer.element("span", "id", field.getClientId());
             writer.write(translate.toClient(value));
+
             return false;
         }
         return null;

Modified: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/structure/InternalComponentResourcesImplTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/structure/InternalComponentResourcesImplTest.java?rev=902157&r1=902156&r2=902157&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/structure/InternalComponentResourcesImplTest.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/structure/InternalComponentResourcesImplTest.java Fri Jan 22 16:31:47 2010
@@ -44,7 +44,7 @@
         replay();
 
         InternalComponentResources resources = new InternalComponentResourcesImpl(null, element, null, null, null,
-                                                                                  null, ins);
+                                                                                  null, ins, false);
 
         resources.renderInformalParameters(writer);
 
@@ -69,7 +69,7 @@
         replay();
 
         InternalComponentResources resources = new InternalComponentResourcesImpl(null, element, null, null, null,
-                                                                                  null, ins);
+                                                                                  null, ins, false);
 
         resources.bindParameter("fred", binding);
 
@@ -105,7 +105,7 @@
 
         InternalComponentResources resources = new InternalComponentResourcesImpl(null, element, null,
                                                                                   componentPageElementResources,
-                                                                                  null, null, ins);
+                                                                                  null, null, ins, false);
 
         resources.bindParameter("fred", binding);
 
@@ -130,7 +130,7 @@
 
         replay();
 
-        ComponentResources resources = new InternalComponentResourcesImpl(null, element, null, null, null, null, ins);
+        ComponentResources resources = new InternalComponentResourcesImpl(null, element, null, null, null, null, ins, false);
 
         resources.storeRenderVariable("myRenderVar", value);
 
@@ -160,7 +160,7 @@
         replay();
 
         ComponentResources resources = new InternalComponentResourcesImpl(null, element, null, null, "Foo.bar", null,
-                                                                          ins);
+                                                                          ins, false);
 
         resources.storeRenderVariable("fred", "FRED");
         resources.storeRenderVariable("barney", "BARNEY");
@@ -195,7 +195,7 @@
         replay();
 
         InternalComponentResources resources = new InternalComponentResourcesImpl(null, element, null, null, "Foo.bar",
-                                                                                  null, ins);
+                                                                                  null, ins, false);
 
         resources.storeRenderVariable("fred", "FRED");
         resources.storeRenderVariable("barney", "BARNEY");
@@ -231,7 +231,7 @@
         replay();
 
         InternalComponentResources resources = new InternalComponentResourcesImpl(null, element, null, null, "Foo.bar",
-                                                                                  null, ins);
+                                                                                  null, ins, false);
 
 
         try
@@ -265,7 +265,7 @@
         replay();
 
         InternalComponentResources resources = new InternalComponentResourcesImpl(page, element, null, null, null,
-                                                                                  null, ins);
+                                                                                  null, ins, false);
 
         resources.addPageLifecycleListener(listener);