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/05/21 19:56:11 UTC

svn commit: r408205 - in /tapestry/tapestry4/trunk: annotations/src/descriptor/META-INF/ annotations/src/java/org/apache/tapestry/annotations/ annotations/src/test/org/apache/tapestry/annotations/ examples/TimeTracker/src/java/org/apache/tapestry/timet...

Author: jkuhnert
Date: Sun May 21 10:56:10 2006
New Revision: 408205

URL: http://svn.apache.org/viewvc?rev=408205&view=rev
Log:
Some enhancements for event listener.

Added:
    tapestry/tapestry4/trunk/annotations/src/java/org/apache/tapestry/annotations/EventListener.java
    tapestry/tapestry4/trunk/annotations/src/java/org/apache/tapestry/annotations/EventListenerAnnotationWorker.java
    tapestry/tapestry4/trunk/annotations/src/test/org/apache/tapestry/annotations/TestEventListenerAnnotationWorker.java
    tapestry/tapestry4/trunk/framework/src/descriptor/META-INF/tapestry.event.xml
    tapestry/tapestry4/trunk/framework/src/descriptor/META-INF/tapestry.render.xml
    tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/ComponentEvent.script
    tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/IDirectEvent.java
    tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/dojo/html/WidgetEvent.script
    tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/engine/DirectEventService.java
    tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/engine/DirectEventServiceParameter.java
    tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/enhance/InjectEventInvokerWorker.java
    tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/event/BrowserEvent.java
    tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/internal/
    tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/internal/event/
    tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/internal/event/ComponentEventProperty.java
    tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/internal/event/package.html
    tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/services/ComponentRenderWorker.java
    tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/services/impl/ComponentEventConnectionWorker.java
    tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/services/impl/ComponentEventInvoker.java
    tapestry/tapestry4/trunk/framework/src/test/org/apache/tapestry/enhance/TestInjectEventInvokerWorker.java
Modified:
    tapestry/tapestry4/trunk/annotations/src/descriptor/META-INF/hivemodule.xml
    tapestry/tapestry4/trunk/annotations/src/test/org/apache/tapestry/annotations/AnnotatedPage.java
    tapestry/tapestry4/trunk/examples/TimeTracker/src/java/org/apache/tapestry/timetracker/page/TaskEntryPage.java
    tapestry/tapestry4/trunk/framework/src/descriptor/META-INF/hivemodule.xml
    tapestry/tapestry4/trunk/framework/src/descriptor/META-INF/tapestry.enhance.xml
    tapestry/tapestry4/trunk/framework/src/descriptor/META-INF/tapestry.services.xml
    tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/AbstractComponent.java
    tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/IComponent.java
    tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/TapestryMessages.java
    tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/TapestryStrings2.properties
    tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/enhance/AutowireWorker.java
    tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/pageload/PageLoader.java
    tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/services/impl/DefaultResponseBuilder.java
    tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/services/impl/DefaultResponseContributorImpl.java
    tapestry/tapestry4/trunk/framework/src/test/org/apache/tapestry/form/MockForm.java

Modified: tapestry/tapestry4/trunk/annotations/src/descriptor/META-INF/hivemodule.xml
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/annotations/src/descriptor/META-INF/hivemodule.xml?rev=408205&r1=408204&r2=408205&view=diff
==============================================================================
--- tapestry/tapestry4/trunk/annotations/src/descriptor/META-INF/hivemodule.xml (original)
+++ tapestry/tapestry4/trunk/annotations/src/descriptor/META-INF/hivemodule.xml Sun May 21 10:56:10 2006
@@ -122,7 +122,20 @@
     <worker annotation="Component" object="instance:ComponentAnnotationWorker"/>
     <worker annotation="InjectMeta" object="instance:InjectMetaAnnotationWorker"/>
     <worker annotation="InjectScript" object="instance:InjectScriptAnnotationWorker"/>
+    <worker annotation="EventListener" object="service:EventListenerAnnotationWorker"/>
   </contribution>
+  
+  <service-point id="EventListenerAnnotationWorker" interface="MethodAnnotationEnhancementWorker">
+    
+    Connects IActionListener method invocations with client side javascript events.
+    
+    <invoke-factory>
+      <construct class="EventListenerAnnotationWorker">
+        <set-service property="componentEventInvoker" service-id="tapestry.event.ComponentEventInvoker"/>
+      </construct>
+    </invoke-factory>
+    
+  </service-point>
   
   <service-point id="InjectObjectAnnotationWorker" interface="MethodAnnotationEnhancementWorker">
     

Added: tapestry/tapestry4/trunk/annotations/src/java/org/apache/tapestry/annotations/EventListener.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/annotations/src/java/org/apache/tapestry/annotations/EventListener.java?rev=408205&view=auto
==============================================================================
--- tapestry/tapestry4/trunk/annotations/src/java/org/apache/tapestry/annotations/EventListener.java (added)
+++ tapestry/tapestry4/trunk/annotations/src/java/org/apache/tapestry/annotations/EventListener.java Sun May 21 10:56:10 2006
@@ -0,0 +1,47 @@
+// Copyright May 14, 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.annotations;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation used to connect an event on a component / page 
+ * with a particular listener method. This is currently intended
+ * to be used to connect client side events to listener methods but
+ * may have uses elsewhere.
+ * 
+ * @author jkuhnert
+ */
+@Target({ ElementType.METHOD })
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface EventListener
+{
+    /**
+     * The unique {@link IComponent} or html element ids of the targeted 
+     * sources that this listener will be listening to events on. These 
+     * ids may be specified as constant string values or OGNL expressions.
+     */
+    String[] targets();
+    
+    /**
+     * The list of events that should cause this listener to invoke. 
+     * Ie <code>events = {"onClick", "onOptionSelect"}</code> etc..
+     */
+    String[] events();
+}

Added: tapestry/tapestry4/trunk/annotations/src/java/org/apache/tapestry/annotations/EventListenerAnnotationWorker.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/annotations/src/java/org/apache/tapestry/annotations/EventListenerAnnotationWorker.java?rev=408205&view=auto
==============================================================================
--- tapestry/tapestry4/trunk/annotations/src/java/org/apache/tapestry/annotations/EventListenerAnnotationWorker.java (added)
+++ tapestry/tapestry4/trunk/annotations/src/java/org/apache/tapestry/annotations/EventListenerAnnotationWorker.java Sun May 21 10:56:10 2006
@@ -0,0 +1,56 @@
+// Copyright May 14, 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.annotations;
+
+import java.lang.reflect.Method;
+
+import org.apache.hivemind.Location;
+import org.apache.tapestry.enhance.EnhancementOperation;
+import org.apache.tapestry.services.impl.ComponentEventInvoker;
+import org.apache.tapestry.spec.IComponentSpecification;
+
+
+/**
+ * Performs {@link EventListener} annotation enhancements on components.
+ * 
+ * @author jkuhnert
+ */
+public class EventListenerAnnotationWorker implements MethodAnnotationEnhancementWorker
+{
+    private ComponentEventInvoker _invoker;
+    
+    /** 
+     * {@inheritDoc}
+     */
+    public void performEnhancement(EnhancementOperation op, IComponentSpecification spec, 
+            Method method, Location location)
+    {
+        EventListener listener = method.getAnnotation(EventListener.class);
+        
+        String[] targets = listener.targets();
+        
+        for (int i=0; i < targets.length; i++)
+            _invoker.addEventListener(targets[i], listener.events(), method.getName());
+        
+    }
+    
+    /**
+     * Injected.
+     * @param invoker
+     */
+    public void setComponentEventInvoker(ComponentEventInvoker invoker)
+    {
+        _invoker = invoker;
+    }
+}

