tapestry-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From robertdzeig...@apache.org
Subject svn commit: r795264 [2/3] - in /tapestry/tapestry5/trunk: src/site/apt/dev/ src/site/apt/guide/ tapestry-core/src/main/java/org/apache/tapestry5/annotations/ tapestry-core/src/main/java/org/apache/tapestry5/internal/ tapestry-core/src/main/java/org/apa...
Date Fri, 17 Jul 2009 22:53:32 GMT
Added: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/transform/BindParameterWorker.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/transform/BindParameterWorker.java?rev=795264&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/transform/BindParameterWorker.java (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/transform/BindParameterWorker.java Fri Jul 17 22:53:30 2009
@@ -0,0 +1,348 @@
+// Copyright 2009 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
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry5.internal.transform;
+
+import org.apache.tapestry5.services.*;
+import org.apache.tapestry5.model.MutableComponentModel;
+import org.apache.tapestry5.annotations.BindParameter;
+import org.apache.tapestry5.internal.*;
+import org.apache.tapestry5.internal.bindings.LiteralBinding;
+import org.apache.tapestry5.ioc.util.BodyBuilder;
+import org.apache.tapestry5.ioc.internal.util.InternalUtils;
+import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
+import org.apache.tapestry5.Binding;
+
+import java.util.List;
+import java.util.Iterator;
+import java.util.Arrays;
+import java.lang.reflect.Modifier;
+
+/**
+ * Responsible for identifying, via the {@link org.apache.tapestry5.annotations.BindParameter} annotation,
+ * mixin fields that should be bound to a core-component parameter value.
+ *
+ * @since 5.2.0.0
+ */
+public class BindParameterWorker implements ComponentClassTransformWorker
+{
+
+    private static final String EQUAL_METHOD_NAME = BindParameterWorker.class.getName() + ".equal";
+
+    public void transform(final ClassTransformation transformation, MutableComponentModel model)
+    {
+        List<String> fieldNames = transformation.findFieldsWithAnnotation(BindParameter.class);
+
+        for(String fieldName : fieldNames)
+        {
+            BindParameter annotation = transformation.getFieldAnnotation(fieldName, BindParameter.class);
+            convertFieldIntoContainerBoundParameter(fieldName, annotation, transformation, model);
+        }
+
+    }
+
+    private void convertFieldIntoContainerBoundParameter(String name, BindParameter annotation, ClassTransformation transformation,
+                                           MutableComponentModel model)
+    {
+        transformation.claimField(name, annotation);
+
+        String boundParameterName = getBoundParameterName(name, annotation.name());
+        String[] parentParameterNames = getParentParameterNames(name, annotation.value());
+
+
+        String type = transformation.getFieldType(name);
+
+        //we can't do this exactly the same as parameter. We can't know at transformation time which parameter
+        //this thing will be linked to, because it could be wired to any number of different components.
+        //So we have to wait until runtime to examine caching and whether we should cache, rather than
+        //constructing the class differently based on caching or not.
+        String cachedFieldName = transformation.addField(Modifier.PRIVATE, "boolean", name + "_cached");
+
+        String resourcesFieldName = transformation.getResourcesFieldName();
+
+        String accessFieldName = addBoundParameterSetup(name,
+                boundParameterName, parentParameterNames,
+                cachedFieldName, type, resourcesFieldName,
+                transformation);
+
+        addReaderMethod(name, cachedFieldName, accessFieldName, boundParameterName, type, resourcesFieldName,
+                        transformation);
+
+        addWriterMethod(name, cachedFieldName, accessFieldName, boundParameterName, type, resourcesFieldName,
+                        transformation);
+    }
+
+
+    /**
+     * Returns the name of a field that stores whether the parameter binding is invariant.
+     */
+    private String addBoundParameterSetup(String fieldName, String boundParameterName, String[] parentParameterNames,
+                                     String cachedFieldName, String fieldType,
+                                     String resourcesFieldName, ClassTransformation transformation)
+    {
+        String accessFieldName = transformation.addField(Modifier.PRIVATE, ParameterAccess.class.getName(),
+                fieldName + "_access");
+
+        String parentNamesField = transformation.addField(Modifier.PRIVATE, String[].class.getName(),
+                fieldName + "_parentparameternames");
+
+        String defaultFieldName = transformation.addField(Modifier.PRIVATE, fieldType, fieldName + "_default");
+
+        BodyBuilder builder = new BodyBuilder().begin();
+
+        builder.addln("%s = new String[%d];",parentNamesField,parentParameterNames.length);
+
+        for(int i=0;i<parentParameterNames.length;i++)
+        {
+            builder.addln("%s[%d]=\"%s\";",parentNamesField,i,parentParameterNames[i]);
+        }
+
+        builder.addln("%s = %s.getContainerBoundParameterAccess(\"%s\",%s);",
+                accessFieldName,
+                resourcesFieldName,
+                boundParameterName,
+                parentNamesField);
+
+        // Store the current value of the field into the default field. This value will
+        // be used to reset the field after rendering.
+
+        builder.addln("%s = %s;", defaultFieldName, fieldName);
+
+
+        addListenerSetup(fieldName, fieldType, boundParameterName, parentParameterNames, accessFieldName,  builder,
+                         transformation);
+
+        builder.end();
+
+        transformation.extendMethod(TransformConstants.CONTAINING_PAGE_DID_LOAD_SIGNATURE, builder
+                .toString());
+
+        // 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).
+        // as with reader/writer methods, we have to do the caching check at runtime.
+        builder.clear();
+
+        builder.addln("if (%s.shouldCache() && ! %1$s.isInvariant())", accessFieldName);
+        builder.begin();
+        builder.addln("%s = %s;", fieldName, defaultFieldName);
+        builder.addln("%s = false;", cachedFieldName);
+        builder.end();
+
+        // Clean up after the component renders.
+
+        String body = builder.toString();
+
+        transformation.extendMethod(TransformConstants.POST_RENDER_CLEANUP_SIGNATURE, body);
+
+        // And again, when the page is detached (TAPESTRY-2460)
+
+        transformation.extendMethod(TransformConstants.CONTAINING_PAGE_DID_DETACH_SIGNATURE, body);
+
+        return accessFieldName;
+    }
+
+    private void addListenerSetup(
+            String fieldName,
+            String fieldType,
+            String boundParameterName,
+            String[] parentParameterNames,
+            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().begin();
+        //by this point, we know that there is at least one entry in parent Parameter Names.
+        changedBody.add("if (%s($1, \"%s\")", EQUAL_METHOD_NAME, parentParameterNames[0]);
+        for(int i=1; i<parentParameterNames.length; i++)
+        {
+            changedBody.add(" || %s($1, \"%s\")", EQUAL_METHOD_NAME, parentParameterNames[i]);
+        }
+        changedBody.add(")").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;").end();
+
+        changedBody.end();
+
+        transformation.extendMethod(signature,changedBody.toString());
+
+    }
+
+    private void addWriterMethod(String fieldName, String cachedFieldName, String accessFieldName,
+                                 String boundParameterName, 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();
+
+        //unregistering the listener from the parameter change listener list avoids double-setting the field,
+        builder.addln("%s.unregisterParameterChangeListener($0);",accessFieldName);
+
+        // 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.write(($w)$1);", accessFieldName);
+        builder.addln("%s = $1;",fieldName);
+        builder.addln("%s.registerParameterChangeListener($0);",accessFieldName);
+
+        //note that there's no way of knowing at class transformation time which component a mixin will
+        //be associated with and, further more, no way of knowing which @Parameter a mixin field will be
+        //@BindParameter'ed to.  So we have to generate caching code that works at runtime, rather than
+        //including or not including caching logic at transformation time.
+        builder.addln("if (%s.shouldCache())",accessFieldName).begin();
+        builder.addln("%s = %s.isRendering();",cachedFieldName, resourcesFieldName).end();
+        builder.end();
+
+        String methodName = transformation.newMemberName("update_boundparameter", boundParameterName);
+
+        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,
+                                 String boundParameterName, 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.shouldCache() && %s) || ! %s.isLoaded() || ! %s.isBound()) return %s;",
+                accessFieldName, 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() || (%1$s.shouldCache() && %s.isRendering()))",
+                accessFieldName, resourcesFieldName);
+
+        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_boundparameter", boundParameterName);
+
+        TransformMethodSignature signature = new TransformMethodSignature(Modifier.PRIVATE, fieldType, methodName, null,
+                null);
+
+        transformation.addMethod(signature, builder.toString());
+
+        transformation.replaceReadAccess(fieldName, methodName);
+    }
+
+    private String getBoundParameterName(String fieldName, String annotatedName)
+    {
+        if (InternalUtils.isNonBlank(annotatedName)) return annotatedName;
+
+        return InternalUtils.stripMemberName(fieldName);
+    }
+
+    private String[] getParentParameterNames(String fieldName, String... names)
+    {
+        List<String> temp = CollectionFactory.newList(names);
+        for(Iterator<String> it = temp.iterator();it.hasNext(); )
+        {
+            String name =it.next();
+            if (InternalUtils.isBlank(name)) it.remove();
+        }
+        if (temp.isEmpty())
+            return new String[] {InternalUtils.stripMemberName(fieldName)};
+
+        return temp.toArray(new String[temp.size()]);
+    }
+
+    /**
+     * 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/ComponentWorker.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/transform/ComponentWorker.java?rev=795264&r1=795263&r2=795264&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/transform/ComponentWorker.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/transform/ComponentWorker.java Fri Jul 17 22:53:30 2009
@@ -20,9 +20,11 @@
 import org.apache.tapestry5.internal.KeyValue;
 import org.apache.tapestry5.internal.TapestryInternalUtils;
 import org.apache.tapestry5.ioc.Location;
+import org.apache.tapestry5.ioc.Orderable;
 import org.apache.tapestry5.ioc.internal.services.StringLocation;
 import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
 import org.apache.tapestry5.ioc.internal.util.InternalUtils;
+import org.apache.tapestry5.ioc.internal.util.TapestryException;
 import org.apache.tapestry5.model.ComponentModel;
 import org.apache.tapestry5.model.MutableComponentModel;
 import org.apache.tapestry5.model.MutableEmbeddedComponentModel;
@@ -95,8 +97,20 @@
 
         if (annotation == null) return;
 
-        for (Class c : annotation.value())
-            model.addMixin(c.getName());
+        boolean orderEmpty = annotation.order().length == 0;
+
+        if (!orderEmpty && annotation.order().length != annotation.value().length)
+            throw new TapestryException(TransformMessages.badMixinConstraintLength(annotation,fieldName),
+                    model,null);
+
+
+        for (int i=0; i<annotation.value().length;i++)
+        {
+            String[] constraints = orderEmpty?
+                    new String[0]:
+                    TapestryInternalUtils.splitMixinConstraints(annotation.order()[i]);
+            model.addMixin(annotation.value()[i].getName(), constraints);
+        }
     }
 
     private void addMixinTypes(String fieldName, ClassTransformation transformation,
@@ -108,8 +122,9 @@
 
         for (String typeName : annotation.value())
         {
-            String mixinClassName = resolver.resolveMixinTypeToClassName(typeName);
-            model.addMixin(mixinClassName);
+            Orderable<String> typeAndOrder = TapestryInternalUtils.mixinTypeAndOrder(typeName);
+            String mixinClassName = resolver.resolveMixinTypeToClassName(typeAndOrder.getTarget());
+            model.addMixin(mixinClassName,typeAndOrder.getConstraints());
         }
     }
 

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/transform/MixinWorker.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/transform/MixinWorker.java?rev=795264&r1=795263&r2=795264&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/transform/MixinWorker.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/transform/MixinWorker.java Fri Jul 17 22:53:30 2009
@@ -1,4 +1,4 @@
-// Copyright 2006, 2008 The Apache Software Foundation
+// Copyright 2006, 2008, 2009 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.
@@ -50,12 +50,14 @@
             
             String mixinType = annotation.value();
 
+            String[] order = annotation.order();
+
             String fieldType = transformation.getFieldType(fieldName);
 
             String mixinClassName = InternalUtils.isBlank(mixinType) ? fieldType : resolver
                     .resolveMixinTypeToClassName(mixinType);
 
-            model.addMixinClassName(mixinClassName);
+            model.addMixinClassName(mixinClassName,order);
 
             transformation.makeReadOnly(fieldName);
 

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=795264&r1=795263&r2=795264&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 Jul 17 22:53:30 2009
@@ -16,8 +16,8 @@
 
 import org.apache.tapestry5.Binding;
 import org.apache.tapestry5.annotations.Parameter;
-import org.apache.tapestry5.internal.InternalComponentResources;
-import org.apache.tapestry5.internal.ParameterAccess;
+import org.apache.tapestry5.annotations.BindParameter;
+import org.apache.tapestry5.internal.*;
 import org.apache.tapestry5.internal.bindings.LiteralBinding;
 import org.apache.tapestry5.ioc.internal.util.InternalUtils;
 import org.apache.tapestry5.ioc.util.BodyBuilder;
@@ -35,6 +35,7 @@
 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 BindingSource bindingSource;
 
@@ -84,11 +85,11 @@
 
         String parameterName = getParameterName(name, annotation.name());
 
-        model.addParameter(parameterName, annotation.required(), annotation.allowNull(), annotation.defaultPrefix());
+        boolean cache = annotation.cache();
 
-        String type = transformation.getFieldType(name);
+        model.addParameter(parameterName, annotation.required(), annotation.allowNull(), annotation.defaultPrefix(),cache);
 
-        boolean cache = annotation.cache();
+        String type = transformation.getFieldType(name);
 
         String cachedFieldName = transformation.addField(Modifier.PRIVATE, "boolean", name + "_cached");
 
@@ -133,6 +134,9 @@
         // be used to reset the field after rendering.
 
         builder.addln("%s = %s;", defaultFieldName, fieldName);
+
+        addListenerSetup(fieldName, fieldType, parameterName, accessFieldName, builder, transformation);
+
         builder.end();
 
         transformation.extendMethod(TransformConstants.CONTAINING_PAGE_DID_LOAD_SIGNATURE, builder
@@ -232,9 +236,45 @@
                       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,
+                                 String parameterName, String fieldType, String resourcesFieldName,
                                  ClassTransformation transformation)
     {
         BodyBuilder builder = new BodyBuilder();
@@ -253,11 +293,10 @@
         // 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();
@@ -269,6 +308,17 @@
 
         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);
     }
 
@@ -349,4 +399,9 @@
 
         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=795264&r1=795263&r2=795264&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 Jul 17 22:53:30 2009
@@ -1,4 +1,4 @@
-// Copyright 2008 The Apache Software Foundation
+// Copyright 2008, 2009 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.
@@ -21,6 +21,7 @@
 import org.apache.tapestry5.ioc.internal.util.MessagesImpl;
 import org.apache.tapestry5.runtime.Component;
 import org.apache.tapestry5.services.TransformMethodSignature;
+import org.apache.tapestry5.annotations.MixinClasses;
 
 class TransformMessages
 {
@@ -51,4 +52,10 @@
     {
         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);
+    }
 }

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=795264&r1=795263&r2=795264&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 Jul 17 22:53:30 2009
@@ -167,4 +167,11 @@
      * @return true if event handler present
      */
     boolean handlesEvent(String eventType);
