You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tapestry.apache.org by hl...@apache.org on 2007/03/13 06:31:19 UTC

svn commit: r517535 - in /tapestry/tapestry5/tapestry-core/trunk/src: main/java/org/apache/tapestry/internal/services/ main/java/org/apache/tapestry/runtime/ site/apt/guide/ test/app1/WEB-INF/ test/conf/ test/java/org/apache/tapestry/integration/ test/...

Author: hlship
Date: Mon Mar 12 22:31:18 2007
New Revision: 517535

URL: http://svn.apache.org/viewvc?view=rev&rev=517535
Log:
TAPESTRY-1295: Event handling methods that have too many parameters for the event context should be silently skipped

Added:
    tapestry/tapestry5/tapestry-core/trunk/src/test/app1/WEB-INF/EventHandlerDemo.html
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/base/BaseEventHandlerDemo.java
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/pages/EventHandlerDemo.java
Removed:
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/OnEventWorkerTest.java
Modified:
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ComponentEventImpl.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/OnEventWorker.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/runtime/ComponentEvent.java
    tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/event.apt
    tapestry/tapestry5/tapestry-core/trunk/src/test/app1/WEB-INF/Start.html
    tapestry/tapestry5/tapestry-core/trunk/src/test/conf/testng.xml
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/IntegrationTests.java

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ComponentEventImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ComponentEventImpl.java?view=diff&rev=517535&r1=517534&r2=517535
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ComponentEventImpl.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ComponentEventImpl.java Mon Mar 12 22:31:18 2007
@@ -55,7 +55,6 @@
         _originatingComponentId = originatingComponentId;
         _context = context != null ? context : new Object[0];
         _typeCoercer = notNull(typeCoercer, "typeCoercer");
