You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tapestry.apache.org by jk...@apache.org on 2006/06/04 01:23:18 UTC

svn commit: r411483 [2/2] - in /tapestry/tapestry4/trunk: .settings/ annotations/src/java/org/apache/tapestry/annotations/ annotations/src/test/org/apache/tapestry/annotations/ eclipse/ examples/TimeTracker/src/context/ examples/TimeTracker/src/java/or...

Modified: tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/pages/Exception.html
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/pages/Exception.html?rev=411483&r1=411482&r2=411483&view=diff
==============================================================================
--- tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/pages/Exception.html (original)
+++ tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/pages/Exception.html Sat Jun  3 16:23:16 2006
@@ -24,7 +24,7 @@
 <p>You may continue by <b><a jwcid="restart">restarting</a></b> the session.</p>
 
 <span jwcid="@ExceptionDisplay" exceptions="ognl:exceptions"/>
-
+<br/>
 <span jwcid="@RequestDisplay"/>
 
 <script type="text/javascript">

Modified: tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/services/impl/ComponentEventConnectionWorker.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/services/impl/ComponentEventConnectionWorker.java?rev=411483&r1=411482&r2=411483&view=diff
==============================================================================
--- tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/services/impl/ComponentEventConnectionWorker.java (original)
+++ tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/services/impl/ComponentEventConnectionWorker.java Sat Jun  3 16:23:16 2006
@@ -13,15 +13,19 @@
 // limitations under the License.
 package org.apache.tapestry.services.impl;
 
+import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.Iterator;
+import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 import org.apache.hivemind.ClassResolver;
 import org.apache.hivemind.Resource;
 import org.apache.hivemind.util.ClasspathResource;
 import org.apache.tapestry.IComponent;
 import org.apache.tapestry.IDirectEvent;
+import org.apache.tapestry.IForm;
 import org.apache.tapestry.IRequestCycle;
 import org.apache.tapestry.PageRenderSupport;
 import org.apache.tapestry.TapestryUtils;
@@ -31,6 +35,7 @@
 import org.apache.tapestry.engine.IScriptSource;
 import org.apache.tapestry.html.Body;
 import org.apache.tapestry.internal.event.ComponentEventProperty;
+import org.apache.tapestry.internal.event.EventBoundListener;
 import org.apache.tapestry.services.ComponentRenderWorker;
 
 