Modified: tapestry/tapestry4/trunk/annotations/src/test/org/apache/tapestry/annotations/AnnotatedPage.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/annotations/src/test/org/apache/tapestry/annotations/AnnotatedPage.java?rev=408205&r1=408204&r2=408205&view=diff
==============================================================================
--- tapestry/tapestry4/trunk/annotations/src/test/org/apache/tapestry/annotations/AnnotatedPage.java (original)
+++ tapestry/tapestry4/trunk/annotations/src/test/org/apache/tapestry/annotations/AnnotatedPage.java Sun May 21 10:56:10 2006
@@ -143,4 +143,7 @@
 
     @InitialValue("fred")
     public abstract int getPropertyWithInitialValue();
+    
+    @EventListener(events = { "onClick" }, targets = { "email" })
+    public void eventListener() { }
 }

Added: tapestry/tapestry4/trunk/annotations/src/test/org/apache/tapestry/annotations/TestEventListenerAnnotationWorker.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/annotations/src/test/org/apache/tapestry/annotations/TestEventListenerAnnotationWorker.java?rev=408205&view=auto
==============================================================================
--- tapestry/tapestry4/trunk/annotations/src/test/org/apache/tapestry/annotations/TestEventListenerAnnotationWorker.java (added)
+++ tapestry/tapestry4/trunk/annotations/src/test/org/apache/tapestry/annotations/TestEventListenerAnnotationWorker.java Sun May 21 10:56:10 2006
@@ -0,0 +1,59 @@
+// Copyright May 20, 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.annotations;
+
+import java.lang.reflect.Method;
+import java.util.List;
+
+import org.apache.hivemind.Location;
+import org.apache.tapestry.enhance.EnhancementOperation;
+import org.apache.tapestry.internal.event.ComponentEventProperty;
+import org.apache.tapestry.services.impl.ComponentEventInvoker;
+import org.apache.tapestry.spec.IComponentSpecification;
+
+
+/**
+ * Tests functionality of {@link TestEventListenerAnnotationWorker}.
+ * @author jkuhnert
+ */
+public class TestEventListenerAnnotationWorker extends BaseAnnotationTestCase
+{
+
+    public void testEventConnection()
+    {
+        Location l = newLocation();
+        
+        EnhancementOperation op = newOp();
+        IComponentSpecification spec = newSpec();
+        
+        EventListenerAnnotationWorker worker = new EventListenerAnnotationWorker();
+        ComponentEventInvoker invoker = new ComponentEventInvoker();
+        worker.setComponentEventInvoker(invoker);
+        
+        replayControls();
+        
+        Method m = findMethod(AnnotatedPage.class, "eventListener");
+        worker.performEnhancement(op, spec, m, l);
+        
+        verifyControls();
+        
+        ComponentEventProperty property = invoker.getComponentEvents("email");
+        assertNotNull(property);
+        
+        List listeners = property.getEventListeners("onClick");
+        assertNotNull(listeners);
+        assertEquals(1, listeners.size());
+    }
+
+}

Modified: tapestry/tapestry4/trunk/examples/TimeTracker/src/java/org/apache/tapestry/timetracker/page/TaskEntryPage.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/examples/TimeTracker/src/java/org/apache/tapestry/timetracker/page/TaskEntryPage.java?rev=408205&r1=408204&r2=408205&view=diff
==============================================================================
--- tapestry/tapestry4/trunk/examples/TimeTracker/src/java/org/apache/tapestry/timetracker/page/TaskEntryPage.java (original)
+++ tapestry/tapestry4/trunk/examples/TimeTracker/src/java/org/apache/tapestry/timetracker/page/TaskEntryPage.java Sun May 21 10:56:10 2006
@@ -18,6 +18,7 @@
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.tapestry.annotations.Component;
+import org.apache.tapestry.annotations.EventListener;
 import org.apache.tapestry.annotations.InjectObject;
 import org.apache.tapestry.dojo.form.Autocompleter;
 import org.apache.tapestry.form.BeanPropertySelectionModel;
@@ -68,5 +69,16 @@
     public void addTask()
     {
         _log.debug("addTask() selected task is " + getSelectedProject().getName());
+    }
+    
+    /**
+     * Invoked when an item is selected from the project
+     * selection list.
+     */
+    @EventListener(events = {"selectOption"}, 
+            targets = { "projectChoose" })
+    public void projectSelected()
+    {
+        
     }
 }

Modified: tapestry/tapestry4/trunk/framework/src/descriptor/META-INF/hivemodule.xml
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/framework/src/descriptor/META-INF/hivemodule.xml?rev=408205&r1=408204&r2=408205&view=diff
==============================================================================
--- tapestry/tapestry4/trunk/framework/src/descriptor/META-INF/hivemodule.xml (original)
+++ tapestry/tapestry4/trunk/framework/src/descriptor/META-INF/hivemodule.xml Sun May 21 10:56:10 2006
@@ -47,6 +47,9 @@
   <sub-module descriptor="tapestry.listener.xml"/>
   <sub-module descriptor="tapestry.form.xml"/>
   <sub-module descriptor="tapestry.l10n.xml"/>
+  <sub-module descriptor="tapestry.event.xml"/>
+  <sub-module descriptor="tapestry.render.xml"/>
+  
   
   <service-point id="ClasspathResourceFactory">
   

Modified: tapestry/tapestry4/trunk/framework/src/descriptor/META-INF/tapestry.enhance.xml
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/framework/src/descriptor/META-INF/tapestry.enhance.xml?rev=408205&r1=408204&r2=408205&view=diff
==============================================================================
--- tapestry/tapestry4/trunk/framework/src/descriptor/META-INF/tapestry.enhance.xml (original)
+++ tapestry/tapestry4/trunk/framework/src/descriptor/META-INF/tapestry.enhance.xml Sun May 21 10:56:10 2006
@@ -81,6 +81,7 @@
 
     <command id="inject-messages" object="service:InjectMessagesWorker" before="abstract-property"/>    
     <command id="inject-specification" object="service:InjectSpecificationWorker" before="abstract-property"/>
+    <command id="inject-event-invoker" object="service:InjectEventInvokerWorker" before="abstract-property"/>
     <command id="specified-property" object="service:SpecifiedPropertyWorker" before="abstract-property"/>
     <command id="parameter" object="service:ParameterPropertyWorker" before="abstract-property"/>
     <command id="dispatch-inject" object="service:DispatchToInjectWorker" before="abstract-property"/>
@@ -171,6 +172,18 @@
     
     <invoke-factory>
       <construct class="InjectSpecificationWorker"/>
+    </invoke-factory>
+    
+  </service-point>
+  
+  <service-point id="InjectEventInvokerWorker" interface="EnhancementWorker">
+    
+    Injects the eventInvoker property into all components.
+    
+    <invoke-factory>
+      <construct class="InjectEventInvokerWorker">
+        <set-service property="componentEventInvoker" service-id="tapestry.event.ComponentEventInvoker" />
+      </construct>
     </invoke-factory>
     
   </service-point>

