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 2011/10/03 23:22:19 UTC

svn commit: r1178584 - in /tapestry/tapestry5/trunk/tapestry-core/src: main/java/org/apache/tapestry5/internal/pageload/ main/resources/org/apache/tapestry5/internal/pageload/ test/groovy/org/apache/tapestry5/integration/app1/ test/java/org/apache/tape...

Author: hlship
Date: Mon Oct  3 21:22:18 2011
New Revision: 1178584

URL: http://svn.apache.org/viewvc?rev=1178584&view=rev
Log:
TAP5-1680: A mixin with a formal parameter will prevent an informal parameter of the same name from being bound on the component

Added:
    tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/mixins/AltTitle.java
    tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/MixinVsInformalParameter.java
    tapestry/tapestry5/trunk/tapestry-core/src/test/resources/org/apache/tapestry5/integration/app1/pages/MixinVsInformalParameter.tml
Modified:
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/ComponentAssemblerImpl.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/EmbeddedComponentAssembler.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/EmbeddedComponentAssemblerImpl.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/PageloadMessages.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/internal/pageload/PageloadStrings.properties
    tapestry/tapestry5/trunk/tapestry-core/src/test/groovy/org/apache/tapestry5/integration/app1/ParameterTests.groovy
    tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/Index.java

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/ComponentAssemblerImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/ComponentAssemblerImpl.java?rev=1178584&r1=1178583&r2=1178584&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/ComponentAssemblerImpl.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/ComponentAssemblerImpl.java Mon Oct  3 21:22:18 2011
@@ -286,6 +286,7 @@ class ComponentAssemblerImpl implements 
                 throw new TapestryException(
                         PageloadMessages.missingComponentType(), location, null);
             }
+
             EmbeddedComponentAssemblerImpl embedded = new EmbeddedComponentAssemblerImpl(assemblerSource,
                     instantiatorSource, componentClassResolver, componentClassName, getSelector(), embeddedModel,
                     mixins, location);

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/EmbeddedComponentAssembler.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/EmbeddedComponentAssembler.java?rev=1178584&r1=1178583&r2=1178584&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/EmbeddedComponentAssembler.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/EmbeddedComponentAssembler.java Mon Oct  3 21:22:18 2011
@@ -33,7 +33,9 @@ interface EmbeddedComponentAssembler ext
      * Creates a binder that can later be used to bind the parameter. The parameter name may be unqualified ("value") or
      * have a mixin prefix ("mymixin.value").  In the former case, the correct mixin is located (though the more typical
      * case is to bind a parameter of the component itself, not a parameter of a mixin attached to the component). In
-     * the latter case, the mixinId is validated (to ensure it exists).
+     * the latter case, the mixinId is validated (to ensure it exists). In addition, a special mixinid that matches the
+     * component's class name can be used; this is necessary to disambiguate informal parameters of the component from formal mixin parameters
+     * (where an unqualified name would be bound to the mixin's parameter).
      * <p/>
      * If the name of the parameter does not match a formal parameter of the component (or mixin) and the component (or
      * mixin) does not support informal parameters, then null is returned.
@@ -41,8 +43,7 @@ interface EmbeddedComponentAssembler ext
      * This method should only be called at page-assembly time as it requires some data that is collected during
      * ComponentAssembly construction in order to handle published parameters of embedded components.
      *
-     * @param parameterName
-     *         simple or qualified parameter name
+     * @param parameterName simple or qualified parameter name
      * @return object that can bind the parameter
      */
     ParameterBinder createParameterBinder(String parameterName);
@@ -62,8 +63,7 @@ interface EmbeddedComponentAssembler ext
     /**
      * Adds mixins to the newly created embedded element.
      *
-     * @param newElement
-     *         new element requiring mixins
+     * @param newElement new element requiring mixins
      */
     void addMixinsToElement(ComponentPageElement newElement);
 

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/EmbeddedComponentAssemblerImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/EmbeddedComponentAssemblerImpl.java?rev=1178584&r1=1178583&r2=1178584&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/EmbeddedComponentAssemblerImpl.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/EmbeddedComponentAssemblerImpl.java Mon Oct  3 21:22:18 2011
@@ -57,24 +57,19 @@ public class EmbeddedComponentAssemblerI
 
     private final String informalParametersMixinId;
 
+    private final String componentPsuedoMixinId;
+
     private Map<String, Boolean> bound;
 
     /**
      * @param assemblerSource
-     * @param instantiatorSource
-     *         used to access component models
-     * @param componentClassResolver
-     *         used to convert mixin types to component models
-     * @param componentClassName
-     *         class name of embedded component
-     * @param selector
-     *         used to select template and other resources
-     * @param embeddedModel
-     *         embedded model (may be null for components defined in the template)
-     * @param templateMixins
-     *         list of mixins from the t:mixins element (possibly null)
-     * @param location
-     *         location of components element in its container's template
+     * @param instantiatorSource     used to access component models
+     * @param componentClassResolver used to convert mixin types to component models
+     * @param componentClassName     class name of embedded component
+     * @param selector               used to select template and other resources
+     * @param embeddedModel          embedded model (may be null for components defined in the template)
+     * @param templateMixins         list of mixins from the t:mixins element (possibly null)
+     * @param location               location of components element in its container's template
      */
     public EmbeddedComponentAssemblerImpl(ComponentAssemblerSource assemblerSource,
                                           ComponentInstantiatorSource instantiatorSource, ComponentClassResolver componentClassResolver,
@@ -106,7 +101,7 @@ public class EmbeddedComponentAssemblerI
             }
         }
 