@@ -42,46 +47,72 @@
  */
 public class ComponentEventConnectionWorker implements ComponentRenderWorker
 {
+    /** Stored in {@link IRequestCycle} with associated forms. */
+    public static final String FORM_NAME_LIST = 
+        "org.apache.tapestry.services.impl.ComponentEventConnectionFormNames-";
+    // holds mapped event listener info
     private ComponentEventInvoker _invoker;
     
+    // generates links for scripts
     private IEngineService _eventEngine;
-    
+    // handles resolving and loading different component event 
+    // connection script types
     private IScriptSource _scriptSource;
-    
     private String _componentScript;
-    
     private String _widgetScript;
-    
     private String _elementScript;
-    
     private ClassResolver _resolver;
-    
     private ClasspathResource _componentResource;
     private ClasspathResource _widgetResource;
     private ClasspathResource _elementResource;
     
+    // For event connections referencing forms that have not 
+    // been rendered yet.
+    private Map _deferredFormConnections = new HashMap();
+    
     /** 
      * {@inheritDoc}
      */
     public void renderComponent(IRequestCycle cycle, IComponent component)
     {
-        if (!_invoker.hasEvents(component.getId()))
+        if (cycle.isRewinding() 
+                || TapestryUtils.getOptionalPageRenderSupport(cycle) == null) 
             return;
         
+        if (_invoker.hasEvents(component.getId()))
+            linkComponent(cycle, component);
+        
+        if (IForm.class.isInstance(component))
+            mapFormNames(cycle, (IForm)component);
+        
+        if (isDeferredForm(component))
+            linkDeferredForm(cycle, (IForm)component);
+    }
+    
+    void linkComponent(IRequestCycle cycle, IComponent component)
+    {
         ComponentEventProperty prop = _invoker.getComponentEvents(component.getId());
+        String clientId = component.getClientId();
         
         Map parms = new HashMap();
+        parms.put("clientId", clientId);
+        parms.put("component", component);
+        
+        Set events = prop.getEvents();
+        Object[][] formEvents = filterFormEvents(prop, parms, cycle);
+        
+        if (events.size() < 1 && formEvents.length < 1)
+            return;
+        
         DirectEventServiceParameter dsp =
             new DirectEventServiceParameter((IDirectEvent)component, new Object[] {}, new String[] {}, false);
         
-        parms.put("component", component);
         parms.put("url", _eventEngine.getLink(false, dsp).getURL());
-        parms.put("events", prop.getEvents());
+        parms.put("events", events);
+        parms.put("formEvents", formEvents);
         
         PageRenderSupport prs = TapestryUtils.getPageRenderSupport(cycle, component);
-        
         Resource resource = getScript(component);
-        
         _scriptSource.getScript(resource).execute(cycle, prs, parms);
     }
     
@@ -90,7 +121,7 @@
      */
     public void renderBody(IRequestCycle cycle, Body component)
     {
-        if (!_invoker.hasElementEvents())
+        if (cycle.isRewinding() || !_invoker.hasElementEvents())
             return;
         
         Map parms = new HashMap();
@@ -113,11 +144,63 @@
             parms.put("target", target);
             parms.put("url", url);
             parms.put("events", prop.getEvents());
+            parms.put("formEvents", filterFormEvents(prop, parms, cycle));
             
             _scriptSource.getScript(resource).execute(cycle, prs, parms);
             
             parms.clear();
         }
+        
+        // just in case
+        _deferredFormConnections.clear();
+    }
+    
+    void mapFormNames(IRequestCycle cycle, IForm form)
+    {
+        List names = (List)cycle.getAttribute(FORM_NAME_LIST + form.getId());
+        if (names == null) {
+            names = new ArrayList();
+            cycle.setAttribute(FORM_NAME_LIST + form.getId(), names);
+        }
+        
+        names.add(form.getName());
+    }
+    
+    void linkDeferredForm(IRequestCycle cycle, IForm form)
+    {
+        List deferred = (List)_deferredFormConnections.remove(form.getId());
+        for (int i=0; i < deferred.size(); i++) {
+            Object[] val = (Object[])deferred.get(i);
+            
+            Map scriptParms = (Map)val[0];
+            IComponent component = (IComponent)scriptParms.get("component");
+            
+            ComponentEventProperty props = _invoker.getComponentEvents(component.getId());
+            Object[][] formEvents = buildFormEvents(cycle, form.getId(), props.getFormEvents());
+            
+            // don't want any events accidently connected again
+            scriptParms.remove("events");
+            scriptParms.put("formEvents", formEvents);
+            
+            // execute script
+            PageRenderSupport prs = TapestryUtils.getPageRenderSupport(cycle, component);
+            Resource resource = getScript(component);
+            _scriptSource.getScript(resource).execute(cycle, prs, scriptParms);
+        }
+    }
+    
+    Object[][] buildFormEvents(IRequestCycle cycle, String formId, Set events)
+    {
+        List formNames = (List)cycle.getAttribute(FORM_NAME_LIST + formId);
+        List retval = new ArrayList();
+        
+        Iterator it = events.iterator();
+        while (it.hasNext()) {
+            String event = (String)it.next();
+            retval.add(new Object[]{event, formNames});
+        }
+        
+        return (Object[][])retval.toArray(new Object[retval.size()][2]);
     }
     
     Resource getScript(IComponent component)
@@ -138,6 +221,90 @@
             _componentResource = new ClasspathResource(_resolver, _componentScript);
         
         return _componentResource;