Added: tapestry/tapestry4/trunk/framework/src/descriptor/META-INF/tapestry.event.xml
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/framework/src/descriptor/META-INF/tapestry.event.xml?rev=408205&view=auto
==============================================================================
--- tapestry/tapestry4/trunk/framework/src/descriptor/META-INF/tapestry.event.xml (added)
+++ tapestry/tapestry4/trunk/framework/src/descriptor/META-INF/tapestry.event.xml Sun May 21 10:56:10 2006
@@ -0,0 +1,49 @@
+<?xml version="1.0"?>
+<!-- 
+   Copyright 2005 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.
+-->
+
+<module id="tapestry.event" version="4.1.0" >
+  
+  Mappings from client side events to IActionListener instances.
+  
+  <service-point id="ComponentEventInvoker" interface="org.apache.tapestry.services.impl.ComponentEventInvoker">
+    
+    Manages invoking/connecting events between components and browser.
+    
+    <invoke-factory>
+      <construct class="org.apache.tapestry.services.impl.ComponentEventInvoker">
+        <event-listener service-id="tapestry.ResetEventHub"/>
+      </construct>
+    </invoke-factory>
+    
+  </service-point>  
+  
+  <contribution configuration-id="tapestry.services.FactoryServices">
+        <service name="directevent" object="service:tapestry.event.DirectEvent" />
+  </contribution>
+  
+  <service-point id="DirectEvent" interface="org.apache.tapestry.engine.IEngineService">
+        <invoke-factory>
+            <construct class="org.apache.tapestry.engine.DirectEventService">
+                <set-object property="responseRenderer" value="infrastructure:responseRenderer" />
+                <set-object property="request" value="infrastructure:request" />
+                <set-object property="linkFactory" value="infrastructure:linkFactory" />
+                <set-object property="requestCycle" value="infrastructure:requestCycle" />
+            </construct>
+        </invoke-factory>
+    </service-point>
+  
+</module>
\ No newline at end of file

Added: tapestry/tapestry4/trunk/framework/src/descriptor/META-INF/tapestry.render.xml
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/framework/src/descriptor/META-INF/tapestry.render.xml?rev=408205&view=auto
==============================================================================
--- tapestry/tapestry4/trunk/framework/src/descriptor/META-INF/tapestry.render.xml (added)
+++ tapestry/tapestry4/trunk/framework/src/descriptor/META-INF/tapestry.render.xml Sun May 21 10:56:10 2006
@@ -0,0 +1,61 @@
+<?xml version="1.0"?>
+<!-- 
+   Copyright 2005 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.
+-->
+
+<module id="tapestry.render" version="4.1.0" >
+  
+  Various rendering services.
+  
+  <service-point id="ComponentRenderChain" interface="org.apache.tapestry.services.ComponentRenderWorker">
+    
+    The chain of enhancement workers that render after each individual
+    component renders. Configured from ComponentRenderWorkers configuration point.
+    
+    <invoke-factory service-id="hivemind.lib.ChainFactory">
+      <construct configuration-id="ComponentRenderWorkers"/>
+    </invoke-factory>
+    
+  </service-point>
+  
+  <configuration-point id="ComponentRenderWorkers" schema-id="hivemind.lib.ChainContribution">
+    
+    Provides the logic for component class render contributions.
+    
+  </configuration-point>
+  
+  <service-point id="ComponentEventConnectionWorker" 
+                interface="org.apache.tapestry.services.ComponentRenderWorker">
+    
+    Wires javascript events to components, adds javascript contributions to 
+    render.
+    
+    <invoke-factory>
+      <construct class="org.apache.tapestry.services.impl.ComponentEventConnectionWorker">
+        <set-service property="componentEventInvoker" service-id="tapestry.event.ComponentEventInvoker"/>
+        <set-service property="eventEngine" service-id="tapestry.event.DirectEvent"/>
+        <set property="componentScript" value="/org/apache/tapestry/ComponentEvent.script" />
+        <set property="widgetScript" value="/org/apache/tapestry/dojo/html/WidgetEvent.script" />
+        <set-service property="scriptSource" service-id="tapestry.script.ScriptSource"/>
+      </construct>
+    </invoke-factory>
+  
+  </service-point>
+  
+  <contribution configuration-id="ComponentRenderWorkers">
+    <command id="component-event-connection" object="service:ComponentEventConnectionWorker" />
+  </contribution>
+  
+</module>
\ No newline at end of file

Modified: tapestry/tapestry4/trunk/framework/src/descriptor/META-INF/tapestry.services.xml
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/framework/src/descriptor/META-INF/tapestry.services.xml?rev=408205&r1=408204&r2=408205&view=diff
==============================================================================
--- tapestry/tapestry4/trunk/framework/src/descriptor/META-INF/tapestry.services.xml (original)
+++ tapestry/tapestry4/trunk/framework/src/descriptor/META-INF/tapestry.services.xml Sun May 21 10:56:10 2006
@@ -256,6 +256,7 @@
                 <set-service property="localeManager" service-id="tapestry.request.RequestLocaleManager"/>
                 <set-object property="markupWriterSource"  value="infrastructure:markupWriterSource"/>
                 <set-object property="webResponse" value="infrastructure:response"/>
+                <set-service property="componentRenderWorker" service-id="tapestry.render.ComponentRenderChain" />
             </construct>
         </invoke-factory>
     </service-point>

Modified: tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/AbstractComponent.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/AbstractComponent.java?rev=408205&r1=408204&r2=408205&view=diff
==============================================================================
--- tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/AbstractComponent.java (original)
+++ tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/AbstractComponent.java Sun May 21 10:56:10 2006
@@ -29,8 +29,10 @@
 import org.apache.hivemind.util.PropertyUtils;
 import org.apache.tapestry.bean.BeanProvider;
 import org.apache.tapestry.engine.IPageLoader;
+import org.apache.tapestry.event.BrowserEvent;
 import org.apache.tapestry.event.PageEvent;
 import org.apache.tapestry.listener.ListenerMap;
+import org.apache.tapestry.services.impl.ComponentEventInvoker;
 import org.apache.tapestry.spec.IComponentSpecification;
 import org.apache.tapestry.spec.IContainedComponent;
 
@@ -40,7 +42,7 @@
  * @author Howard Lewis Ship
  */
 