-
     }
 
     /**
@@ -67,8 +66,7 @@
     {
         for (String id : componentId)
         {
-            if (id.equalsIgnoreCase(_originatingComponentId))
-                return true;
+            if (id.equalsIgnoreCase(_originatingComponentId)) return true;
         }
 
         return false;
@@ -78,11 +76,15 @@
     {
         for (String type : eventTypes)
         {
-            if (type.equalsIgnoreCase(_eventType))
-                return true;
+            if (type.equalsIgnoreCase(_eventType)) return true;
         }
 
         return false;
+    }
+
+    public boolean matchesByParameterCount(int parameterCount)
+    {
+        return _context.length >= parameterCount;
     }
 
     @SuppressWarnings("unchecked")

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/OnEventWorker.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/OnEventWorker.java?view=diff&rev=517535&r1=517534&r2=517535
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/OnEventWorker.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/OnEventWorker.java Mon Mar 12 22:31:18 2007
@@ -38,6 +38,8 @@
 
     private final String[] _empty = new String[0];
 
+    private final static int ANY_NUMBER_OF_PARAMETERS = -1;
+
     public void transform(final ClassTransformation transformation, MutableComponentModel model)
     {
         MethodFilter filter = new MethodFilter()
@@ -75,6 +77,16 @@
 
         int closeCount = 0;
 
+        int parameterCount = getParameterCount(method);
+
+        if (parameterCount > 0)
+        {
+            builder.addln("if ($1.matchesByParameterCount(%d))", parameterCount);
+            builder.begin();
+
+            closeCount++;
+        }
+
         OnEvent annotation = transformation.getMethodAnnotation(method, OnEvent.class);
 
         String[] eventTypes = extractEventTypes(method, annotation);
@@ -168,10 +180,24 @@
 
         // This is intended for onAnyFromComponentId, but just onAny works too (and is dangerous).
 
-        if (eventName.equals("AnyEvent")) return _empty;
+        if (eventName.equalsIgnoreCase("AnyEvent")) return _empty;
 
         return new String[]
         { eventName };
+    }
+
+    private int getParameterCount(MethodSignature method)
+    {
+        String[] types = method.getParameterTypes();
+
+        if (types.length == 0) return 0;
+
+        if (types[0].equals(OBJECT_ARRAY_TYPE)) return ANY_NUMBER_OF_PARAMETERS;
+
+        // TODO: If the first parameter is Object[], that should be the only parameter.
+        // Otherwise, Object[] should not be allowed.
+
+        return types.length;
     }
 
     private void buildMethodParameters(BodyBuilder builder, MethodSignature method)

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/runtime/ComponentEvent.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/runtime/ComponentEvent.java?view=diff&rev=517535&r1=517534&r2=517535
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/runtime/ComponentEvent.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/runtime/ComponentEvent.java Mon Mar 12 22:31:18 2007
@@ -45,6 +45,14 @@
     boolean matchesByComponentId(ComponentResources resources, String[] componentId);
 
     /**
+     * Returns true if the event context contains the specified number of parameters (or more).
+     * 
+     * @param parameterCount number of parameters in the event handler method
+     * @return true if the event can 
+     */
+    boolean matchesByParameterCount(int parameterCount);
+
+    /**
      * Coerces a context value to a particular type. The context is an array of objects; typically
      * it is an array of strings of extra path information encoded into the action URL.
      * 

Modified: tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/event.apt
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/event.apt?view=diff&rev=517535&r1=517534&r2=517535
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/event.apt (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/event.apt Mon Mar 12 22:31:18 2007
@@ -86,7 +86,7 @@
   []
   
   In the above example, the valueChosen() method will be invoked on <any event> that originates
-  inn component <<<choose>>>.  Since ActionLink components only emit a single type of event, "action", 
+  in component <<<choose>>> (and has at least one context value).  Since ActionLink components only emit a single type of event, "action", 
   this will not be a problem.
   
   Some components can emit more than one type of event, in which case you will want to be more specific:
@@ -143,8 +143,9 @@
   context parameter), then each one, in order, will be added to the URL.
   
   When an event handler method is invoked, a
-  {{{coercion.html}coercion}} from string to the actual type occurs. A runtime exception
-  occurs if there are more parameters than context strings.
+  {{{coercion.html}coercion}} from string to the actual type occurs. An event handler method will only be invoked
+  <if the context contains at least as many values as the method has parameters>.  Methods with too many parameters
+  will be silently skipped.
   
   Alternately, an event handler method may take a parameter of type java.lang.Object[].  This parameter
   will receive the entire context array. This is useful when, for example, the context

Added: tapestry/tapestry5/tapestry-core/trunk/src/test/app1/WEB-INF/EventHandlerDemo.html
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/app1/WEB-INF/EventHandlerDemo.html?view=auto&rev=517535
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/app1/WEB-INF/EventHandlerDemo.html (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/app1/WEB-INF/EventHandlerDemo.html Mon Mar 12 22:31:18 2007
@@ -0,0 +1,29 @@
+<html t:type="Border" xmlns:t="http://tapestry.apache.org/schema/tapestry_5_0_0.xsd">
+
+  <h1>EventHandler Demo</h1>
+
+  <t:if test="methodNames">
+    <p> Event method names: ${methodNames} </p>
+  </t:if>
+
+
+  <p> [<t:pagelink page="eventhandlerdemo" context="'anything'">clear</t:pagelink>] </p>
+
+
+  <ul>
+    <li>
+      <t:actionlink t:id="wilma">No Context</t:actionlink>
+    </li>
+    <li>
+      <t:actionlink t:id="barney" context="literal:one">Single context value</t:actionlink>
+    </li>
+    <li>
+      <t:actionlink t:id="betty" context="twoContext">Two value context</t:actionlink>
+    </li>
+    <li>
+      <t:actionlink context="'two'" t:id="fred">Two value context (from fred)</t:actionlink>
+    </li>
+  </ul>
+
+
+</html>

Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/app1/WEB-INF/Start.html
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/app1/WEB-INF/Start.html?view=diff&rev=517535&r1=517534&r2=517535
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/app1/WEB-INF/Start.html (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/app1/WEB-INF/Start.html Mon Mar 12 22:31:18 2007
@@ -123,6 +123,10 @@
           <li>
             <t:pagelink page="renderabledemo">Renderable Demo</t:pagelink> -- Shows that render
             phase methods can return a Renderable object </li>
+          <li>
+            <t:pagelink page="eventhandlerdemo" context="'clear'">EventHandler Demo</t:pagelink>
+            -- Tests for event handling method order and matching
+          </li>
         </ul>
       </td>
     </tr>

Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/conf/testng.xml
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/conf/testng.xml?view=diff&rev=517535&r1=517534&r2=517535
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/conf/testng.xml (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/conf/testng.xml Mon Mar 12 22:31:18 2007
@@ -21,6 +21,7 @@
     <packages>
       <package name="org.apache.tapestry"/>
       <package name="org.apache.tapestry.integration"/>
+      <package name="org.apache.tapestry.integration.pagelevel"/>
       <package name="org.apache.tapestry.test.pagelevel"/>
       <package name="org.apache.tapestry.corelib.components"/>
       <package name="org.apache.tapestry"/>

Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/IntegrationTests.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/IntegrationTests.java?view=diff&rev=517535&r1=517534&r2=517535
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/IntegrationTests.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/IntegrationTests.java Mon Mar 12 22:31:18 2007
@@ -874,4 +874,32 @@
 
         assertTextPresent("Renderable Demo", "[This proves it works.]");
     }
+
+    @Test
+    public void verify_event_handler_invocation_order_and_circumstance()
+    {
+        String clear = "link=clear";
+
+        open(BASE_URL);
+        clickAndWait("link=EventHandler Demo");
+        clickAndWait(clear);
+
+        clickAndWait("wilma");
+        assertTextPresent("[parent.eventHandlerZero(), parent.onAction(), child.eventHandlerZeroChild(), child.onAction()]");
+
+        clickAndWait(clear);
+        clickAndWait("barney");
+
+        assertTextPresent("[parent.eventHandlerOne(String), parent.eventHandlerZero(), parent.onAction(), parent.onAction(String), child.eventHandlerOneChild(), child.eventHandlerZeroChild(), child.onAction(), child.onAction(String)]");
+
+        clickAndWait(clear);
+        clickAndWait("betty");
+        assertTextPresent("[parent.eventHandlerOne(String), parent.eventHandlerZero(), parent.onAction(), parent.onAction(String), child.eventHandlerOneChild(), child.eventHandlerZeroChild(), child.onAction(), child.onAction(String)]");
+
+        clickAndWait(clear);
+        clickAndWait("fred");
+
+        assertTextPresent("[parent.eventHandlerOne(String), parent.eventHandlerZero(), parent.onAction(), parent.onAction(String), child.eventHandlerForFred(), child.eventHandlerOneChild(), child.eventHandlerZeroChild(), child.onAction(), child.onAction(String), child.onActionFromFred(), child.onActionFromFred(String), child.onAnyEventFromFred(), child.onAnyEventFromFred(String)]");
+
+    }
 }

Added: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/base/BaseEventHandlerDemo.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/base/BaseEventHandlerDemo.java?view=auto&rev=517535
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/base/BaseEventHandlerDemo.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/base/BaseEventHandlerDemo.java Mon Mar 12 22:31:18 2007
@@ -0,0 +1,74 @@
+// Copyright 2007 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.tapestry.integration.app1.base;
+
+import java.util.List;
+
+import org.apache.tapestry.annotations.OnEvent;
+import org.apache.tapestry.annotations.Persist;
+import org.apache.tapestry.ioc.internal.util.CollectionFactory;
+
+public abstract class BaseEventHandlerDemo
+{
+    @Persist
+    private List<String> _methodNames;
+
+    protected final void addMethodName(String name)
+    {
+        List<String> methodNames = _methodNames;
+
+        if (methodNames == null) methodNames = CollectionFactory.newList();
+
+        methodNames.add(name);
+
+        _methodNames = methodNames;
+    }
+
+    void onActivate(String placeholder)
+    {
+        _methodNames = null;
+    }
+
+    public List<String> getMethodNames()
+    {
+        return _methodNames;
+    }
+
+    @SuppressWarnings("unused")
+    private void onAction()
+    {
+        addMethodName("parent.onAction()");
+    }
+
+    @SuppressWarnings("unused")
+    private void onAction(String value)
+    {
+        addMethodName("parent.onAction(String)");
+
+    }
+
+    @OnEvent(value = "action")
+    void eventHandlerZero()
+    {
+        addMethodName("parent.eventHandlerZero()");
+    }
+
+    @OnEvent(value = "action")
+    void eventHandlerOne(String value)
+    {
+        addMethodName("parent.eventHandlerOne(String)");
+    }
+
+}

Added: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/pages/EventHandlerDemo.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/pages/EventHandlerDemo.java?view=auto&rev=517535
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/pages/EventHandlerDemo.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/pages/EventHandlerDemo.java Mon Mar 12 22:31:18 2007
@@ -0,0 +1,81 @@
+// Copyright 2007 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.tapestry.integration.app1.pages;
+
+import org.apache.tapestry.annotations.OnEvent;
+import org.apache.tapestry.integration.app1.base.BaseEventHandlerDemo;
+
+public class EventHandlerDemo extends BaseEventHandlerDemo
+{
+    @SuppressWarnings("unused")
+    private void onAction()
+    {
+        addMethodName("child.onAction()");
+    }
+
+    @SuppressWarnings("unused")
+    private void onAction(String value)
+    {
+        addMethodName("child.onAction(String)");
+    }
+
+    @SuppressWarnings("unused")
+    private void onActionFromFred()
+    {
+        addMethodName("child.onActionFromFred()");
+    }
+
+    @SuppressWarnings("unused")
+    private void onActionFromFred(String value)
+    {
+        addMethodName("child.onActionFromFred(String)");
+    }
+
+    @SuppressWarnings("unused")
+    private void onAnyEventFromFred()
+    {
+        addMethodName("child.onAnyEventFromFred()");
+    }
+
+    @SuppressWarnings("unused")
+    private void onAnyEventFromFred(String value)
+    {
+        addMethodName("child.onAnyEventFromFred(String)");
+    }
+
+    @OnEvent(value = "action")
+    void eventHandlerZeroChild()
+    {
+        addMethodName("child.eventHandlerZeroChild()");
+    }
+
+    @OnEvent(value = "action")
+    void eventHandlerOneChild(String value)
+    {
+        addMethodName("child.eventHandlerOneChild()");
+    }
+
+    @OnEvent(component = "fred")
+    void eventHandlerForFred()
+    {
+        addMethodName("child.eventHandlerForFred()");
+    }
+
+    public Object[] getTwoContext()
+    {
+        return new Object[]
+        { 1, 2 };
+    }
+}