+
+    /**
+     * @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
+     */
+    String[] getOrderForMixin(String mixinClassName);
 }

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/model/EmbeddedComponentModel.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/model/EmbeddedComponentModel.java?rev=795264&r1=795263&r2=795264&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/model/EmbeddedComponentModel.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/model/EmbeddedComponentModel.java Fri Jul 17 22:53:30 2009
@@ -69,4 +69,11 @@
      * @since 5.1.0.0
      */
     List<String> getPublishedParameters();
+
+    /**
+     * @param mixinClassName
+     * @return the ordering constraints for the specified mixin, or null.
+     * @Since 5.2.0.0
+     */
+    String[] getConstraintsForMixin(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=795264&r1=795263&r2=795264&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 Jul 17 22:53:30 2009
@@ -34,10 +34,27 @@
      * @param defaultBindingPrefix the default binding prefix for this parameter @throws IllegalArgumentException if a
      *                             parameter with the given name has already been defined for this model
      * @see Parameter
+     * @deprecated Use {@link #addParameter(String, boolean, boolean, String, boolean)} instead.
      */
     void addParameter(String name, boolean required, boolean allowNull, String defaultBindingPrefix);
 
     /**
+     * Adds a new formal parameter to the model. Each parameter has a unique name (though access to parameters is case
+     * insensitive).
+     *
+     * @param name                 new, unique name for the parameter
+     * @param required             if true, the parameter must be bound
+     * @param allowNull            if true, then parameter may be bound to null, if false a null check will be added
+     * @param defaultBindingPrefix the default binding prefix for this parameter @throws IllegalArgumentException if a
+     *                             parameter with the given name has already been defined for this model
+     * @param cached               if true, the parameter value should be cached within the component during rendering
+     * @see org.apache.tapestry5.annotations.Parameter
+     * @since 5.2.0.0
+     */
+    public void addParameter(String name, boolean required, boolean allowNull, String defaultBindingPrefix,boolean cached);
+
+
+    /**
      * Defines a new embedded component.
      *
      * @param id                        the unique id for the embedded component, which must not already exist.
@@ -66,9 +83,10 @@
     String setFieldPersistenceStrategy(String fieldName, String strategy);
 
     /**
-     * Adds a mixin to the component's implementation.
+     * Adds a mixin to the component's implementation, optionally specifying ordering constraints, as per OrderedConfiguration.
+     * @since 5.2.0.0
      */
-    void addMixinClassName(String mixinClassName);
+    void addMixinClassName(String mixinClassName, String... order);
 
     /**
      * Sets the internal flag to indicate that this model (and all models that extend from it) support informal

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/model/MutableEmbeddedComponentModel.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/model/MutableEmbeddedComponentModel.java?rev=795264&r1=795263&r2=795264&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/model/MutableEmbeddedComponentModel.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/model/MutableEmbeddedComponentModel.java Fri Jul 17 22:53:30 2009
@@ -25,9 +25,9 @@
     void addParameter(String name, String value);
 
     /**
-     * Adds a mixin to the component in terms of its fully qualified class name.
+     * Adds a mixin to the component in terms of its fully qualified class name, with optional ordering constraints.
      */
-    void addMixin(String mixinClassName);
+    void addMixin(String mixinClassName, String... orderingConstraints);
 
     /**
      * Sets the list of published parameters for this embedded component.

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/model/ParameterModel.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/model/ParameterModel.java?rev=795264&r1=795263&r2=795264&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/model/ParameterModel.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/model/ParameterModel.java Fri Jul 17 22:53:30 2009
@@ -1,4 +1,4 @@
-// Copyright 2006, 2008 The Apache Software Foundation
+// Copyright 2006, 2008, 2009 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.
@@ -42,4 +42,10 @@
      * The default binding prefix for the parameter, usually "prop".
      */
     String getDefaultBindingPrefix();
+
+    /**
+     * @return true if the bound-value is cached in the component during rendering.
+     * @since 5.2.0.0
+     */
+    boolean isCached();
 }

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=795264&r1=795263&r2=795264&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 Jul 17 22:53:30 2009
@@ -484,6 +484,12 @@
 
         configuration.addInstance("Parameter", ParameterWorker.class, "after:Inject*");
 
+        //bind parameter should always go after parameter to make sure all parameters
+        //have been properly setup.
+
+        configuration.addInstance("BindParameter",BindParameterWorker.class, "after:Parameter");
+
+
         // Workers for the component rendering state machine methods; this is in typical
         // execution order.
 

Added: tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/internal/pageload/PageloadStrings.properties
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/internal/pageload/PageloadStrings.properties?rev=795264&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/internal/pageload/PageloadStrings.properties (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/internal/pageload/PageloadStrings.properties Fri Jul 17 22:53:30 2009
@@ -0,0 +1,40 @@
+#
+# Copyright 2009 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
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+unique_mixin_required=Mixins applied to a component must be unique. Mixin '%s' has already been applied.
+mixinid_for_paramnotfound="Mixin id for parameter '%s' not found. Attached mixins: %s."
+missing_component_type=You must specify the type via t:type, the element, or @Componentno_more_tokens=No more template tokens.
+could_not_find_override=Could not find an override for extension point '%s'.
+no_parent_for_extension=Component %s uses an extension template, but does not have a parent component.
+token_not_implemented=Not yet implemented: %s
+parameter_not_supported=Component %s does not include a formal parameter '%s' (and does not support informal parameters).
+redundant_embedded_component_types=Embedded component '%s' provides a type attribute in the template ('%s') \
+                                   as well as in the component class ('%s'). You should not provide a type attribute \
+                                   in the template when defining an embedded component within the component class.
+recursive_template=The template for component %s is recursive (contains another direct or indirect reference to \
+                   component %<s). This is not supported (components may not contain themselves).
+composite_render_command_method_not_implemented=RenderQueue method %s() is not implemented for composited render commands.
+exception_assembling_root_component=Exception assembling root component of page %s: %s
+exception_assembling_embedded_component=Exception assembling embedded component '%s' (of type %s, within %s): %s
+embedded_components_not_in_template=Embedded component(s) %s are defined within component class %s \
+                                    (or a super-class of %s), but are not present in the component template (%s).
+parameter_already_published=Parameter '%s' of embedded component '%s' can not be published as a parameter of component \
+                            %s, as it has previously been published by embedded component '%s'.
+failure_creating_embedded_component=Failure creating embedded component '%s' of %s: %s"
+published_parameter_nonexistant=Parameter '%s' of component %s is improperly published from embedded component '%s' \
+                                (where it does not exist). This may be a typo in the publishParameters attribute of \
+                                the @Component annotation.
+

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=795264&r1=795263&r2=795264&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 Jul 17 22:53:30 2009
@@ -35,4 +35,8 @@
 missing-render-variable=Component %s does not contain a stored render variable with name '%s'.  Stored render variables: %s.
 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 newline at end of file
+  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=795264&r1=795263&r2=795264&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 Jul 17 22:53:30 2009
@@ -17,3 +17,5 @@
 cached-no-return-value=@Cached may only be used with methods that return values: %s
 cached-no-parameters=@Cached cannot be used with methods that accept parameters: %s
 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).

Modified: tapestry/tapestry5/trunk/tapestry-core/src/test/app1/ClientPersistenceDemo.tml
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/app1/ClientPersistenceDemo.tml?rev=795264&r1=795263&r2=795264&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/app1/ClientPersistenceDemo.tml (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/app1/ClientPersistenceDemo.tml Fri Jul 17 22:53:30 2009
@@ -10,8 +10,12 @@
   <p>
     Session: [${sessionExists}]
   </p>
-  
-  
+
+
+  <p>
+    <t:actionlink t:id="nixSession">nix session</t:actionlink>
+  </p>
+
   <p>
     <t:actionlink t:id="storeString">store string</t:actionlink>
   </p>
@@ -24,4 +28,5 @@
     <t:pagelink page="clientpersistencedemo">refresh</t:pagelink>
   </p>
 
+
 </html>
\ No newline at end of file

Modified: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/IntegrationTests.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/IntegrationTests.java?rev=795264&r1=795263&r2=795264&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/IntegrationTests.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/IntegrationTests.java Fri Jul 17 22:53:30 2009
@@ -41,6 +41,16 @@
         super("src/test/app1");
     }
 
+
+    @Test(enabled = false)
+    public static void main(String[] args) throws Exception {
+        IntegrationTests it = new IntegrationTests();
+        it.setup();
+        while(true) {
+            Thread.sleep(1000);
+        }
+    }
+
     @Test
     public void assets() throws Exception
     {
@@ -133,12 +143,13 @@
     @Test
     public void exception_report()
     {
+        //mismatched tag.
         start("BadTemplate Page");
 
         assertTextPresent("org.apache.tapestry5.ioc.internal.util.TapestryException",
-                          "Failure parsing template classpath:org/apache/tapestry5/integration/app1/pages/BadTemplate.tml, line 7, column 15",
-                          "<t:foobar>content from template</t:foobar>",
-                          "Element <t:foobar> is in the Tapestry namespace, but is not a recognized Tapestry template element.");
+                          "Failure parsing template classpath:org/apache/tapestry5/integration/app1/pages/BadTemplate.tml: Unexpected close tag </foobar>; expected </t:foobar>",
+                          "classpath:org/apache/tapestry5/integration/app1/pages/BadTemplate.tml, line 6",
+                          "<t:foobar>content from template</foobar>");
     }
 
     @Test
@@ -566,7 +577,7 @@
         // The XPath support is too weak for //div[@class='t-beandisplay-value'][%d], so we
         // just look for the text itself.
 
-        assertTextPresent("Howard", "Lewis Ship", "1966", "Martian", "U. S. Citizen", "***********", "line1", "line2",
+        assertTextPresent("Howard", "Lewis Ship", "1966", "Martian", "U.S. Citizen", "***********", "line1", "line2",
                           "line3");
     }
 
@@ -581,10 +592,11 @@
         type("firstName", "Howard");
         type("lastName", "Lewis Ship");
         type("password", "supersecret");
+        check("citizen");
 
         clickAndWait("//input[@type=\'submit\']");
 
-        assertTextPresent("Howard", "Lewis Ship", "0", "100% He-Man", "U. S. Citizen");
+        assertTextPresent("Howard", "Lewis Ship", "0", "100% He-Man", "U.S. Citizen");
     }
 
     @Test