-public abstract class AbstractComponent extends BaseLocatable implements IComponent
+public abstract class AbstractComponent extends BaseLocatable implements IDirectEvent
 {
     private static final int MAP_SIZE = 5;
     
@@ -143,7 +145,7 @@
     /** @since 4.0 */
 
     private IContainedComponent _containedComponent;
-
+    
     public void addAsset(String name, IAsset asset)
     {
         Defense.notNull(name, "name");
@@ -644,7 +646,7 @@
      */
 
     protected abstract void renderComponent(IMarkupWriter writer, IRequestCycle cycle);
-
+    
     /**
      * Invoked by {@link #render(IMarkupWriter, IRequestCycle)}after the component renders. This
      * implementation does nothing.
@@ -856,5 +858,28 @@
 
         _containedComponent = containedComponent;
     }
-
+    
+    /**
+     * {@inheritDoc}
+     */
+    public ComponentEventInvoker getEventInvoker()
+    {
+        throw new IllegalStateException(TapestryMessages.providedByEnhancement("getEventInvoker"));
+    }
+    
+    /**
+     * {@inheritDoc}
+     */
+    public void triggerEvent(IRequestCycle cycle, BrowserEvent event)
+    {
+        getEventInvoker().invokeListeners(this, cycle, event);
+    }
+    
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isStateful()
+    {
+        return false;
+    }
 }

Added: tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/ComponentEvent.script
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/ComponentEvent.script?rev=408205&view=auto
==============================================================================
--- tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/ComponentEvent.script (added)
+++ tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/ComponentEvent.script Sun May 21 10:56:10 2006
@@ -0,0 +1,25 @@
+<?xml version="1.0"?>
+<!DOCTYPE script PUBLIC
+  "-//Apache Software Foundation//Tapestry Script Specification 3.0//EN"
+  "http://jakarta.apache.org/tapestry/dtd/Script_3_0.dtd">
+<script>
+<include-script resource-path="/org/apache/tapestry/dojo/Widget.js"/>
+
+<input-symbol key="component" required="yes" />
+<input-symbol key="url" required="yes" />
+<input-symbol key="events" required="yes" />
+    <body>
+        <unique>
+            dojo.require("dojo.io");
+            dojo.require("dojo.json");
+            dojo.require("dojo.event");
+        </unique>
+    </body>
+    <initialization>
+        <foreach expression="events" key="event">
+        dojo.event.connect(dojo.byId("${component.id}"), "${event}", function(e) {
+            dojo.debug("Event fired");
+        });
+        </foreach>
+    </initialization>
+</script>
\ No newline at end of file

Modified: tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/IComponent.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/IComponent.java?rev=408205&r1=408204&r2=408205&view=diff
==============================================================================
--- tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/IComponent.java (original)
+++ tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/IComponent.java Sun May 21 10:56:10 2006
@@ -21,6 +21,7 @@
 import org.apache.hivemind.Messages;
 import org.apache.tapestry.engine.IPageLoader;
 import org.apache.tapestry.listener.ListenerMap;
+import org.apache.tapestry.services.impl.ComponentEventInvoker;
 import org.apache.tapestry.spec.IComponentSpecification;
 import org.apache.tapestry.spec.IContainedComponent;
 
@@ -30,7 +31,7 @@
  * Components are created dynamically from thier class names (part of the
  * {@link IComponentSpecification}).
  * 
- * @author Howard Leiws Ship
+ * @author Howard Lewis Ship
  */
 
 public interface IComponent extends IRender, LocationHolder
@@ -364,4 +365,13 @@
      * @since 4.0
      */
     void setContainedComponent(IContainedComponent containedComponent);
+    
+    /**
+     * Returns the event connection manager services that handles creating/accepting
+     * browser events associated with various properties of components.
+     * 
+     * @return eventInvoker, may not be null
+     * @since 4.1
+     */
+    ComponentEventInvoker getEventInvoker();
 }

Added: tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/IDirectEvent.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/IDirectEvent.java?rev=408205&view=auto
==============================================================================
--- tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/IDirectEvent.java (added)
+++ tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/IDirectEvent.java Sun May 21 10:56:10 2006
@@ -0,0 +1,45 @@
+// Copyright May 20, 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;
+
+import org.apache.tapestry.event.BrowserEvent;
+
+
+/**
+ * Interface that defines classes that may be invoked directly by
+ * the event service. 
+ * 
+ * @author jkuhnert
+ */
+public interface IDirectEvent extends IComponent
+{
+
+    /**
+     *  Invoked by the event service to have the component peform
+     *  the appropriate action. 
+     **/
+    
+    void triggerEvent(IRequestCycle cycle, BrowserEvent event);
+
+    /**
+     *  Invoked by the event service to query the component as to
+     *  whether it is stateful.  If stateful and no 
+     *  {@link javax.servlet.http.HttpSession} is active, then a
+     *  {@link org.apache.tapestry.StaleSessionException} is
+     *  thrown by the service.
+     * 
+     **/
+
+    boolean isStateful();
+}

Modified: tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/TapestryMessages.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/TapestryMessages.java?rev=408205&r1=408204&r2=408205&view=diff
==============================================================================
--- tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/TapestryMessages.java (original)
+++ tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/TapestryMessages.java Sun May 21 10:56:10 2006
@@ -70,6 +70,12 @@
                 .format("attempt-to-change-contained-component", component.getExtendedId());
     }
 