+    }
+    
+    boolean isDeferredForm(IComponent component)
+    {
+        if (IForm.class.isInstance(component) 
+                && _deferredFormConnections.get(((IForm)component).getId()) != null)
+            return true;
+        
+        return false;
+    }
+    
+    /**
+     * For each form event attempts to find a rendered form name list that corresponds
+     * to the actual client ids that the form can be connected to. If the form hasn't been
+     * rendered yet the events will be filtered out and deferred for execution <i>after</i>
+     * the form has rendererd.
+     * 
+     * @param prop
+     * @param scriptParms
+     * @param cycle
+     * @return
+     */
+    Object[][] filterFormEvents(ComponentEventProperty prop, Map scriptParms, IRequestCycle cycle)
+    {
+        Set events = prop.getFormEvents();
+        if (events.size() < 1) return new Object[0][0];
+        
+        List retval = new ArrayList();
+        
+        Iterator it = events.iterator();
+        while (it.hasNext()) {
+            String event = (String)it.next();
+            Iterator lit = prop.getFormEventListeners(event).iterator();
+            
+            while (lit.hasNext()) {
+                EventBoundListener listener = (EventBoundListener)lit.next();
+                
+                String formId = listener.getFormId();
+                List formNames = (List)cycle.getAttribute(FORM_NAME_LIST + formId);
+                
+                // defer connection until form is rendered
+                if (formNames == null) {
+                    deferFormConnection(formId, scriptParms);
+                    continue;
+                }
+                
+                // form has been rendered so go ahead
+                retval.add(new Object[] {event, formNames});
+            }
+        }
+        
+        return (Object[][])retval.toArray(new Object[retval.size()][2]);
+    }
+    
+    /**
+     * Temporarily stores the data needed to perform script evaluations that
+     * connect a component event to submitting a particular form that hasn't
+     * been rendered yet. We can't reliably connect to a form until its name has
+     * been set by a render, which could happen multiple times if it's in a list.
+     * 
+     * <p>
+     * The idea here is that when the form actually ~is~ rendered we will look for 
+     * any pending deferred operations and run them while also clearing out our
+     * deferred list.
+     * </p>
+     * 
+     * @param formId
+     * @param scriptParms
+     */
+    void deferFormConnection(String formId, Map scriptParms)
+    {
+        List deferred = (List)_deferredFormConnections.get(formId);
+        if (deferred == null) {
+            deferred = new ArrayList();
+            _deferredFormConnections.put(formId, deferred);
+        }
+        
+        deferred.add(new Object[] {scriptParms});
+    }
+    
+    // for testing
+    Map getDefferedFormConnections()
+    {
+        return _deferredFormConnections;
     }
     
     /**

Modified: tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/services/impl/ComponentEventInvoker.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/services/impl/ComponentEventInvoker.java?rev=411483&r1=411482&r2=411483&view=diff
==============================================================================
--- tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/services/impl/ComponentEventInvoker.java (original)
+++ tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/services/impl/ComponentEventInvoker.java Sat Jun  3 16:23:16 2006
@@ -24,6 +24,7 @@
 import org.apache.tapestry.event.BrowserEvent;
 import org.apache.tapestry.event.ResetEventListener;
 import org.apache.tapestry.internal.event.ComponentEventProperty;
+import org.apache.tapestry.internal.event.EventBoundListener;
 import org.apache.tapestry.listener.ListenerInvoker;
 
 
@@ -81,13 +82,14 @@
     {
         List listeners = prop.getEventListeners(event.getName());
         for (int i=0; i < listeners.size(); i++) {
-            String methodName = (String)listeners.get(i);
+            EventBoundListener eventListener = (EventBoundListener)listeners.get(i);
             
             IComponent container = component.getContainer();
             if (container == null) // only IPage has no container
                 container = component; 
             
-            IActionListener listener = container.getListeners().getListener(methodName);
+            IActionListener listener = 
+                container.getListeners().getListener(eventListener.getMethodName());
             _invoker.invokeListener(listener, container, cycle);
         }
     }
@@ -103,11 +105,12 @@
      *          The page/component listener name that should be executed when
      *          one of the supplied events occurs.
      */
-    public void addEventListener(String componentId, String[] events, String methodName)
+    public void addEventListener(String componentId, String[] events, 
+            String methodName, String formId, boolean validateForm)
     {
         ComponentEventProperty property = getComponentEvents(componentId);
         
-        property.addListener(events, methodName);
+        property.addListener(events, methodName, formId, validateForm);
     }
     
     /**
@@ -117,11 +120,12 @@
      * @param events
      * @param methodName
      */