-        // And the template may include a t:mixins element to define yet more mixin.
+        // And the template may include a t:mixins element to define yet more mixins.
         // Template strings specified as:
         for (String mixinDef : TapestryInternalUtils.splitAtCommas(templateMixins))
         {
@@ -116,6 +111,12 @@ public class EmbeddedComponentAssemblerI
             addMixin(className, order.getConstraints());
         }
 
+        // Finally (new in 5.3, for TAP5-1680), the component itself can sometimes acts as a mixin;
+        // this allows for dealing with parameter name conflicts between the component and the mixin
+        // (especially where informal parameters are involved).
+
+        componentPsuedoMixinId = InternalUtils.lastTerm(componentClassName);
+
         informalParametersMixinId = prescanMixins();
 
     }
@@ -182,51 +183,116 @@ public class EmbeddedComponentAssemblerI
         return assemblerSource.getAssembler(componentModel.getComponentClassName(), selector);
     }
 
-    public ParameterBinder createParameterBinder(String parameterName)
+
+    public ParameterBinder createParameterBinder(String qualifiedParameterName)
     {
-        int dotx = parameterName.indexOf('.');
-        if (dotx >= 0)
-        {
-            String mixinId = parameterName.substring(0, dotx);
-            if (!mixinIdToInstantiator.containsKey(mixinId))
-            {
-                throw new TapestryException(
-                        PageloadMessages.mixinidForParamnotfound(parameterName, mixinIdToInstantiator.keySet()), location,
-                        null);
-            }
-        } else
+        int dotx = qualifiedParameterName.indexOf('.');
+
+        if (dotx < 0)
         {
-            // Unqualified parameter name. May be a reference not to a parameter of this component, but a published
-            // parameter of a component embedded in this component. The ComponentAssembler for this component
-            // will know.
+            return createParameterBinderFromSimpleParameterName(qualifiedParameterName);
+        }
+
+        return createParameterBinderFromQualifiedParameterName(qualifiedParameterName, qualifiedParameterName.substring(0, dotx),
+                qualifiedParameterName.substring(dotx + 1));
+    }
 
-            ComponentAssembler assembler = assemblerSource.getAssembler(componentModel.getComponentClassName(),
-                    selector);
+    private ParameterBinder createParameterBinderFromSimpleParameterName(String parameterName)
+    {
 
-            ParameterBinder binder = assembler.getBinder(parameterName);
+        // Look for a *formal* parameter with the simple name on the component itself.
 
-            if (binder != null)
-                return binder;
+        ParameterBinder binder = getComponentAssembler().getBinder(parameterName);
+
+        if (binder != null)
+        {
+            return binder;
         }
 
-        final ParameterBinder binder = parameterNameToBinder.get(parameterName);
+        // Next see if any mixin has a formal parameter with this simple name.
+
+        binder = parameterNameToBinder.get(parameterName);
 
         if (binder != null)
+        {
             return binder;
+        }
 
-        // Informal parameter: Is there a mixin for that?
+
+        // So, is there an mixin that's claiming all informal parameters?
 
         if (informalParametersMixinId != null)
+        {
             return new ParameterBinderImpl(informalParametersMixinId, parameterName, null);
+        }
 
+        // Maybe the component claims informal parameters?
         if (componentModel.getSupportsInformalParameters())
             return new ParameterBinderImpl(null, parameterName, null);
 
-        // Otherwise, informal parameter and not supported by the component or any mixin.
+        // Otherwise, informal parameter are not supported by the component or any mixin.
 
         return null;
     }
 