+    static String attemptToChangeEventInvoker(IComponent component)
+    {
+        return _formatter
+                .format("attempt-to-change-event-invoker", component.getExtendedId());
+    }
+    
     static String componentWrongType(IComponent component, Class expectedType)
     {
         return _formatter.format("component-wrong-type", component.getExtendedId(), expectedType

Modified: tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/TapestryStrings2.properties
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/TapestryStrings2.properties?rev=408205&r1=408204&r2=408205&view=diff
==============================================================================
--- tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/TapestryStrings2.properties (original)
+++ tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/TapestryStrings2.properties Sun May 21 10:56:10 2006
@@ -21,4 +21,5 @@
 provided-by-enhancement=Method {0}() is not implemented. An implementation of this method should be provided via runtime class enhancement.
 no-form=Component {0} must be enclosed by a form, but no Form component has been stored into the request cycle.
 attempt-to-change-contained-component=Attempt to change containedComponent property of component {0}, which is not allowed.
+attempt-to-change-event-invoker=Attempt to change eventInvoker property of component {0}, which is not allowed.
 component-wrong-type=Component {0} is not assignable to type {1}.

Added: tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/dojo/html/WidgetEvent.script
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/dojo/html/WidgetEvent.script?rev=408205&view=auto
==============================================================================
--- tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/dojo/html/WidgetEvent.script (added)
+++ tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/dojo/html/WidgetEvent.script Sun May 21 10:56:10 2006
@@ -0,0 +1,25 @@
+<?xml version="1.0"?>
+<!DOCTYPE script PUBLIC
+  "-//Apache Software Foundation//Tapestry Script Specification 3.0//EN"
+  "http://jakarta.apache.org/tapestry/dtd/Script_3_0.dtd">
+<script>
+<include-script resource-path="/org/apache/tapestry/dojo/Widget.js"/>
+
+<input-symbol key="component" required="yes" />
+<input-symbol key="url" required="yes" />
+<input-symbol key="events" required="yes" />
+    <body>
+        <unique>
+            dojo.require("dojo.io");
+            dojo.require("dojo.json");
+            dojo.require("dojo.event");
+        </unique>
+    </body>
+    <initialization>
+        <foreach expression="events" key="event">
+        dojo.event.connect(dojo.widget.byId("${component.id}"), "${event}", function(e) {
+            dojo.debug("Event fired");
+        });
+        </foreach>
+    </initialization>
+</script>
\ No newline at end of file

Added: tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/engine/DirectEventService.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/engine/DirectEventService.java?rev=408205&view=auto
==============================================================================
--- tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/engine/DirectEventService.java (added)
+++ tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/engine/DirectEventService.java Sun May 21 10:56:10 2006
@@ -0,0 +1,182 @@
+// Copyright 2004, 2005 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.engine;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.hivemind.ApplicationRuntimeException;
+import org.apache.hivemind.util.Defense;
+import org.apache.tapestry.IComponent;
+import org.apache.tapestry.IDirectEvent;
+import org.apache.tapestry.IPage;
+import org.apache.tapestry.IRequestCycle;
+import org.apache.tapestry.StaleSessionException;
+import org.apache.tapestry.Tapestry;
+import org.apache.tapestry.event.BrowserEvent;
+import org.apache.tapestry.services.LinkFactory;
+import org.apache.tapestry.services.ResponseRenderer;
+import org.apache.tapestry.services.ServiceConstants;
+import org.apache.tapestry.web.WebRequest;
+import org.apache.tapestry.web.WebSession;
+
+/**
+ * Implementation of the direct event service, which encodes the page and component id in the service
+ * context, and passes application-defined parameters as well.
+ * 
+ * @author jkuhnert
+ * @since 4.1
+ */
+
+public class DirectEventService implements IEngineService
+{
+    /** @since 4.0 */
+    protected ResponseRenderer _responseRenderer;
+
+    /** @since 4.0 */
+    protected LinkFactory _linkFactory;
+
+    /** @since 4.0 */
+    protected WebRequest _request;
+
+    /** @since 4.0 */
+    private IRequestCycle _requestCycle;
+
+    public ILink getLink(boolean post, Object parameter)
+    {
+        Defense.isAssignable(parameter, DirectEventServiceParameter.class, "parameter");
+
+        DirectEventServiceParameter dsp = (DirectEventServiceParameter) parameter;
+
+        IComponent component = dsp.getDirect();
+
+        // New since 1.0.1, we use the component to determine
+        // the page, not the cycle. Through the use of tricky
+        // things such as Block/InsertBlock, it is possible
+        // that a component from a page different than
+        // the response page will render.
+        // In 1.0.6, we start to record *both* the render page
+        // and the component page (if different).
+
+        IPage activePage = _requestCycle.getPage();
+        IPage componentPage = component.getPage();
+        
+        Map parameters = new HashMap();
+        
+        boolean stateful = _request.getSession(false) != null;
+        
+        parameters.put(ServiceConstants.PAGE, activePage.getPageName());
+        parameters.put(ServiceConstants.COMPONENT, component.getIdPath());
+        parameters.put(ServiceConstants.CONTAINER, componentPage == activePage ? null
+                : componentPage.getPageName());
+        parameters.put(ServiceConstants.SESSION, stateful ? "T" : null);
+        if (dsp.getUpdateParts() != null && dsp.getUpdateParts().length > 0)
+            parameters.put(ServiceConstants.UPDATE_PARTS, dsp.getUpdateParts());
+        if (dsp.isJSON())
+            parameters.put("json", String.valueOf(dsp.isJSON()));
+        parameters.put(ServiceConstants.PARAMETER, dsp.getServiceParameters());
+        
+        return _linkFactory.constructLink(this, post, parameters, true);
+    }
+
+    public void service(IRequestCycle cycle) throws IOException
+    {
+        String componentId = cycle.getParameter(ServiceConstants.COMPONENT);
+        String componentPageName = cycle.getParameter(ServiceConstants.CONTAINER);
+        String activePageName = cycle.getParameter(ServiceConstants.PAGE);
+        boolean activeSession = cycle.getParameter(ServiceConstants.SESSION) != null;
+        
+        IPage page = cycle.getPage(activePageName);
+
+        cycle.activate(page);
+
+        IPage componentPage = componentPageName == null ? page : cycle.getPage(componentPageName);
+
+        IComponent component = componentPage.getNestedComponent(componentId);
+
+        IDirectEvent direct = null;
+
+        try
+        {
+            direct = (IDirectEvent) component;
+        }
+        catch (ClassCastException ex)
+        {
+            throw new ApplicationRuntimeException(EngineMessages.wrongComponentType(
+                    component,
+                    IDirectEvent.class), component, null, ex);
+        }
+
+        // Check for a StaleSession only when the session was stateful when
+        // the link was created.
+
+        if (activeSession && direct.isStateful())
+        {
+            WebSession session = _request.getSession(false);
+
+            if (session == null || session.isNew())
+                throw new StaleSessionException(EngineMessages.requestStateSession(direct),
+                        componentPage);
+        }
+
+        Object[] parameters = _linkFactory.extractListenerParameters(cycle);
+
+        triggerComponent(cycle, direct, parameters);
+
+        // Render the response. This will be the active page
+        // unless the direct component (or its delegate) changes it.
+
+        _responseRenderer.renderResponse(cycle);
+    }
+
+    /** @since 4.0 */
+
+    protected void triggerComponent(IRequestCycle cycle, IDirectEvent direct, Object[] parameters)
+    {
+        cycle.setListenerParameters(parameters);
+
+        direct.triggerEvent(cycle, new BrowserEvent("onSelect"));
+    }
+
+    public String getName()
+    {
+        return Tapestry.DIRECT_SERVICE;
+    }
+
+    /** @since 4.0 */
+    public void setResponseRenderer(ResponseRenderer responseRenderer)
+    {
+        _responseRenderer = responseRenderer;
+    }
+
+    /** @since 4.0 */
+    public void setLinkFactory(LinkFactory linkFactory)
+    {
+        _linkFactory = linkFactory;
+    }
+
+    /** @since 4.0 */
+    public void setRequest(WebRequest request)
+    {
+        _request = request;
+    }
+
+    /** @since 4.0 */
+    public void setRequestCycle(IRequestCycle requestCycle)
+    {
+        _requestCycle = requestCycle;
+    }
+}

Added: tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/engine/DirectEventServiceParameter.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/engine/DirectEventServiceParameter.java?rev=408205&view=auto
==============================================================================
--- tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/engine/DirectEventServiceParameter.java (added)
+++ tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/engine/DirectEventServiceParameter.java Sun May 21 10:56:10 2006
@@ -0,0 +1,84 @@
+// Copyright 2004, 2005 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.engine;
+
+import org.apache.hivemind.util.Defense;
+import org.apache.tapestry.IDirectEvent;
+
+/**
+ * Parameter object used by {@link org.apache.tapestry.engine.DirectEventService}.
+ * 
+ * @author jkuhnert
+ * @since 4.1
+ */
+public class DirectEventServiceParameter
+{
+    protected IDirectEvent _direct;
+
+    protected Object[] _serviceParameters;
+
+    protected String[] _updateParts;
+    
+    protected boolean _json;
+    
+    public DirectEventServiceParameter(IDirectEvent direct)
+    {
+        this(direct, null, null, false);
+    }
+
+    public DirectEventServiceParameter(IDirectEvent direct, Object[] serviceParameters)
+    {
+        this(direct, serviceParameters, null, false);
+    }
+    
+    /**
+     * Creates a new direct service parameter map. 
+     * 
+     * @param direct The object implementing the direct triggerable interface
+     * @param serviceParameters The parameters for the triggered object
+     * @param updateParts The parts expected to be updated on any returned response
+     * triggerd by this direct call.
+     */
+    public DirectEventServiceParameter(IDirectEvent direct, Object[] serviceParameters,
+            String[] updateParts, boolean json)
+    {
+        Defense.notNull(direct, "direct");
+        
+        _direct = direct;
+        _serviceParameters = serviceParameters;
+        _updateParts = updateParts;
+        _json = json;
+    }
+
+    public IDirectEvent getDirect()
+    {
+        return _direct;
+    }
+
+    public Object[] getServiceParameters()
+    {
+        return _serviceParameters;
+    }
+    
+    public String[] getUpdateParts()
+    {
+        return _updateParts;
+    }
+    
+    public boolean isJSON()
+    {
+        return _json;
+    }
+}

Modified: tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/enhance/AutowireWorker.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/enhance/AutowireWorker.java?rev=408205&r1=408204&r2=408205&view=diff
==============================================================================
--- tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/enhance/AutowireWorker.java (original)
+++ tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/enhance/AutowireWorker.java Sun May 21 10:56:10 2006
@@ -56,8 +56,11 @@
             if( _module.containsService( propertyType )) {
                 final Object serviceProxy = _module.getService( propertyType );
                 final Location location = spec.getLocation();
+                
                 _log.debug( EnhanceMessages.autowiring( propertyName, spec, serviceProxy ) );
+                
                 final String fieldName = op.addInjectedField( "_$" + propertyName, propertyType, serviceProxy );
+                
                 EnhanceUtils.createSimpleAccessor( op, fieldName, propertyName, propertyType, location );
                 op.claimReadonlyProperty( propertyName );
             }

Added: tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/enhance/InjectEventInvokerWorker.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/enhance/InjectEventInvokerWorker.java?rev=408205&view=auto
==============================================================================
--- tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/enhance/InjectEventInvokerWorker.java (added)
+++ tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/enhance/InjectEventInvokerWorker.java Sun May 21 10:56:10 2006
@@ -0,0 +1,77 @@
+// Copyright 2005 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.enhance;
+
+import org.apache.hivemind.ErrorLog;
+import org.apache.hivemind.util.Defense;
+import org.apache.tapestry.services.impl.ComponentEventInvoker;
+import org.apache.tapestry.spec.IComponentSpecification;
+
+/**
+ * Injects the component's event invoker as the
+ * {@link org.apache.tapestry.IComponent#getEventInvoker() eventInvoker}property.
+ * 
+ * @author jkuhnert
+ * @since 4.1
+ */
+public class InjectEventInvokerWorker implements EnhancementWorker
+{
+
+    public static final String PROPERTY_NAME = "eventInvoker";
+
+    private ErrorLog _errorLog;
+
+    private ComponentEventInvoker _invoker;
+    
+    public void performEnhancement(EnhancementOperation op, IComponentSpecification spec)
+    {
+        try
+        {
+            injectEventInvoker(op, spec);
+        }
+        catch (Exception ex)
+        {
+            _errorLog.error(EnhanceMessages.errorAddingProperty(
+                    PROPERTY_NAME, op.getBaseClass(), ex), spec
+                    .getLocation(), ex);
+        }
+    }
+
+    public void injectEventInvoker(EnhancementOperation op, IComponentSpecification spec)
+    {
+        Defense.notNull(op, "op");
+        Defense.notNull(spec, "spec");
+        
+        op.claimReadonlyProperty(PROPERTY_NAME);
+        
+        String fieldName = op.addInjectedField("_$"
+                + PROPERTY_NAME, ComponentEventInvoker.class,
+                _invoker);
+        
+        EnhanceUtils.createSimpleAccessor(op, fieldName,
+                PROPERTY_NAME, ComponentEventInvoker.class,
+                spec.getLocation());
+    }
+
+    public void setErrorLog(ErrorLog errorLog)
+    {
+        _errorLog = errorLog;
+    }
+    
+    public void setComponentEventInvoker(ComponentEventInvoker invoker)
+    {
+        _invoker = invoker;
+    }
+}

Added: tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/event/BrowserEvent.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/event/BrowserEvent.java?rev=408205&view=auto
==============================================================================
--- tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/event/BrowserEvent.java (added)
+++ tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/event/BrowserEvent.java Sun May 21 10:56:10 2006
@@ -0,0 +1,43 @@
+// Copyright May 20, 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.event;
+
+
+/**
+ * Represents a client side generated browser event.
+ * 
+ * @author jkuhnert
+ */
+public class BrowserEvent
+{
+    private String _name;
+    
+    public BrowserEvent(String name)
+    {
+        _name = name;
+    }
+    
+    /**
+     * The name of the event that was generated. 
+     * 
+     * <p>
+     * Examples would be <code>onClick,onSelect,onLoad,etc...</code>.
+     * </p>
+     * @return The event name.
+     */
+    public String getName()
+    {
+        return _name;
+    }
+}

Added: tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/internal/event/ComponentEventProperty.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/internal/event/ComponentEventProperty.java?rev=408205&view=auto
==============================================================================
--- tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/internal/event/ComponentEventProperty.java (added)
+++ tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/internal/event/ComponentEventProperty.java Sun May 21 10:56:10 2006
@@ -0,0 +1,85 @@
+// Copyright May 20, 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.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+
+/**
+ * Represents a configured listener/event(s) binding for a 
+ * a component and the events that may be optionally listened
+ * for on the client browser.
+ * 
+ * @author jkuhnert
+ */
+public class ComponentEventProperty
+{
+    private Map _eventMap = new HashMap();
+    
+    /**
+     * Adds a listener bound to the specified client side
+     * events.
+     * @param events
+     * @param methodName
+     */
+    public void addListener(String[] events, String methodName)
+    {
+        for (int i=0; i < events.length; i++) {
+            addEventListener(events[i], methodName);
+        }
+    }
+    
+    /**
+     * Adds a listener to the specified client side event.
+     * @param event
+     * @param methodName
+     */
+    public void addEventListener(String event, String methodName)
+    {
+        List listeners = getEventListeners(event);
+        if (!listeners.contains(methodName))
+            listeners.add(methodName);
+    }
+    
+    /**
+     * Gets the current list of listeners for a specific event,
+     * creates a new instance if one doesn't exist already.
+     * 
+     * @param event
+     * @return
+     */
+    public List getEventListeners(String event)
+    {
+        List listeners = (List)_eventMap.get(event);
+        if (listeners == null) {
+            listeners = new ArrayList();
+            _eventMap.put(event, listeners);
+        }
+        
+        return listeners;
+    }
+    
+    /**
+     * The set of all events.
+     * @return The unique set of events.
+     */
+    public Set getEvents()
+    {
+        return _eventMap.keySet();
+    }
+}

Added: tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/internal/event/package.html
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/internal/event/package.html?rev=408205&view=auto
==============================================================================
--- tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/internal/event/package.html (added)
+++ tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/internal/event/package.html Sun May 21 10:56:10 2006
@@ -0,0 +1,16 @@
+<!doctype html public "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+<title>Tapestry: Web Application Framework</title>
+</head>
+<body>
+
+<p>
+Event related internal classes only. Use at your own risk as they may be changed/removed
+at any point.
+</p>
+
+@author Jesse Kuhnert <a href="mailto:jkuhnert@apache.org">jkuhnert@apache.org</a>
+
+</body>
+</html>

Modified: tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/pageload/PageLoader.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/pageload/PageLoader.java?rev=408205&r1=408204&r2=408205&view=diff
==============================================================================
--- tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/pageload/PageLoader.java (original)
+++ tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/pageload/PageLoader.java Sun May 21 10:56:10 2006
@@ -499,8 +499,6 @@
         String className = _componentClassProvider
                 .provideComponentClassName(context);
 
-        // String className = spec.getComponentClassName();
-
         if (HiveMind.isBlank(className))
             className = BaseComponent.class.getName();
         else

Added: tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/services/ComponentRenderWorker.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/services/ComponentRenderWorker.java?rev=408205&view=auto
==============================================================================
--- tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/services/ComponentRenderWorker.java (added)
+++ tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/services/ComponentRenderWorker.java Sun May 21 10:56:10 2006
@@ -0,0 +1,40 @@
+// Copyright May 20, 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.services;
+
+import org.apache.tapestry.IComponent;
+import org.apache.tapestry.IRequestCycle;
+
+
+/**
+ * Interface that defines the chain of render workers that will be 
+ * invoked after all {@link IComponent} render invocations.
+ * 
+ * @author jkuhnert
+ */
+public interface ComponentRenderWorker
+{
+    
+    /**
+     * Invoked just after the components render call, giving services 
+     * implementing the {@link ComponentRenderWorker} interface a guaranteed 
+     * state to work off of.
+     * 
+     * @param cycle
+     *          The associated request for this render.
+     * @param component
+     *          The component that has just been rendered.
+     */
+    void renderComponent(IRequestCycle cycle, IComponent component);
+}

Added: 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=408205&view=auto
==============================================================================
--- tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/services/impl/ComponentEventConnectionWorker.java (added)
+++ tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/services/impl/ComponentEventConnectionWorker.java Sun May 21 10:56:10 2006
@@ -0,0 +1,141 @@
+// Copyright May 20, 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.services.impl;
+
+import java.util.HashMap;
+import java.util.Map;
+
+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.IRequestCycle;
+import org.apache.tapestry.PageRenderSupport;
+import org.apache.tapestry.TapestryUtils;
+import org.apache.tapestry.dojo.IWidget;
+import org.apache.tapestry.engine.DirectEventServiceParameter;
+import org.apache.tapestry.engine.IEngineService;
+import org.apache.tapestry.engine.IScriptSource;
+import org.apache.tapestry.internal.event.ComponentEventProperty;
+import org.apache.tapestry.services.ComponentRenderWorker;
+
+
+/**
+ * Implementation that handles connecting events to listener
+ * method invocations.
+ * 
+ * @author jkuhnert
+ */
+public class ComponentEventConnectionWorker implements ComponentRenderWorker
+{
+    private ComponentEventInvoker _invoker;
+    
+    private IEngineService _eventEngine;
+    
+    private IScriptSource _scriptSource;
+    
+    private String _componentScript;
+    
+    private String _widgetScript;
+    
+    private ClassResolver _resolver;
+    
+    /** 
+     * {@inheritDoc}
+     */
+    public void renderComponent(IRequestCycle cycle, IComponent component)
+    {
+        if (!_invoker.hasEvents(component.getId()))
+            return;
+        
+        ComponentEventProperty prop = _invoker.getComponentEvents(component.getId());
+        
+        Map parms = new HashMap();
+        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());
+        
+        PageRenderSupport prs = TapestryUtils.getPageRenderSupport(cycle, component);
+        
+        Resource resource = getScript(component);
+        
+        _scriptSource.getScript(resource).execute(cycle, prs, parms);
+    }
+    
+    Resource getScript(IComponent component)
+    {
+        if (IWidget.class.isInstance(component))
+            return new ClasspathResource(_resolver, _widgetScript);
+        
+        return new ClasspathResource(_resolver, _componentScript);
+    }
+    
+    /**
+     * Sets the invoker to use/manage event connections.
+     * @param invoker
+     */
+    public void setComponentEventInvoker(ComponentEventInvoker invoker)
+    {
+        _invoker = invoker;
+    }
+    
+    /**
+     * Sets the engine service that will be used to construct callback
+     * URL references to invoke the specified components event listener.
+     * 
+     * @param eventEngine
+     */
+    public void setEventEngine(IEngineService eventEngine)
+    {
+        _eventEngine = eventEngine;
+    }
+    
+    /**
+     * The javascript that will be used to connect the component
+     * to its configured events. (if any)
+     * @param script
+     */
+    public void setComponentScript(String script)
+    {
+        _componentScript = script;
+    }
+    
+    /**
+     * The javascript that will be used to connect the widget component
+     * to its configured events. (if any)
+     * @param script
+     */
+    public void setWidgetScript(String script)
+    {
+        _widgetScript = script;
+    }
+    
+    /**
+     * The service that parses script files.
+     * @param scriptSource
+     */
+    public void setScriptSource(IScriptSource scriptSource)
+    {
+        _scriptSource = scriptSource;
+    }
+    
+    public void setClassResolver(ClassResolver resolver)
+    {
+        _resolver = resolver;
+    }
+}

Added: 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=408205&view=auto
==============================================================================
--- tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/services/impl/ComponentEventInvoker.java (added)
+++ tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/services/impl/ComponentEventInvoker.java Sun May 21 10:56:10 2006
@@ -0,0 +1,137 @@
+// Copyright May 20, 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.services.impl;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.hivemind.util.Defense;
+import org.apache.tapestry.IActionListener;
+import org.apache.tapestry.IComponent;
+import org.apache.tapestry.IRequestCycle;
+import org.apache.tapestry.event.BrowserEvent;
+import org.apache.tapestry.event.ResetEventListener;
+import org.apache.tapestry.internal.event.ComponentEventProperty;
+import org.apache.tapestry.listener.ListenerInvoker;
+
+
+/**
+ * Managed and handles invoking listener methods for components 
+ * in response to requested event listener invocations.
+ * 
+ * @author jkuhnert
+ */
+public class ComponentEventInvoker implements ResetEventListener
+{
+    private Map _components = new HashMap();
+    
+    private ListenerInvoker _invoker;
+    
+    /**
+     * Causes the configured listeners for the passed component to
+     * be invoked.
+     * @param component
+     *          The component that recieved the invocations.
+     * @param cycle
+     *          The associated request.
+     * @param event
+     *          The event that started it all.
+     */
+    public void invokeListeners(IComponent component, IRequestCycle cycle, 
+            BrowserEvent event)
+    {
+        Defense.notNull(component, "component");
+        Defense.notNull(cycle, "cycle");
+        Defense.notNull(event, "event");
+        
+        ComponentEventProperty prop = getComponentEvents(component.getId());
+        
+        List listeners = prop.getEventListeners(event.getName());
+        for (int i=0; i < listeners.size(); i++) {
+            String methodName = (String)listeners.get(i);
+            
+            IComponent container = component.getContainer();
+            if (container == null) // only IPage has no container
+                container = component; 
+            
+            IActionListener listener = component.getListeners().getListener(methodName);
+            _invoker.invokeListener(listener, component, cycle);
+        }
+    }
+    
+    /**
+     * Adds a deferred event listener binding for the specified component.
+     * 
+     * @param componentId 
+     *          The component to add an event listener for.
+     * @param events
+     *          The events that should cause the listener to be executed.
+     * @param methodName
+     *          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)
+    {
+        ComponentEventProperty property = getComponentEvents(componentId);
+        
+        property.addListener(events, methodName);
+    }
+    
+    /**
+     * Returns whether or not the specified component has any
+     * connected events.
+     * 
+     * @param componentId
+     *          The unique component id to check.
+     * @return True, if at least one listener is connected to the specified
+     *          component.
+     */
+    public boolean hasEvents(String componentId)
+    {
+        return _components.get(componentId) != null;
+    }
+    
+    /**
+     * Gets event properties fro the specified component, creates a new
+     * instance if one doesn't exist already.
+     * 
+     * @param id The component id 
+     * @return A new/existing instance.
+     */
+    public ComponentEventProperty getComponentEvents(String id)
+    {
+        ComponentEventProperty prop = (ComponentEventProperty)_components.get(id);
+        if (prop == null) {
+            prop = new ComponentEventProperty();
+            _components.put(id, prop);
+        }
+        
+        return prop;
+    }
+    
+    public void resetEventDidOccur()
+    {
+        _components.clear();
+    }
+    
+    /**
+     * Injected.
+     * @param invoker
+     */
+    public void setListenerInvoker(ListenerInvoker invoker)
+    {
+        _invoker = invoker;
+    }
+}

Modified: tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/services/impl/DefaultResponseBuilder.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/services/impl/DefaultResponseBuilder.java?rev=408205&r1=408204&r2=408205&view=diff
==============================================================================
--- tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/services/impl/DefaultResponseBuilder.java (original)
+++ tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/services/impl/DefaultResponseBuilder.java Sun May 21 10:56:10 2006
@@ -23,6 +23,7 @@
 import org.apache.tapestry.IRequestCycle;
 import org.apache.tapestry.engine.NullWriter;
 import org.apache.tapestry.markup.MarkupWriterSource;
+import org.apache.tapestry.services.ComponentRenderWorker;
 import org.apache.tapestry.services.RequestLocaleManager;
 import org.apache.tapestry.services.ResponseBuilder;
 import org.apache.tapestry.util.ContentType;
@@ -44,14 +45,16 @@
     
     public static final String ENCODING_KEY = "charset";
     
-    protected RequestLocaleManager _localeManager;
+    private RequestLocaleManager _localeManager;
     
-    protected MarkupWriterSource _markupWriterSource;
+    private MarkupWriterSource _markupWriterSource;
 
-    protected WebResponse _webResponse;
+    private WebResponse _webResponse;
+    
+    private ComponentRenderWorker _renderWorker;
     
     /** Writer that creates JSON output response. */
-    protected IMarkupWriter _writer;
+    private IMarkupWriter _writer;
     
     /**
      * Used in testing only.
@@ -75,11 +78,12 @@
      */
     public DefaultResponseBuilder(RequestLocaleManager localeManager, 
             MarkupWriterSource markupWriterSource,
-            WebResponse webResponse)
+            WebResponse webResponse, ComponentRenderWorker renderWorker)
     {
         _localeManager = localeManager;
         _markupWriterSource = markupWriterSource;
         _webResponse = webResponse;
+        _renderWorker = renderWorker;
     }
     
     /**
@@ -129,6 +133,9 @@
             render.render(_writer, cycle);
         else
             render.render(writer, cycle);
+        
+        if (IComponent.class.isInstance(render))
+            _renderWorker.renderComponent(cycle, (IComponent)render);
     }
     
     /** 

Modified: tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/services/impl/DefaultResponseContributorImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/services/impl/DefaultResponseContributorImpl.java?rev=408205&r1=408204&r2=408205&view=diff
==============================================================================
--- tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/services/impl/DefaultResponseContributorImpl.java (original)
+++ tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/services/impl/DefaultResponseContributorImpl.java Sun May 21 10:56:10 2006
@@ -17,6 +17,7 @@
 
 import org.apache.tapestry.IRequestCycle;
 import org.apache.tapestry.markup.MarkupWriterSource;
+import org.apache.tapestry.services.ComponentRenderWorker;
 import org.apache.tapestry.services.RequestLocaleManager;
 import org.apache.tapestry.services.ResponseBuilder;
 import org.apache.tapestry.services.ResponseContributor;
@@ -36,6 +37,8 @@
 
     protected WebResponse _webResponse;
     
+    private ComponentRenderWorker _renderWorker;
+    
     /**
      * {@inheritDoc}
      */