-    public void addElementEventListener(String elementId, String[] events, String methodName)
+    public void addElementEventListener(String elementId, String[] events, 
+            String methodName, String formId, boolean validateForm)
     {
         ComponentEventProperty property = getElementEvents(elementId);
         
-        property.addListener(events, methodName);
+        property.addListener(events, methodName, formId, validateForm);
     }
     
     /**
@@ -167,7 +171,7 @@
     {
         ComponentEventProperty prop = (ComponentEventProperty)_components.get(id);
         if (prop == null) {
-            prop = new ComponentEventProperty();
+            prop = new ComponentEventProperty(id);
             _components.put(id, prop);
         }
         
@@ -185,7 +189,7 @@
     {
         ComponentEventProperty prop = (ComponentEventProperty)_elements.get(id);
         if (prop == null) {
-            prop = new ComponentEventProperty();
+            prop = new ComponentEventProperty(id);
             _elements.put(id, prop);
         }
         

Added: tapestry/tapestry4/trunk/framework/src/test/org/apache/tapestry/internal/event/ComponentEventPropertyTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/framework/src/test/org/apache/tapestry/internal/event/ComponentEventPropertyTest.java?rev=411483&view=auto
==============================================================================
--- tapestry/tapestry4/trunk/framework/src/test/org/apache/tapestry/internal/event/ComponentEventPropertyTest.java (added)
+++ tapestry/tapestry4/trunk/framework/src/test/org/apache/tapestry/internal/event/ComponentEventPropertyTest.java Sat Jun  3 16:23:16 2006
@@ -0,0 +1,74 @@
+// Copyright Jun 3, 2006 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.internal.event;
+
+import java.util.List;
+
+import org.apache.hivemind.test.HiveMindTestCase;
+
+
+/**
+ * Tests for {@link ComponentEventProperty} and {@link EventBoundListener}.
+ * 
+ * @author jkuhnert
+ */
+public class ComponentEventPropertyTest extends HiveMindTestCase
+{
+
+    public void testAddEventListener()
+    {
+        String[] events = {"onClick", "onFoo"};
+        ComponentEventProperty prop = new ComponentEventProperty("compid");
+        
+        prop.addListener(events, "doFoo", null, false);
+        
+        assertEquals("compid", prop.getComponentId());
+        assertEquals(2, prop.getEvents().size());
+        assertEquals(0, prop.getFormEvents().size());
+        
+        assertNotNull(prop.getEventListeners("onClick"));
+        
+        List listeners = prop.getEventListeners("onClick");
+        assertEquals(1, listeners.size());
+        
+        EventBoundListener listener = (EventBoundListener)listeners.get(0);
+        assertEquals("compid", listener.getComponentId());
+        assertNull(listener.getFormId());
+        assertEquals("doFoo", listener.getMethodName());
+    }
+    
+    public void testAddFormEventListener()
+    {
+        String[] events = {"onFoo"};
+        ComponentEventProperty prop = new ComponentEventProperty("compid");
+        
+        prop.addListener(events, "doFoo", "formid", false);
+        
+        assertEquals("compid", prop.getComponentId());
+        assertEquals(0, prop.getEvents().size());
+        assertEquals(1, prop.getFormEvents().size());
+        
+        assertNotNull(prop.getFormEventListeners("onFoo"));
+        
+        List listeners = prop.getFormEventListeners("onFoo");
+        assertEquals(1, listeners.size());
+        
+        EventBoundListener listener = (EventBoundListener)listeners.get(0);
+        assertEquals("compid", listener.getComponentId());
+        assertEquals("formid", listener.getFormId());
+        assertFalse(listener.isValidateForm());
+        
+        assertEquals("doFoo", listener.getMethodName());
+    }
+}

Modified: tapestry/tapestry4/trunk/framework/src/test/org/apache/tapestry/services/impl/ComponentEventConnectionWorkerTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/framework/src/test/org/apache/tapestry/services/impl/ComponentEventConnectionWorkerTest.java?rev=411483&r1=411482&r2=411483&view=diff
==============================================================================
--- tapestry/tapestry4/trunk/framework/src/test/org/apache/tapestry/services/impl/ComponentEventConnectionWorkerTest.java (original)
+++ tapestry/tapestry4/trunk/framework/src/test/org/apache/tapestry/services/impl/ComponentEventConnectionWorkerTest.java Sat Jun  3 16:23:16 2006
@@ -13,7 +13,10 @@
 // limitations under the License.
 package org.apache.tapestry.services.impl;
 