@@ -847,7 +859,7 @@
 
         clickAndWait(SUBMIT);
 
-        assertTextPresent("Howard", "Lewis Ship", "1966", "U. S. Citizen");
+        assertTextPresent("Howard", "Lewis Ship", "1966", "U.S. Citizen");
     }
 
     @Test
@@ -865,7 +877,7 @@
     {
         start("Renderable Demo");
 
-        assertTextPresent("Renderable Demo", "[proves it works.]");
+        assertTextPresent("Renderable Demo", "[This proves it works.]");
     }
 
     @Test
@@ -912,6 +924,9 @@
     public void client_persistence()
     {
         start("Client Persistence Demo");
+        //can't assume session won't exist because other tests use form components w/ defaults, which means
+        //session creation to store the ValidationTracker. So we explicitly clear the session here.
+        clickAndWait("link=nix session");
 
         assertTextPresent("Persisted value: []", "Session: [false]");
 
@@ -1045,16 +1060,17 @@
         goBack();
         waitForPageToLoad();
 
-        // This has been failing?  Why?
-
-        // clickAndWait("link=URL");
-        // assertTextPresent("Google");
-        // goBack();
-        // waitForPageToLoad();
+        /*
+        clickAndWait("link=URL");
+        assertTextPresent("Google>");
+        goBack();
+        waitForPageToLoad();
+        */
 
         clickAndWait("link=bad");
         assertTextPresent("An unexpected application exception has occurred.",
-                          "An event handler for component org.apache.tapestry5.integration.app1.pages.Index returned the value 20 (from method org.apache.tapestry5.integration.app1.pages.Index.onActionFromBadReturnType() (at Index.java:34)). Return type java.lang.Integer can not be handled.");
+                          "A component event handler method returned the value 20. Return type java.lang.Integer can not be handled.",
+                          "context:ReturnTypes.tml, line 50");
     }
 
     @Test