+    private ParameterBinder createParameterBinderFromQualifiedParameterName(String qualifiedParameterName, String mixinId, String parameterName)
+    {
+
+        if (mixinId.equalsIgnoreCase(componentPsuedoMixinId))
+        {
+            return createParameterBinderForComponent(qualifiedParameterName, parameterName);
+        }
+
+        if (!mixinIdToInstantiator.containsKey(mixinId))
+        {
+            throw new TapestryException(
+                    String.format("Mixin id for parameter '%s' not found. Attached mixins: %s.", qualifiedParameterName,
+                            InternalUtils.joinSorted(mixinIdToInstantiator.keySet())), location,
+                    null);
+        }
+
+        ParameterBinder binder = parameterNameToBinder.get(qualifiedParameterName);
+
+        if (binder != null)
+        {
+            return binder;
+        }
+
+        // Ok, so perhaps this is a qualified name for an informal parameter of the mixin.
+
+        Instantiator instantiator = mixinIdToInstantiator.get(mixinId);
+
+        assert instantiator != null;
+
+        return bindInformalParameter(qualifiedParameterName, mixinId, parameterName, instantiator.getModel());
+    }
+
+    private ParameterBinder bindInformalParameter(String qualifiedParameterName, String mixinId, String parameterName, ComponentModel model)
+    {
+        if (model.getSupportsInformalParameters())
+        {
+            return new ParameterBinderImpl(mixinId, parameterName, null);
+        }
+
+        // Pretty sure this was not caught as an error in 5.2.
+
+        throw new TapestryException(String.format("Binding parameter %s as an informal parameter does not make sense, as %s does not support informal parameters.",
+                qualifiedParameterName, model.getComponentClassName()), location, null);
+    }
+
+    private ParameterBinder createParameterBinderForComponent(String qualifiedParameterName, String parameterName)
+    {
+        ParameterBinder binder = getComponentAssembler().getBinder(parameterName);
+
+        if (binder != null)
+        {
+            return binder;
+        }
+
+        return bindInformalParameter(qualifiedParameterName, null, parameterName, componentModel);
+    }
+
+
     public boolean isBound(String parameterName)
     {
         return InternalUtils.get(bound, parameterName) != null;

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/PageloadMessages.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/PageloadMessages.java?rev=1178584&r1=1178583&r2=1178584&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/PageloadMessages.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/PageloadMessages.java Mon Oct  3 21:22:18 2011
@@ -14,17 +14,15 @@
 
 package org.apache.tapestry5.internal.pageload;
 
+import org.apache.tapestry5.internal.parser.TokenType;
 import org.apache.tapestry5.ioc.Messages;
 import org.apache.tapestry5.ioc.Resource;
 import org.apache.tapestry5.ioc.internal.util.MessagesImpl;
-import org.apache.tapestry5.ioc.internal.util.InternalUtils;
-import org.apache.tapestry5.internal.parser.TokenType;
 import org.apache.tapestry5.model.ComponentModel;
 
-import java.util.Collection;
-
 /**
  * Localized exception message support for pageload-related classes.
+ *
  * @since 5.2.0
  */
 final class PageloadMessages
@@ -41,11 +39,6 @@ final class PageloadMessages
         return MESSAGES.format("unique_mixin_required", mixinId);
     }
 