+import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
 
 import org.apache.hivemind.ClassResolver;
 import org.apache.hivemind.Resource;
@@ -23,6 +26,7 @@
 import org.apache.hivemind.util.ClasspathResource;
 import org.apache.tapestry.BaseComponentTestCase;
 import org.apache.tapestry.IDirectEvent;
+import org.apache.tapestry.IForm;
 import org.apache.tapestry.IRequestCycle;
 import org.apache.tapestry.IScript;
 import org.apache.tapestry.IgnoreMatcher;
@@ -83,7 +87,11 @@
         assertEquals(widScript, worker.getScript(widget).getPath());
         
         // now test render
-        invoker.addEventListener("comp1", new String[] {"onclick"}, "testMethod");
+        invoker.addEventListener("comp1", new String[] {"onclick"}, 
+                "testMethod", null, false);
+        
+        cycle.isRewinding();
+        setReturnValue(cycle, false);
         
         component.getId();
         setReturnValue(component, "comp1");
@@ -91,12 +99,18 @@
         component.getId();
         setReturnValue(component, "comp1");
         
+        component.getClientId();
+        setReturnValue(component, "comp1");
+        
         trainGetLinkCheckIgnoreParameter(engine, cycle, false, new Object(), link);
         trainGetURL(link, "/some/url");
         
         cycle.getAttribute(TapestryUtils.PAGE_RENDER_SUPPORT_ATTRIBUTE);
         setReturnValue(cycle, prs);
         
+        cycle.getAttribute(TapestryUtils.PAGE_RENDER_SUPPORT_ATTRIBUTE);
+        setReturnValue(cycle, prs);
+        
         scriptSource.getScript(compScriptResource);
         setReturnValue(scriptSource, script);
         
@@ -112,23 +126,37 @@
         
         verifyControls();
         
+        assertEquals(0, worker.getDefferedFormConnections().size());
+        
+        resetControls();
+        
         // test widget render
         
-        invoker.addEventListener("wid1", new String[] {"onSelect"}, "testMethod");
+        invoker.addEventListener("wid1", new String[] {"onSelect"}, "testMethod",
+                null, false);
         
         assertTrue(invoker.hasEvents("wid1"));
         
+        cycle.isRewinding();
+        setReturnValue(cycle, false);
+     
         widget.getId();
         setReturnValue(widget, "wid1");
         
         widget.getId();
         setReturnValue(widget, "wid1");
         
+        widget.getClientId();
+        setReturnValue(widget, "wid1");
+        
         trainGetLinkCheckIgnoreParameter(engine, cycle, false, new Object(), link);
         trainGetURL(link, "/some/url2");
         
         cycle.getAttribute(TapestryUtils.PAGE_RENDER_SUPPORT_ATTRIBUTE);
         setReturnValue(cycle, prs);
+
+        cycle.getAttribute(TapestryUtils.PAGE_RENDER_SUPPORT_ATTRIBUTE);
+        setReturnValue(cycle, prs);
         
         scriptSource.getScript(widScriptResource);
         setReturnValue(scriptSource, script);
@@ -141,6 +169,218 @@
         replayControls();
         
         worker.renderComponent(cycle, widget);