@@ -1260,7 +1276,7 @@
         start("BeanEditor / Date Demo", "clear");
 
         type("name", "Howard Lewis Ship");
-        type("date", "12/24/66");
+        type("date", "12/24/1966");
 
         clickAndWait(SUBMIT);
 
@@ -1635,7 +1651,7 @@
         clickAndWait("link=force invalid event context");
 
         assertTextPresent("An unexpected application exception has occurred.",
-                          "org.apache.tapestry5.ioc.internal.util.TapestryException",
+                          "org.apache.tapestry5.runtime.ComponentEventException",
                           "java.lang.NumberFormatException");
     }
 
@@ -2362,7 +2378,7 @@
 
         assertTextPresent("org.apache.tapestry5.internal.services.RenderQueueException",
                           "Render queue error in SetupRender[FormFieldOutsideForm:textfield]: The Textfield component must be enclosed by a Form component.",
-                          "context:FormFieldOutsideForm.tml, line 5, column 45");
+                          "context:FormFieldOutsideForm.tml, line 5");
     }
 
     /**
@@ -2968,6 +2984,130 @@
     }
 
     @Test
+    public void bindparameter()
+    {
+        start("BindParameter mixin annotation");
+        //implicit parameter name
+        assertEchoMixins("testmixin","mypropertyvalue",0,-1,-1,1,true);
+        assertText("mypropertyoutput","mypropertyvalue");
+
+        //explicit parameter name
+        assertEchoMixins("testmixin2","10",-1,0,-1,2,true);
+        assertText("mypropertyoutput2","10");
+
+        //multiple parameter names; first one found wins.
+        assertEchoMixins("testmixin3","hello",-1,-1,0,3,true);
+
+        //multiple mixins
+        assertEchoMixins("multimixins","supervalue",0,1,2,3,true);
+        assertText("mypropertyoutput4","supervalue");
+
+        //finally, binding to default bindings (which is tricky because of page load invocation order)
+        assertEchoMixins("defaultbinding","goodbye",0,-1,-1,1,false);
+        assertText("mypropertyoutput5","goodbye");
+    }
+
+    @Test
+    public void bindparameter_nomatchingparameter()
+    {
+        start("BindParameter error handling");
+
+        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]");
+
+    }
+
+    @Test
+    public void bindparameter_on_componentfield_throws_exception()
+    {
+        start("BindParameter on component");
+
+        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");
+    }
+
+    @Test
+    public void mixin_ordering()
+    {
+        //echo => <original>-before, temporaryvaluefromechovaluemixin, <original>-after
+        //echo2 => echo2-<original>-before, "3", echo2-<original>-after
+        //echo3 => echo3-<original>-before, "world", echo3-<original>-after
+        //order1: echo, echo2, echo3
+        start("Mixin Ordering Demo");
+
+        assertMixinOrder(1,0,1,2,3,true);
+        //order2: echo3, echo2, echo
+        assertMixinOrder(2,2,3,0,1,true);
+        //order3: echo2, echo3, echo
+        assertMixinOrder(3,3,0,2,1,true);
+        //order4: echo3, echo, echo2
+        assertMixinOrder(4,3,1,0,2,true);
+        //order5: echo2, echo, echo3
+        assertMixinOrder(5,2,0,1,3,true);
+        //order6: echo, echo3, echo2, TextOnlyOnDisabled
+        assertMixinOrder(6,0,3,1,2,false);
+        //make sure mixin after and mixin before constraints don't interfere...
+        //order7: echo, echo2 <corecomponent> echoafter2, echoafter
+        assertMixinOrder(7,0,1,-1,2,true);
+        assertText("order7_before_but_after","afterrender_for_mixinafter_isreally_justbefore_corecomponent_afterrender-before");
+        assertText("order7_after_but_before","afterrender_for_mixinafter_isreally_justbefore_corecomponent_afterrender-after");
+        //echoafter2 should have for its value at the point it renders
+        //the value that echo2 sets, since the core component isn't changing its value.
+        assertText("order7_before_but_after2","3-before");
+        assertText("order7_after_but_before2","3-after");
+    }
+
+    private void assertMixinOrder(int orderNum, int echo1From, int echo2From, int echo3From, int fieldFrom, boolean isField)
+    {
+        assertEchoMixins("order" + orderNum,"batman", echo1From,echo2From,echo3From,fieldFrom,isField);
+    }
+
+    /**
+     * asserts that the "echo value" mixins are properly functioning (ie @BindParameter, and mixin ordering).
+     * each integer value specifies the echo mixin number (echovalue => 1, echovalue2 => 2, echovalue3 => 3; 0 is the original value)
+     * from which the specified echo mixin is expected to "receive" its value. So if echo1From is 2, then the "original value"
+     * printed by echo1 is expected to be the value set by echo2. If a given "from" is < 0, checking the corresponding mixin values is disabled.
+     */
+
+    private void assertEchoMixins(String fieldName, String originalValue, int echo1From, int echo2From, int echo3From, int fieldFrom, boolean isField)
+    {
+        String[] vals = {originalValue,"temporaryvaluefromechovaluemixin","3","world"};
+        String before = fieldName + "_before";
+        String after = fieldName + "_after";
+        if (echo1From > -1)
+        {
+            assertText(before,vals[echo1From] + "-before");
+            assertText(after,vals[echo1From] + "-after");
+        }
+        if (echo2From > -1)
+        {
+            assertText(before + "2","echo2-" + vals[echo2From] + "-before");
+            assertText(after + "2","echo2-" + vals[echo2From] + "-after");
+        }
+        if (echo3From > -1)
+        {
+            assertText(before + "3","echo3-" + vals[echo3From] + "-before");
+            assertText(after + "3","echo3-" + vals[echo3From] + "-after");
+        }
+        if (isField)
+            assertFieldValue(fieldName,vals[fieldFrom]);
+        else
+            assertText(fieldName,vals[fieldFrom]);
+    }
+
+
+    @Test
+    public void missing_componentclass()
+    {
+        start("Missing Component Class Exception");
+        assertTextPresent(
+                "An unexpected application exception has occurred",
+                "Failure creating embedded component 'componentwithnotype' of org.apache.tapestry5.integration.app1.pages.MissingComponentClassException: You must specify the type via t:type, the element, or @Component");
+    }
+
+    @Test
     public void session_attribute()
     {
         start("SessionAttribute Demo");
@@ -2980,4 +3120,4 @@
         assertTextPresent("read Foo");
         assertTextPresent("read Bar");
     }