-    public static String mixinidForParamnotfound(String parameterName, Collection<String> availableMixins)
-    {
-        return MESSAGES.format("mixinid_for_paramnotfound", parameterName, InternalUtils.joinSorted(availableMixins));
-    }
-
     public static String missingComponentType()
     {
         return MESSAGES.get("missing_component_type");
@@ -83,12 +76,12 @@ final class PageloadMessages
 
     public static String compositeRenderCommandMethodNotImplemented(String methodName)
     {
-        return MESSAGES.format("composite_render_command_method_not_implemented",methodName);
+        return MESSAGES.format("composite_render_command_method_not_implemented", methodName);
     }
 
     public static String exceptionAssemblingRootComponent(String pageName, String exceptionMessage)
     {
-        return MESSAGES.format("exception_assembling_root_component",pageName,exceptionMessage);
+        return MESSAGES.format("exception_assembling_root_component", pageName, exceptionMessage);
     }
 
     public static String exceptionAssemblingEmbeddedComponent(
@@ -118,7 +111,7 @@ final class PageloadMessages
     }
 
     public static String parameterAlreadyPublished(
-            String publishedParameterName, 
+            String publishedParameterName,
             String embeddedId,
             String componentClassName,
             String existingEmbeddedId)
@@ -132,7 +125,7 @@ final class PageloadMessages
 
     public static String failureCreatingEmbeddedComponent(String embeddedId, String containerClass, String exception)
     {
-        return MESSAGES.format("failure_creating_embedded_component",embeddedId, containerClass, exception);
+        return MESSAGES.format("failure_creating_embedded_component", embeddedId, containerClass, exception);
     }
 
     public static String publishedParameterNonexistant(String parameterName, String publishingClass, String embeddedId)

Modified: 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=1178584&r1=1178583&r2=1178584&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/internal/pageload/PageloadStrings.properties (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/internal/pageload/PageloadStrings.properties Mon Oct  3 21:22:18 2011
@@ -15,7 +15,6 @@
 #
 
 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 @Component annotation.
 no_more_tokens=No more template tokens.
 could_not_find_override=Could not find an override for extension point '%s'.

Modified: tapestry/tapestry5/trunk/tapestry-core/src/test/groovy/org/apache/tapestry5/integration/app1/ParameterTests.groovy
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/groovy/org/apache/tapestry5/integration/app1/ParameterTests.groovy?rev=1178584&r1=1178583&r2=1178584&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/groovy/org/apache/tapestry5/integration/app1/ParameterTests.groovy (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/groovy/org/apache/tapestry5/integration/app1/ParameterTests.groovy Mon Oct  3 21:22:18 2011
@@ -57,4 +57,18 @@ class ParameterTests extends TapestryCor
 
         assertTextPresent "Parameter 'value' of component class org.apache.tapestry5.integration.app1.components.ParameterSubClass conflicts with the parameter defined by the org.apache.tapestry5.integration.app1.base.ParameterBaseClass base class."
     }
+
+    /**
+     * https://issues.apache.org/jira/browse/TAP5-1680
+     */
+    @Test
+    void use_component_class_name_to_disambiguate_informal_parameter()
+    {
+        openLinks "Mixin Parameter vs. Informal Parameter"
+
+        // Why frog?  I don't know.
+
+        assertAttribute "//a[@id='frog']/@alt", "Alt Title"
+        assertAttribute "//a[@id='frog']/@title", "Frog Title"
+    }
 }

Added: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/mixins/AltTitle.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/mixins/AltTitle.java?rev=1178584&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/mixins/AltTitle.java (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/mixins/AltTitle.java Mon Oct  3 21:22:18 2011
@@ -0,0 +1,32 @@
+package org.apache.tapestry5.integration.app1.mixins;
+
+import org.apache.tapestry5.BindingConstants;
+import org.apache.tapestry5.ClientElement;
+import org.apache.tapestry5.MarkupWriter;
+import org.apache.tapestry5.annotations.InjectContainer;
+import org.apache.tapestry5.annotations.MixinAfter;
+import org.apache.tapestry5.annotations.Parameter;
+
+/**
+ * Used to test https://issues.apache.org/jira/browse/TAP5-1680.
+ */
+@MixinAfter
+public class AltTitle
+{
+    @InjectContainer
+    private ClientElement container;
+
+    @Parameter(required = true, defaultPrefix = BindingConstants.LITERAL)
+    private String title;
+
+    void afterRender()
+    {
+        container.getClientId();
+    }
+
+    void beginRender(MarkupWriter writer)
+    {
+        writer.attributes("alt", title);
+    }
+
+}

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=1178584&r1=1178583&r2=1178584&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 Mon Oct  3 21:22:18 2011
@@ -56,6 +56,8 @@ public class Index
     private static final List<Item> ITEMS = CollectionFactory
             .newList(
 
+                    new Item("MixinVsInformalParameter", "Mixin Parameter vs. Informal Parameter", "Informal Paramters vs. Mixin parameter of same name"),
+
                     new Item("inherit/childa", "TAP5-1656 Demo", "Test a reported bug in component inheritance"),
 
                     new Item("ComponentInsideBlockDemo", "Component Inside Block Demo", "Verify that a component, inside a block, is still an embedded "),

Added: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/MixinVsInformalParameter.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/MixinVsInformalParameter.java?rev=1178584&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/MixinVsInformalParameter.java (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/MixinVsInformalParameter.java Mon Oct  3 21:22:18 2011
@@ -0,0 +1,13 @@
+package org.apache.tapestry5.integration.app1.pages;
+
+/**
+ *
+ */
+public class MixinVsInformalParameter
+{
+    void onActionFromFrog()
+    {
+
+
+    }
+}

Added: tapestry/tapestry5/trunk/tapestry-core/src/test/resources/org/apache/tapestry5/integration/app1/pages/MixinVsInformalParameter.tml
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/resources/org/apache/tapestry5/integration/app1/pages/MixinVsInformalParameter.tml?rev=1178584&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/resources/org/apache/tapestry5/integration/app1/pages/MixinVsInformalParameter.tml (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/resources/org/apache/tapestry5/integration/app1/pages/MixinVsInformalParameter.tml Mon Oct  3 21:22:18 2011
@@ -0,0 +1,10 @@
+<html t:type="Border" xmlns:t="http://tapestry.apache.org/schema/tapestry_5_3.xsd">
+
+<h1>Mixin Parameter vs. Component Informal Parameter</h1>
+
+<p>
+    <t:actionlink t:id="frog" actionlink.title="Frog Title" t:mixins="alttitle" alttitle.title="Alt Title">little frog
+    </t:actionlink>
+</p>
+
+</html>
\ No newline at end of file