+        
+        verifyControls();
+    }
+    
+    public void testRewindRender()
+    {
+        IRequestCycle cycle = newCycle();
+        
+        ComponentEventConnectionWorker worker = new ComponentEventConnectionWorker();
+        
+        cycle.isRewinding();
+        setReturnValue(cycle, true);
+        
+        replayControls();
+        
+        worker.renderComponent(cycle, null);
+        
+        verifyControls();
+    }
+    
+    public void testNullPageSupport()
+    {
+        IRequestCycle cycle = newCycle();
+        
+        ComponentEventConnectionWorker worker = new ComponentEventConnectionWorker();
+        
+        cycle.isRewinding();
+        setReturnValue(cycle, false);
+        
+        cycle.getAttribute(TapestryUtils.PAGE_RENDER_SUPPORT_ATTRIBUTE);
+        setReturnValue(cycle, null);
+        
+        replayControls();
+        
+        worker.renderComponent(cycle, null);
+        
+        verifyControls();
+    }
+    
+    public void testDeferredConnection()
+    {
+        ComponentEventInvoker invoker = new ComponentEventInvoker();
+        IEngineService engine = (IEngineService)newMock(IEngineService.class);
+        IRequestCycle cycle = newCycle();
+        PageRenderSupport prs = newPageRenderSupport();
+        
+        ComponentEventConnectionWorker worker = new ComponentEventConnectionWorker();
+        worker.setComponentEventInvoker(invoker);
+        worker.setEventEngine(engine);
+        
+        IDirectEvent component = (IDirectEvent)newMock(IDirectEvent.class);
+        
+        // now test render
+        invoker.addEventListener("comp1", new String[] {"onclick"}, 
+                "testMethod", "form1", false);
+        
+        cycle.isRewinding();
+        setReturnValue(cycle, false);
+        
+        cycle.getAttribute(TapestryUtils.PAGE_RENDER_SUPPORT_ATTRIBUTE);
+        setReturnValue(cycle, prs);
+        
+        component.getId();
+        setReturnValue(component, "comp1");
+        
+        cycle.getAttribute(ComponentEventConnectionWorker.FORM_NAME_LIST + "form1");
+        setReturnValue(cycle, null);
+        
+        component.getId();
+        setReturnValue(component, "comp1");
+        
+        component.getClientId();
+        setReturnValue(component, "comp1");
+        
+        replayControls();
+        
+        worker.renderComponent(cycle, component);
+        
+        verifyControls();
+        
+        assertEquals(1, worker.getDefferedFormConnections().size());
+        
+        resetControls();
+        
+        List deferred = (List)worker.getDefferedFormConnections().get("form1");
+        assertNotNull(deferred);
+        assertEquals(1, deferred.size());
+        
+        Object[] parms = (Object[])deferred.get(0);
+        assertEquals(1, parms.length);
+        Map parm = (Map)parms[0];
+        
+        assertNotNull(parm.get("clientId"));
+        assertNotNull(parm.get("component"));
+        assertNull(parm.get("url"));
+        assertNull(parm.get("formEvents"));
+        assertNull(parm.get("target"));
+        
+        assertEquals("comp1", parm.get("clientId"));
+        assertEquals(component, parm.get("component"));
+    }
+    
+    public void testFormRenderDeffered()
+    {
+        ClassResolver resolver = new DefaultClassResolver();
+        
+        ComponentEventInvoker invoker = new ComponentEventInvoker();
+        IEngineService engine = (IEngineService)newMock(IEngineService.class);
+        IRequestCycle cycle = newCycle();
+        IScriptSource scriptSource = (IScriptSource)newMock(IScriptSource.class);
+        IScript script = (IScript)newMock(IScript.class);
+        
+        PageRenderSupport prs = newPageRenderSupport();
+        
+        String compScript = "/org/apache/tapestry/ComponentEvent.script";
+        Resource compScriptResource = new ClasspathResource(resolver, compScript);
+        
+        ComponentEventConnectionWorker worker = new ComponentEventConnectionWorker();
+        worker.setClassResolver(resolver);
+        worker.setComponentEventInvoker(invoker);
+        worker.setComponentScript(compScript);
+        worker.setEventEngine(engine);
+        worker.setScriptSource(scriptSource);
+        
+        IDirectEvent component = (IDirectEvent)newMock(IDirectEvent.class);
+        IForm form = (IForm)newMock(IForm.class);
+        
+        // now test render
+        invoker.addEventListener("comp1", new String[] {"onclick"}, 
+                "testMethod", "form1", false);
+        
+        cycle.isRewinding();
+        setReturnValue(cycle, false);
+        
+        cycle.getAttribute(TapestryUtils.PAGE_RENDER_SUPPORT_ATTRIBUTE);
+        setReturnValue(cycle, prs);
+        
+        component.getId();
+        setReturnValue(component, "comp1");
+        
+        component.getId();
+        setReturnValue(component, "comp1");
+        
+        component.getClientId();
+        setReturnValue(component, "comp1");
+        
+        cycle.getAttribute(ComponentEventConnectionWorker.FORM_NAME_LIST + "form1");
+        setReturnValue(cycle, null);
+        
+        replayControls();
+        
+        worker.renderComponent(cycle, component);
+        
+        verifyControls();
+        
+        assertEquals(1, worker.getDefferedFormConnections().size());
+        
+        resetControls();
+        
+        cycle.isRewinding();
+        setReturnValue(cycle, false);
+        
+        cycle.getAttribute(TapestryUtils.PAGE_RENDER_SUPPORT_ATTRIBUTE);
+        setReturnValue(cycle, prs);
+        
+        form.getId();
+        setReturnValue(form, "form1");
+        
+        cycle.getAttribute(ComponentEventConnectionWorker.FORM_NAME_LIST + "form1");
+        setReturnValue(cycle, null);
+        
+        form.getId();
+        setReturnValue(form, "form1");
+        
+        cycle.setAttribute(ComponentEventConnectionWorker.FORM_NAME_LIST + "form1", new ArrayList());
+        ArgumentMatcher ignore = new IgnoreMatcher();
+        getControl(cycle)
+        .setMatcher(new AggregateArgumentsMatcher(new ArgumentMatcher[]{ null, ignore }));
+        
+        form.getId();
+        setReturnValue(form, "form1");
+        
+        form.getName();
+        setReturnValue(form, "form1_0");
+        
+        form.getId();
+        setReturnValue(form, "form1");
+        component.getId();
+        setReturnValue(component, "comp1");
+        form.getId();
+        setReturnValue(form, "form1");
+        form.getId();
+        setReturnValue(form, "form1");
+        
+        List formNames = new ArrayList();
+        formNames.add("form1_0");
+        cycle.getAttribute(ComponentEventConnectionWorker.FORM_NAME_LIST + "form1");
+        setReturnValue(cycle, formNames);
+        
+        cycle.getAttribute(TapestryUtils.PAGE_RENDER_SUPPORT_ATTRIBUTE);
+        setReturnValue(cycle, prs);
+        
+        scriptSource.getScript(compScriptResource);
+        setReturnValue(scriptSource, script);
+        
+        script.execute(cycle, prs, new HashMap());
+        getControl(script).setMatcher(new AggregateArgumentsMatcher(new ArgumentMatcher[]
+        { null, null, ignore }));
+        
+        replayControls();
+        
+        worker.renderComponent(cycle, form);
         
         verifyControls();
     }