@@ -43,7 +46,7 @@
     throws IOException
     {
         return new DefaultResponseBuilder(_localeManager, _markupWriterSource,
-                _webResponse);
+                _webResponse, _renderWorker);
     }
     
     /**
@@ -67,5 +70,10 @@
     public void setWebResponse(WebResponse webResponse)
     {
         _webResponse = webResponse;
+    }
+    
+    public void setComponentRenderWorker(ComponentRenderWorker renderWorker)
+    {
+        _renderWorker = renderWorker;
     }
 }

Added: tapestry/tapestry4/trunk/framework/src/test/org/apache/tapestry/enhance/TestInjectEventInvokerWorker.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/framework/src/test/org/apache/tapestry/enhance/TestInjectEventInvokerWorker.java?rev=408205&view=auto
==============================================================================
--- tapestry/tapestry4/trunk/framework/src/test/org/apache/tapestry/enhance/TestInjectEventInvokerWorker.java (added)
+++ tapestry/tapestry4/trunk/framework/src/test/org/apache/tapestry/enhance/TestInjectEventInvokerWorker.java Sun May 21 10:56:10 2006
@@ -0,0 +1,107 @@
+// Copyright May 21, 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.enhance;
+
+import java.lang.reflect.Modifier;
+
+import org.apache.hivemind.ApplicationRuntimeException;
+import org.apache.hivemind.ErrorLog;
+import org.apache.hivemind.Location;
+import org.apache.hivemind.service.MethodSignature;
+import org.apache.tapestry.BaseComponent;
+import org.apache.tapestry.services.impl.ComponentEventInvoker;
+import org.apache.tapestry.spec.IComponentSpecification;
+import org.easymock.MockControl;
+
+
+/**
+ * Test functionality of {@link InjectEventInvokerWorker} enhancer.
+ * 
+ * @author jkuhnert
+ */
+public class TestInjectEventInvokerWorker extends BaseEnhancementTestCase
+{
+
+    public void testSuccess() throws Exception
+    {
+        Location l = newLocation();
+
+        MockControl control = newControl(EnhancementOperation.class);
+        EnhancementOperation op = (EnhancementOperation) control.getMock();
+        ComponentEventInvoker invoker = new ComponentEventInvoker();
+        
+        IComponentSpecification spec = newSpec(l);
+        
+        op.claimReadonlyProperty("eventInvoker");
+        
+        op.addInjectedField("_$eventInvoker", ComponentEventInvoker.class, invoker);
+        control.setReturnValue("_$eventInvoker");
+        
+        op.getAccessorMethodName("eventInvoker");
+        control.setReturnValue("getEventInvoker");
+        
+        op.addMethod(Modifier.PUBLIC, new MethodSignature(ComponentEventInvoker.class,
+                "getEventInvoker", null, null), "return _$eventInvoker;", l);
+        
+        replayControls();
+        
+        InjectEventInvokerWorker worker = new InjectEventInvokerWorker();
+        worker.setComponentEventInvoker(invoker);
+        worker.performEnhancement(op, spec);
+        
+        verifyControls();
+    }
+    
+    public void testFailure()
+    {
+        Location l = newLocation();
+
+        MockControl control = newControl(EnhancementOperation.class);
+        EnhancementOperation op = (EnhancementOperation) control.getMock();
+        ComponentEventInvoker invoker = new ComponentEventInvoker();
+        
+        ErrorLog log = (ErrorLog) newMock(ErrorLog.class);
+        
+        Throwable ex = new ApplicationRuntimeException(EnhanceMessages
+                .claimedProperty("eventInvoker"));
+        
+        MockControl specc = newControl(IComponentSpecification.class);
+        IComponentSpecification spec = (IComponentSpecification) specc.getMock();
+
+        op.claimReadonlyProperty("eventInvoker");
+        control.setThrowable(ex);
+
+        op.getBaseClass();
+        control.setReturnValue(BaseComponent.class);
+        
+        spec.getLocation();
+        specc.setReturnValue(l);
+
+        log.error(
+                EnhanceMessages.errorAddingProperty("eventInvoker", BaseComponent.class, ex),
+                l,
+                ex);
+
+        replayControls();
+
+        InjectEventInvokerWorker worker = new InjectEventInvokerWorker();
+        worker.setComponentEventInvoker(invoker);
+        worker.setErrorLog(log);
+        
+        worker.performEnhancement(op, spec);
+
+        verifyControls();
+    }
+    
+}