-}
\ No newline at end of file
+}

Added: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/components/BindParameterComponent.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/components/BindParameterComponent.java?rev=795264&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/components/BindParameterComponent.java (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/components/BindParameterComponent.java Fri Jul 17 22:53:30 2009
@@ -0,0 +1,28 @@
+// Copyright 2009 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
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry5.integration.app1.components;
+
+import org.apache.tapestry5.annotations.BindParameter;
+import org.apache.tapestry5.MarkupWriter;
+
+/**
+ * @BindParameter should only be used inside a mixin; should get an intelligible exception when trying to use this component.
+ */
+public class BindParameterComponent
+{
+
+    @BindParameter
+    private Object value;
+}

Added: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/components/BindParameterComponentContainer.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/components/BindParameterComponentContainer.java?rev=795264&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/components/BindParameterComponentContainer.java (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/components/BindParameterComponentContainer.java Fri Jul 17 22:53:30 2009
@@ -0,0 +1,31 @@
+// Copyright 2009 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
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry5.integration.app1.components;
+
+import org.apache.tapestry5.annotations.Parameter;
+import org.apache.tapestry5.annotations.MixinAfter;
+
+/**
+ * Used to help prove that BindParameter on a component field throws an intelligible exception, even if the containing
+ * resources actually do contain a declared parameter of the appropriate name.
+ */
+public class BindParameterComponentContainer
+{
+
+    @Parameter("literal:testvalue")
+    private String value;
+
+
+}

Added: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/components/TextOnlyOnDisabledTextField.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/components/TextOnlyOnDisabledTextField.java?rev=795264&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/components/TextOnlyOnDisabledTextField.java (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/components/TextOnlyOnDisabledTextField.java Fri Jul 17 22:53:30 2009
@@ -0,0 +1,30 @@
+// Copyright 2009 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
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry5.integration.app1.components;
+
+import org.apache.tapestry5.corelib.components.TextField;
+import org.apache.tapestry5.annotations.Mixin;
+import org.apache.tapestry5.integration.app1.mixins.TextOnlyOnDisabled;
+
+/**
+ *
+ */
+public class TextOnlyOnDisabledTextField extends TextField
+{
+
+    @Mixin(order = "after:*")
+    private TextOnlyOnDisabled theMixin;
+    
+}

Added: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/mixins/EchoAfter.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/mixins/EchoAfter.java?rev=795264&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/mixins/EchoAfter.java (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/mixins/EchoAfter.java Fri Jul 17 22:53:30 2009
@@ -0,0 +1,56 @@
+// Copyright 2009 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
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry5.integration.app1.mixins;
+
+import org.apache.tapestry5.annotations.*;
+import org.apache.tapestry5.MarkupWriter;
+import org.apache.tapestry5.ComponentResources;
+import org.apache.tapestry5.Field;
+import org.apache.tapestry5.ioc.annotations.Inject;
+
+/**
+ * Mixin demonstrating the use of the BindParameter annotation, using implicit parent-parameter naming.
+ * It echos the current value, changes said value for the duration of the component
+ * render, then changes it back and re-echos it.
+ */
+@MixinAfter
+public class EchoAfter
+{
+    @BindParameter
+    private String value;
+
+    private String temp;
+
+    @InjectContainer
+    private Field field;
+
+    @BeginRender
+    void beginRender(MarkupWriter writer)
+    {
+        writer.element("div","id",field.getClientId() + "_before_but_after");
+        writer.writeRaw(value + "-before");
+        writer.end();
+        temp = value;
+        value = "beginrender_for_mixinafter_isreally_justafter_corecomponent_render";
+    }
+
+    @AfterRender
+    void afterRender(MarkupWriter writer) {
+        value = temp;
+        writer.element("div","id",field.getClientId() + "_after_but_before");
+        writer.writeRaw(value + "-after");
+        writer.end();
+    }
+}
\ No newline at end of file

Added: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/mixins/EchoAfter2.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/mixins/EchoAfter2.java?rev=795264&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/mixins/EchoAfter2.java (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/mixins/EchoAfter2.java Fri Jul 17 22:53:30 2009
@@ -0,0 +1,56 @@
+// Copyright 2009 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
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry5.integration.app1.mixins;
+
+import org.apache.tapestry5.annotations.*;
+import org.apache.tapestry5.MarkupWriter;
+import org.apache.tapestry5.ComponentResources;
+import org.apache.tapestry5.Field;
+import org.apache.tapestry5.ioc.annotations.Inject;
+
+/**
+ * Mixin demonstrating the use of the BindParameter annotation, using implicit parent-parameter naming.
+ * It echos the current value, changes said value for the duration of the component
+ * render, then changes it back and re-echos it.
+ */
+@MixinAfter
+public class EchoAfter2
+{
+    @BindParameter
+    private String value;
+
+    private String temp;
+
+    @InjectContainer
+    private Field field;
+
+    @BeginRender
+    void beginRender(MarkupWriter writer)
+    {
+        writer.element("div","id",field.getClientId() + "_before_but_after2");
+        writer.writeRaw(value + "-before");
+        writer.end();
+        temp = value;
+        value = "afterrender_for_mixinafter_isreally_justbefore_corecomponent_afterrender";
+    }
+
+    @AfterRender
+    void afterRender(MarkupWriter writer) {
+        value = temp;
+        writer.element("div","id",field.getClientId() + "_after_but_before2");
+        writer.writeRaw(value + "-after");
+        writer.end();
+    }
+}
\ No newline at end of file

Added: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/mixins/EchoValue.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/mixins/EchoValue.java?rev=795264&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/mixins/EchoValue.java (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/mixins/EchoValue.java Fri Jul 17 22:53:30 2009
@@ -0,0 +1,55 @@
+// Copyright 2009 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
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry5.integration.app1.mixins;
+
+import org.apache.tapestry5.annotations.*;
+import org.apache.tapestry5.MarkupWriter;
+import org.apache.tapestry5.ComponentResources;
+import org.apache.tapestry5.Field;
+import org.apache.tapestry5.ioc.annotations.Inject;
+
+/**
+ * Mixin demonstrating the use of the BindParameter annotation, using implicit parent-parameter naming.
+ * It echos the current value, changes said value for the duration of the component
+ * render, then changes it back and re-echos it.
+ */
+public class EchoValue
+{
+    @BindParameter
+    private String value;
+
+    private String temp;
+
+    @InjectContainer
+    private Field field;
+
+    @BeginRender
+    void beginRender(MarkupWriter writer)
+    {
+        writer.element("div","id",field.getClientId() + "_before");
+        writer.writeRaw(value + "-before");
+        writer.end();
+        temp = value;
+        value = "temporaryvaluefromechovaluemixin";
+    }
+
+    @AfterRender
+    void afterRender(MarkupWriter writer) {
+        value = temp;
+        writer.element("div","id",field.getClientId() + "_after");
+        writer.writeRaw(value + "-after");
+        writer.end();
+    }
+}

Added: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/mixins/EchoValue2.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/mixins/EchoValue2.java?rev=795264&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/mixins/EchoValue2.java (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/mixins/EchoValue2.java Fri Jul 17 22:53:30 2009
@@ -0,0 +1,51 @@
+// Copyright 2009 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
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry5.integration.app1.mixins;
+
+import org.apache.tapestry5.annotations.BindParameter;
+import org.apache.tapestry5.annotations.InjectContainer;
+import org.apache.tapestry5.MarkupWriter;
+import org.apache.tapestry5.ClientElement;
+
+/**
+ * Mixin demonstrating the use of BindParameter, using explicit naming of the parent parameter.
+ */
+public class EchoValue2
+{
+    @BindParameter(value = "value")
+    private Object boundParameter;
+
+    @InjectContainer
+    private ClientElement element;
+
+    private Object temp;
+
+    void beginRender(MarkupWriter writer)
+    {
+        writer.element("div","id",element.getClientId() + "_before2");
+        writer.writeRaw("echo2-" + boundParameter + "-before");
+        writer.end();
+        temp = boundParameter;
+        boundParameter = "3";
+    }
+
+    void afterRender(MarkupWriter writer)
+    {
+        boundParameter = temp;
+        writer.element("div","id",element.getClientId() + "_after2");
+        writer.writeRaw("echo2-" + boundParameter + "-after");
+        writer.end();
+    }
+}

Added: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/mixins/EchoValue3.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/mixins/EchoValue3.java?rev=795264&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/mixins/EchoValue3.java (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/mixins/EchoValue3.java Fri Jul 17 22:53:30 2009
@@ -0,0 +1,51 @@
+// Copyright 2009 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
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry5.integration.app1.mixins;
+
+import org.apache.tapestry5.annotations.BindParameter;
+import org.apache.tapestry5.annotations.InjectContainer;
+import org.apache.tapestry5.MarkupWriter;
+import org.apache.tapestry5.ClientElement;
+
+/**
+ * Mixin demonstrating the use of BindParameter, using explicit naming of the parent parameter.
+ */
+public class EchoValue3
+{
+    @BindParameter(value = {"object","value"})
+    private Object boundParameter;
+
+    @InjectContainer
+    private ClientElement element;
+
+    private Object temp;
+
+    void beginRender(MarkupWriter writer)
+    {
+        writer.element("div","id",element.getClientId() + "_before3");
+        writer.writeRaw("echo3-" + boundParameter + "-before");
+        writer.end();
+        temp = boundParameter;
+        boundParameter = "world";
+    }
+
+    void afterRender(MarkupWriter writer)
+    {
+        boundParameter = temp;
+        writer.element("div","id",element.getClientId() + "_after3");
+        writer.writeRaw("echo3-" + boundParameter + "-after");
+        writer.end();
+    }
+}
\ No newline at end of file

Added: 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=795264&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/mixins/TextOnlyOnDisabled.java (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/mixins/TextOnlyOnDisabled.java Fri Jul 17 22:53:30 2009
@@ -0,0 +1,65 @@
+// Copyright 2009 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
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry5.integration.app1.mixins;
+
+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 
+ */
+public class TextOnlyOnDisabled
+{
+    @BindParameter
+    private Object value;
+
+    @BindParameter
+    private boolean disabled;
+
+
+    @BindParameter
+    private FieldTranslator translate;
+
+    @Inject
+    private TypeCoercer coercer;
+
+    @InjectContainer
+    private ClientElement field;
+
+    @Inject
+    private ComponentResources resources;
+
+    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());
+            writer.write(translate.toClient(value));
+            return false;
+        }
+        return null;
+    }
+
+}

Added: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/BindParameterDemo.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/BindParameterDemo.java?rev=795264&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/BindParameterDemo.java (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/BindParameterDemo.java Fri Jul 17 22:53:30 2009
@@ -0,0 +1,50 @@
+// Copyright 2009 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
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry5.integration.app1.pages;
+
+import org.apache.tapestry5.annotations.Property;
+import org.apache.tapestry5.annotations.SetupRender;
+
+/**
+ * Page for demonstrating/testing the use of the BindParameter mixin demonstration.
+ */
+public class BindParameterDemo
+{
+
+    @Property
+    private String myproperty;
+
+    @Property
+    private Integer myproperty2;
+
+    @Property
+    private String myproperty3;
+
+    @Property
+    private String myproperty4;
+
+    @Property
+    private String myproperty5;
+    
+    @SetupRender
+    void initMyprop()
+    {
+        myproperty="mypropertyvalue";
+        myproperty2=10;
+        myproperty3="hello";
+        myproperty4="supervalue";
+        myproperty5="goodbye";
+    }
+}

Added: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/BindParameterNoSuchParameter.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/BindParameterNoSuchParameter.java?rev=795264&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/BindParameterNoSuchParameter.java (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/BindParameterNoSuchParameter.java Fri Jul 17 22:53:30 2009
@@ -0,0 +1,22 @@
+// Copyright 2009 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
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry5.integration.app1.pages;
+
+/**
+ *
+ */
+public class BindParameterNoSuchParameter
+{
+}

Added: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/BindParameterOnComponent.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/BindParameterOnComponent.java?rev=795264&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/BindParameterOnComponent.java (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/BindParameterOnComponent.java Fri Jul 17 22:53:30 2009
@@ -0,0 +1,24 @@
+// Copyright 2009 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
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry5.integration.app1.pages;
+
+import org.apache.tapestry5.annotations.Property;
+
+/**
+ *
+ */
+public class BindParameterOnComponent
+{
+}

Modified: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/ClientPersistenceDemo.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/ClientPersistenceDemo.java?rev=795264&r1=795263&r2=795264&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/ClientPersistenceDemo.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/ClientPersistenceDemo.java Fri Jul 17 22:53:30 2009
@@ -1,4 +1,4 @@
-// Copyright 2007 The Apache Software Foundation
+// Copyright 2007, 2009 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.
@@ -15,8 +15,10 @@
 package org.apache.tapestry5.integration.app1.pages;
 
 import org.apache.tapestry5.annotations.Persist;
+
 import org.apache.tapestry5.ioc.annotations.Inject;
 import org.apache.tapestry5.services.Request;
+import org.apache.tapestry5.services.Session;
 
 public class ClientPersistenceDemo
 {
@@ -33,7 +35,7 @@
 
     public boolean getSessionExists()
     {
-        return request.getSession(false) != null;
+        return session() != null;
     }
 
     void onActionFromStoreString()
@@ -50,4 +52,17 @@
             }
         };
     }
+
+    void onActionFromNixSession()
+    {
+        if (getSessionExists() && !session().isInvalidated())
+        {
+            session().invalidate();
+        }
+    }
+
+    private Session session()
+    {
+        return request.getSession(false);
+    }
 }

Modified: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/Index.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/Index.java?rev=795264&r1=795263&r2=795264&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/Index.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/Index.java Fri Jul 17 22:53:30 2009
@@ -357,6 +357,26 @@
                      "RenderClientId Mixin",
                      "Force render of client-side id of a client element via the RenderClientId mixin"),
 
+            new Item("BindParameterDemo",
+                     "BindParameter mixin annotation",
+                     "Accessing component parameter values from a mixin"),
+
+            new Item("BindParameterNoSuchParameter",
+                     "BindParameter error handling",
+                     "BindParameter throws exception if the containing component doesn't have a matching parameter"),
+
+            new Item("BindParameterOnComponent",
+                      "BindParameter on component",
+                      "Verify that BindParameter can only be used on mixin fields"),
+
+            new Item("MixinOrderingDemo",
+                     "Mixin Ordering Demo",
+                     "Various mixin-ordering scenarios"),
+
+            new Item("MissingComponentClassException",
+                     "Missing Component Class Exception",
+                     "Meaningful exception message thrown when component class can't be determined from template or field in containing component."),
+
             new Item("SessionAttributeDemo",
                      "SessionAttribute Demo",
                      "Annotation to map a field to a specific session attribute")

Added: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/MissingComponentClassException.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/MissingComponentClassException.java?rev=795264&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/MissingComponentClassException.java (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/MissingComponentClassException.java Fri Jul 17 22:53:30 2009
@@ -0,0 +1,22 @@
+// Copyright 2009 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
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry5.integration.app1.pages;
+
+/**
+ *
+ */
+public class MissingComponentClassException
+{
+}

Added: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/MixinOrderingDemo.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/MixinOrderingDemo.java?rev=795264&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/MixinOrderingDemo.java (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/MixinOrderingDemo.java Fri Jul 17 22:53:30 2009
@@ -0,0 +1,58 @@
+// Copyright 2009 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
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry5.integration.app1.pages;
+
+import org.apache.tapestry5.annotations.*;
+import org.apache.tapestry5.corelib.components.TextField;
+import org.apache.tapestry5.integration.app1.mixins.EchoValue;
+import org.apache.tapestry5.integration.app1.mixins.EchoValue2;
+import org.apache.tapestry5.integration.app1.components.TextOnlyOnDisabledTextField;
+
+/**
+ * Page for demonstrating/testing the use of the BindParameter mixin demonstration.
+ */
+public class MixinOrderingDemo
+{
+
+    @Property
+    private String myproperty;
+
+    @Component
+    @Mixins("echovalue2::before:echovalue3")
+    @MixinClasses(value={EchoValue.class},order={"after:echovalue2;after:echovalue3"})
+    private TextField order3;
+
+    @Component
+    @Mixins("echovalue2::after:echovalue")
+    @MixinClasses(EchoValue.class)
+    private TextField order4;
+
+    @Component
+    @Mixins("echovalue2")
+    @MixinClasses(value=EchoValue.class,order={"after:echovalue2"})
+    private TextField order5;
+
+
+    @Component
+    @Mixins("echovalue3::before:echovalue2")
+    @MixinClasses(value=EchoValue2.class,order="after:echovalue")
+    private TextOnlyOnDisabledTextField order6;
+
+    @SetupRender
+    void initMyprop()
+    {
+        myproperty="batman";
+    }
+}
\ No newline at end of file

Modified: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/TemplateParserImplTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/TemplateParserImplTest.java?rev=795264&r1=795263&r2=795264&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/TemplateParserImplTest.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/TemplateParserImplTest.java Fri Jul 17 22:53:30 2009
@@ -910,7 +910,7 @@
 
         ExtensionPointToken expansion = get(template.getTokens(), 2);
 
-        assertEquals(expansion.getExtentionPointId(), "title");
+        assertEquals(expansion.getExtensionPointId(), "title");
 
         List<TemplateToken> title = template.getExtensionPointTokens("title");
 



Mime
View raw message