Modified: tapestry/tapestry4/trunk/framework/src/test/org/apache/tapestry/services/impl/ComponentEventInvokerTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/framework/src/test/org/apache/tapestry/services/impl/ComponentEventInvokerTest.java?rev=411483&r1=411482&r2=411483&view=diff
==============================================================================
--- tapestry/tapestry4/trunk/framework/src/test/org/apache/tapestry/services/impl/ComponentEventInvokerTest.java (original)
+++ tapestry/tapestry4/trunk/framework/src/test/org/apache/tapestry/services/impl/ComponentEventInvokerTest.java Sat Jun  3 16:23:16 2006
@@ -40,7 +40,8 @@
     {
         ComponentEventInvoker invoker = new ComponentEventInvoker();
         
-        invoker.addEventListener("comp1", new String[] {"onClick"}, "testFoo");
+        invoker.addEventListener("comp1", new String[] {"onClick"}, "testFoo", 
+                null, false);
         assertTrue(invoker.hasEvents("comp1"));
         
         ComponentEventProperty prop = invoker.getComponentEvents("comp1");
@@ -72,7 +73,8 @@
         ComponentEventInvoker invoker = new ComponentEventInvoker();
         invoker.setListenerInvoker(listenerInvoker);
         
-        invoker.addEventListener("testId", new String[] { "onSelect" }, "fooListener");
+        invoker.addEventListener("testId", new String[] { "onSelect" }, "fooListener",
+                null, false);
         
         comp.getId();
         setReturnValue(comp, "testId");
@@ -107,7 +109,8 @@
         ComponentEventInvoker invoker = new ComponentEventInvoker();
         invoker.setListenerInvoker(listenerInvoker);
         
-        invoker.addElementEventListener("testId", new String[] { "onSelect" }, "fooListener");
+        invoker.addElementEventListener("testId", new String[] { "onSelect" }, 
+                "fooListener", null, false);
         
         comp.getId();
         setReturnValue(comp, "testId");