Modified: tapestry/tapestry4/trunk/framework/src/test/org/apache/tapestry/form/MockForm.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/framework/src/test/org/apache/tapestry/form/MockForm.java?rev=408205&r1=408204&r2=408205&view=diff
==============================================================================
--- tapestry/tapestry4/trunk/framework/src/test/org/apache/tapestry/form/MockForm.java (original)
+++ tapestry/tapestry4/trunk/framework/src/test/org/apache/tapestry/form/MockForm.java Sun May 21 10:56:10 2006
@@ -34,6 +34,7 @@
 import org.apache.tapestry.IRequestCycle;
 import org.apache.tapestry.engine.IPageLoader;
 import org.apache.tapestry.listener.ListenerMap;
+import org.apache.tapestry.services.impl.ComponentEventInvoker;
 import org.apache.tapestry.spec.IComponentSpecification;
 import org.apache.tapestry.spec.IContainedComponent;
 import org.apache.tapestry.valid.IValidationDelegate;
@@ -346,6 +347,21 @@
     }
 
     public void setContainedComponent(IContainedComponent containedComponent)
+    {
+    }
+    
+    /** 
+     * {@inheritDoc}
+     */
+    public ComponentEventInvoker getEventInvoker()
+    {
+        return null;
+    }
+
+    /** 
+     * {@inheritDoc}
+     */
+    public void setEventInvoker(ComponentEventInvoker invoker)
     {
     }
 }