You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tapestry.apache.org by hl...@apache.org on 2007/02/23 20:39:29 UTC

svn commit: r511066 - in /tapestry/tapestry5/tapestry-core/trunk/src: main/java/org/apache/tapestry/ main/java/org/apache/tapestry/corelib/components/ main/java/org/apache/tapestry/internal/services/ site/apt/ site/apt/guide/ test/java/org/apache/tapes...

Author: hlship
Date: Fri Feb 23 11:39:28 2007
New Revision: 511066

URL: http://svn.apache.org/viewvc?view=rev&rev=511066
Log:
Simplify action URLs for the standard case (the event type "action").
Update a bunch of out-of-date documentation.

Modified:
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/TapestryConstants.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/ActionLink.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/Form.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/GridPager.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ActionLinkHandlerImpl.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ActionLinkTarget.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ComponentActionDispatcher.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ComponentInvocation.java
    tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/appstate.apt
    tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/dom.apt
    tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/event.apt
    tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/pagenav.apt
    tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/reload.apt
    tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/request.apt
    tapestry/tapestry5/tapestry-core/trunk/src/site/apt/index.apt
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ComponentActionDispatcherTest.java
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/LinkFactoryImplTest.java

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/TapestryConstants.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/TapestryConstants.java?view=diff&rev=511066&r1=511065&r2=511066
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/TapestryConstants.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/TapestryConstants.java Fri Feb 23 11:39:28 2007
@@ -19,8 +19,8 @@
  */
 public final class TapestryConstants
 {
-    /** Default client event name, used in most situations. */
-    public static final String DEFAULT_EVENT = "action";
+    /** Default client event name, "action", used in most situations. */
+    public static final String ACTION_EVENT = "action";
 
     /**
      * Event triggered when a page is activated (for rendering). The component event handler will be

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/ActionLink.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/ActionLink.java?view=diff&rev=511066&r1=511065&r2=511066
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/ActionLink.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/ActionLink.java Fri Feb 23 11:39:28 2007
@@ -14,7 +14,7 @@
 
 package org.apache.tapestry.corelib.components;
 
-import static org.apache.tapestry.TapestryConstants.DEFAULT_EVENT;
+import static org.apache.tapestry.TapestryConstants.ACTION_EVENT;
 
 import java.util.List;
 
@@ -67,7 +67,7 @@
 
         Object[] contextArray = _context == null ? new Object[0] : _context.toArray();
 
-        Link link = _resources.createActionLink(DEFAULT_EVENT, false, contextArray);
+        Link link = _resources.createActionLink(ACTION_EVENT, false, contextArray);
 
         writer.element("a", "href", link, "id", clientId);
 

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/Form.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/Form.java?view=diff&rev=511066&r1=511065&r2=511066
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/Form.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/Form.java Fri Feb 23 11:39:28 2007
@@ -202,7 +202,7 @@
         String name = _pageRenderSupport.allocateClientId(_resources.getId());
 
         Link link = _resources
-                .createActionLink(TapestryConstants.DEFAULT_EVENT, true, contextArray);
+                .createActionLink(TapestryConstants.ACTION_EVENT, true, contextArray);
         writer.element("form", "name", name, "id", name, "method", "post", "action", link);
 
         _resources.renderInformalParameters(writer);

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/GridPager.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/GridPager.java?view=diff&rev=511066&r1=511065&r2=511066
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/GridPager.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/GridPager.java Fri Feb 23 11:39:28 2007
@@ -124,7 +124,7 @@
             return;
         }
 
-        Link link = _resources.createActionLink(TapestryConstants.DEFAULT_EVENT, false, pageIndex);
+        Link link = _resources.createActionLink(TapestryConstants.ACTION_EVENT, false, pageIndex);
 
         writer.element("a", "href", link, "title", _messages.format("goto-page", pageIndex));
 

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ActionLinkHandlerImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ActionLinkHandlerImpl.java?view=diff&rev=511066&r1=511065&r2=511066
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ActionLinkHandlerImpl.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ActionLinkHandlerImpl.java Fri Feb 23 11:39:28 2007
@@ -97,7 +97,7 @@
         if (holder.hasValue())
             return holder.get();
 
-        element.triggerEvent(actionLinkTarget.getAction(), invocation.getContext(), handler);
+        element.triggerEvent(actionLinkTarget.getEventType(), invocation.getContext(), handler);
 
         ActionResponseGenerator result = holder.get();
 

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ActionLinkTarget.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ActionLinkTarget.java?view=diff&rev=511066&r1=511065&r2=511066
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ActionLinkTarget.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ActionLinkTarget.java Fri Feb 23 11:39:28 2007
@@ -14,12 +14,15 @@
 
 package org.apache.tapestry.internal.services;
 
+import org.apache.tapestry.TapestryConstants;
+import org.apache.tapestry.ioc.internal.util.InternalUtils;
+
 /**
  * It represents an invocation target for an action link.
  */
 public class ActionLinkTarget implements InvocationTarget
 {
-    private final String _action;
+    private final String _eventType;
 
     private final String _pageName;
 
@@ -27,7 +30,7 @@
 
     public ActionLinkTarget(String action, String pageName, String componentNestedId)
     {
-        _action = action;
+        _eventType = action;
         _pageName = pageName;
         _componentNestedId = componentNestedId;
 
@@ -38,18 +41,32 @@
         StringBuilder builder = new StringBuilder();
 
         builder.append(_pageName.toLowerCase());
-        builder.append(".");
-        // Already lower case by design.
-        builder.append(_componentNestedId);
-        builder.append(".");
-        builder.append(_action);
+
+        boolean hasComponentId = InternalUtils.isNonBlank(_componentNestedId);
+
+        if (hasComponentId)
+        {
+
+            builder.append(".");
+            // Already lower case by design.
+            builder.append(_componentNestedId);
+        }
+
+        // If no nested component id, then must append the action; the ':' and the action become the
+        // delimiter between the page name and the event context.
+
+        if (!hasComponentId || !_eventType.equals(TapestryConstants.ACTION_EVENT))
+        {
+            builder.append(":");
+            builder.append(_eventType);
+        }
 
         return builder.toString();
     }
 
-    public String getAction()
+    public String getEventType()
     {
-        return _action;
+        return _eventType;
     }
 
     public String getComponentNestedId()

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ComponentActionDispatcher.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ComponentActionDispatcher.java?view=diff&rev=511066&r1=511065&r2=511066
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ComponentActionDispatcher.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ComponentActionDispatcher.java Fri Feb 23 11:39:28 2007
@@ -16,6 +16,7 @@
 
 import java.io.IOException;
 
+import org.apache.tapestry.TapestryConstants;
 import org.apache.tapestry.internal.InternalConstants;
 import org.apache.tapestry.internal.TapestryUtils;
 import org.apache.tapestry.services.ActionResponseGenerator;
@@ -42,26 +43,68 @@
     {
         String path = request.getPath();
 
-        int dotx = path.indexOf('.');
-
-        if (dotx < 0)
-            return false;
+        String logicalPageName = null;
+        String nestedComponentId = "";
+        String eventType = TapestryConstants.ACTION_EVENT;
 
-        // Skip the leading slash, the rest is logical page name.
+        // Will always have a dot or a colon
 
-        String logicalPageName = path.substring(1, dotx);
-
-        int slashx = path.indexOf('/', dotx + 1);
-        if (slashx < 0)
-            slashx = path.length();
+        int dotx = path.indexOf('.');
+        int colonx = path.indexOf(':');
 
-        int lastDotx = path.lastIndexOf('.', slashx);
+        int contextStart = -1;
 
-        String nestedComponentId = dotx != lastDotx ? path.substring(dotx + 1, lastDotx) : "";
+        if (dotx > 0)
+        {
+            logicalPageName = path.substring(1, dotx);
+
+            int slashx = path.indexOf('/', dotx + 1);
+
+            // The nested id ends at the colon (if present) or
+            // the first slash (if present) or the end of the path.
+
+            if (slashx < 0)
+            {
+                slashx = path.length() ;
+            }
+            else
+            {
+                contextStart = slashx + 1;
+            }
+
+            int nestedIdEnd = slashx;
+
+            if (colonx > 0 && colonx < slashx)
+            {
+                nestedIdEnd = colonx;
+                eventType = path.substring(colonx + 1, slashx);
+            }
+
+            nestedComponentId = path.substring(dotx + 1, nestedIdEnd);
+        }
+        else if (colonx > 0)
+        {
+            // No dot, but a colon. Therefore no nested component id, but an action name and
+            // maybe some event context.
+
+            int slashx = path.indexOf('/', colonx + 1);
+            if (slashx < 0)
+            {
+                slashx = path.length();
+            }
+            else
+            {
+                contextStart = slashx + 1;
+            }
+
+            eventType = path.substring(colonx + 1, slashx);
+            logicalPageName = path.substring(1, colonx);
+        }
 
-        String eventType = path.substring(lastDotx + 1, slashx);
+        if (logicalPageName == null)
+            return false;
 
-        String[] context = slashx < path.length() ? decodeContext(path.substring(slashx + 1))
+        String[] eventContext = contextStart > 0 ? decodeContext(path.substring(contextStart))
                 : _emptyString;
 
         String activationContextValue = request.getParameter(InternalConstants.PAGE_CONTEXT_NAME);
@@ -73,7 +116,7 @@
                 logicalPageName,
                 nestedComponentId,
                 eventType,
-                context,
+                eventContext,
                 activationContext);
 
         responseGenerator.sendClientResponse(response);

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ComponentInvocation.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ComponentInvocation.java?view=diff&rev=511066&r1=511065&r2=511066
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ComponentInvocation.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ComponentInvocation.java Fri Feb 23 11:39:28 2007
@@ -43,10 +43,12 @@
      *            identifies the target of the event: a component with a page
      * @param context
      *            context information supplied by the component to be provided back when the event
-     *            on the component is triggered
+     *            on the component is triggered, or contains the activation context when the
+     *            invocation is for a page render request
      * @param activationContext
      *            page activation context for the page containing the component, supplied via a
-     *            passivate event to the page's root component
+     *            passivate event to the page's root component (used when an action component
+     *            invocation is for a page with an activation context)
      */
     public ComponentInvocation(InvocationTarget target, String[] context, String[] activationContext)
     {

Modified: tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/appstate.apt
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/appstate.apt?view=diff&rev=511066&r1=511065&r2=511066
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/appstate.apt (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/appstate.apt Fri Feb 23 11:39:28 2007
@@ -64,7 +64,7 @@
   {
     ApplicationStateCreator<MyState> creator = new ApplicationStateCreator<MyState>()
     {
-      MyState create()
+      public MyState create()
       {
         return new MyState(new Date());
       }

Modified: tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/dom.apt
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/dom.apt?view=diff&rev=511066&r1=511065&r2=511066
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/dom.apt (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/dom.apt Fri Feb 23 11:39:28 2007
@@ -142,6 +142,11 @@
   The writef() method formats an number of arguments.  It uses a java.util.Formatter.  It is a convience for formatting that ultimately
   invokes write().
   
+* writeRaw()
+
+  The writeRaw() method writes unfiltered text into the DOM.  When the DOM is rendered to markup, the provided string is written to the
+  output stream exactly as-is. Care should be taken, as this can easily result invalid markup, or even markup that is not well formed.
+  
 * comment()
 
   Adds an XML comment.  The comment delimiters will be supplied by Tapestry:

Modified: tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/event.apt
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/event.apt?view=diff&rev=511066&r1=511065&r2=511066
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/event.apt (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/event.apt Fri Feb 23 11:39:28 2007
@@ -7,44 +7,71 @@
   Component events are the means by which components are made aware of behaviors by the user, such
   as clicking links and submitting forms.
   
+  Component events are used for two purposes:
+  
+  * They represent requests initiated by the user, triggered by links and forms in the client web browser.
+    These are described more fully in {{{pagenav.html}page navigation}} and in 
+    {{{request.html}requst processing}}.
+    
+  * They represent flow-of-control within a request, allowing one component to notify its container
+    about some kind of circumstance ("a form was submitted"), or to collect some piece for data
+    from the container.
+    
+  []
+  
+  Often, a navigation request (originating with the user) will spawn a number of flow-of-control
+  requests.  For example, a Form component will be triggered by an action request, and will then
+  send notification events to announce when the form submission is about to be processed, and
+  whether it was succesful or not.
+  
   In Tapestry 4, you would configure a parameter of a component with the name of a method to invoke
   when a certain event occured, usually a request from the client.
   
   This has some limitations, including the fact that only a single method could be invoked.
   
-  Tapestry 5 introduces the
-  {{{../apidocs/org/apache/tapestry/annotations/OnEvent.html}OnEvent annotation}} which is used
-  to mark methods as <event handler methods>.  As with other annotations, these methods
-  may be private or public.
-  
-  Rather than configure a component to invoke a particular method, you annotate one or more
-  methods to listen for events from that component.
+  Tapestry 5 introduces the concept of <event handler methods>, identified via a naming convention, or
+  via the 
+  {{{../apidocs/org/apache/tapestry/annotations/OnEvent.html}OnEvent annotation}}.  Event handler methods
+  have any visibility, even private (normally they are given package private visibility, to support testing).
+  
+  Rather than configure a component to invoke a particular method, you identify one or more
+  methods to listen for events from that component. A single event handler method may receive notifications from
+  many different components.
   
-  For example, here's a portion of a page that lets the user choose a value between 1 and 10:
+  For example, here's a portion of a page (let's call it "Chooser") that lets the user choose a number between 1 and 10:
   
 +---+
 <p> Choose a number from 1 to 10: </p>
 
 <p>
     <t:comp type="Count" end="10" value="index">
-        <t:comp id="choose" type="ActionLink" context="index">${index}</t:comp>
+        <a t:id="select" t:type="actionlink" context="index">${index}</t:comp>
     </t:comp>
 </p>
 +---+
 
   The ActionLink component creates an action URL.
   
-  The URL identifies the page that contains the component, the type of event
-  ("action", the default), the id of the component ("choose"), plus the additional context value.
-  A sample URL: <<<http://localhost:8080/ActionPage.action/choose/3>>>.
+  The URL identifies the page that contains the component ("chooser"), the type of event
+  (unless it is "action", the default and most common event type),
+  the id of the component within the page ("select"), plus the additional context value(s).
   
+  A sample URL: <<<http://localhost:8080/chooser.select/3>>>.
+
   When there are additional context values, they are appended to the path.
+  
+  This demonstrates a critical difference between Tapestry and a more traditional, action oriented framework.
+  This URL doesn't say what happens when the link is clicked, it identifies <which component is responsible>.
+
+  There's no simple mapping from URL to a piece of code; instead the component sends notifications, in the form
+  of invocations of event handler methods,   
+  
    
   A Java method can be invoked when the link for the component is clicked by the user:
   
 +---+
-  @OnEvent(component = "choose")
-  void choose(int value)
+  @OnEvent(component = "select")
+  void valueChosen(int value)
   {
     _value = value;
   }
@@ -52,21 +79,21 @@
 
   Tapestry has done two things here:
   
-  * It has identified method choose() as the method to invoke.
+  * It has identified method valueChosen() as the method to invoke.
   
   * It has converted the context value from a string to an integer and passed it into the method.
   
   []
   
-  In the above example, the choose() method will be invoked on <any event> that originates
+  In the above example, the valueChosen() method will be invoked on <any event> that originates
   inn component <<<choose>>>.  Since ActionLink components only emit a single type of event, "action", 
   this will not be a problem.
   
   Some components can emit more than one type of event, in which case you will want to be more specific:
   
 +---+
-  @OnEvent(value = "action", component = "choose")
-  void choose(int value)
+  @OnEvent(value = "action", component = "select")
+  void valueChosen(int value)
   {
     _value = value;
   }
@@ -74,6 +101,12 @@
   
   The value attribute of the OnEvent annotation is the name of the event to match.
   
+  "action" is the name of the default event type; the ActionLink and Form components each use this event type.
+  If you omit the component part of the OnEvent annotation, then you'll recieve notifications from
+  <all> contained components, possibly including nested components (due to event bubbling).
+  
+  You should qualify exactly which component(s) you wish to recieve events from.
+  
 Event Handler Method Convention Names  
   
   As an alternative to the use of annotations, you may name your events in a specific fashion, and Tapestry will invoke your methods just as if
@@ -85,14 +118,19 @@
   The previous example may be rewritten as:
   
 +---+
-  void onActionFromChoose(int value)
+  void onActionFromSelect(int value)
   {
     _value = value;
   }
 +---+  
   
+  If you event type is named "onAny", it will receive all types of events. This is rarely what you want!
+  
+  If for some unfathomable reason you want to be notified of the same event from multiple components in the same method, you'll need to use the OnEvent annotation.  
+  
+  Note from Howard: I've found that I prefer the naming convention approach, and reserve the annotation just for situations that don't otherwise fit.  
   
-Context
+Event Context
 
   The context values (the context parameter to the ActionLink component) can be any object.
   However, only a simple conversion to string occurs.  This is in contrast to Tapestry 4, which had
@@ -110,7 +148,7 @@
   
   Alternately, an event handler method may take a parameter of type java.lang.Object[].  This parameter
   will receive the entire context array. This is useful when, for example, the context
-  is off different lengths at different times. You should use either explicit, typed parameters or
+  is of different lengths at different times. You should use either explicit, typed parameters or
   a single parameter of type Object[].
   
 Event Bubbling
@@ -118,76 +156,7 @@
   The event will bubble up the hierarchy, until it is aborted. The event is aborted
   when an event handler method returns a non-null value.
   
-  The value returned from an event handler method determines how Tapestry will render a response.
-  
-Event Handler Returns Types
+  For page navigation events, the value returned from an event handler method {{{pagenav.html}determines how Tapestry will render a response}}.
 
-  An event handler may return a number of different types:
-  
-  * A page component, via the {{{../apidocs/org/apache/tapestry/annotations/InjectPage.html}InjectPage}} annotation
-  
-  * A string, the <logical> name of a page (not the fully qualified class name)
-
-  * <More types to be determined>
-  
-  []
-  
-  Returning a page will abort the event and direct Tapestry to render the returned page.  It's completely acceptible to invoke
-  methods on the page before returning it (often to inform it about what it should display), but remember that rendering of the page
-  <<will occur in a subsequent request>>, which often requires that you store information persistently between requests.
-  
-  Returning a string is much the same, except that the string is used to locate the page to be activated. This is easy to use
-  when there is no need to invoke methods on the page before returning it.
-  
-  <TODO: Describe differences between client-originating events and flow-of-control events from components.>
-  
-End of Action Request
-
-  The default behavior at the end of an action request is to set up the page containing
-  the component to render.  This is normally the page that contains the component, but the active page
-  (the page that renders the response) may be altered based on the value returned from an component event
-  handler method.
-  
-  <<This is very important:>> The rendering occurs in a <<new>> request. The normal response
-  to an action request is a client-side redirect to re-render the page. Thus an action is <<two>>
-  requests: one to process the action and update server-side state, and a second request to render
-  the resulting page.
-  
-  It is very important that you make use of 
-  {{{persist.html}page persistence}} to allow information from the action request
-  to survive to the next render request.
-  
-Passivate and Activate Events
-
-  When a link to a page is created, the page will be sent a passivate event. The event handler method for the
-  passivate event may return a single value, or a list or array of values. 
-  These objects will become the context portion of the URI.  When a page is later rendered, the context is extracted from the URI and
-  passed to any activate event handlers.  In this way, information about the page can be encoded into URIs for the page, in a light-weight
-  (and human readable) manner.
-  
-  This was created with the intent of handling pages that exist to view (or perhaps to edit) a specific instance of some type; in the
-  context of a CRUD application, the context is used to store the primary key of some entity object:
-    
-+---+
-  public class ViewCustomer
-  {
-    private Customer _customer;
-    
-    @Inject
-    private CustomerDAO _customerDAO;
     
-    long onPassivate()
-    {
-      return _customer.getId();
-    }
-  
-    void onActivate(long customerId)
-    {
-      _customer = _customerDAO.get(customerId);
-    }
-  }
-+---+
-  
-  Render page request URI's for this page would be created as <<</ViewCustomer.html/1234>>>.
-  
    

Modified: tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/pagenav.apt
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/pagenav.apt?view=diff&rev=511066&r1=511065&r2=511066
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/pagenav.apt (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/pagenav.apt Fri Feb 23 11:39:28 2007
@@ -202,7 +202,7 @@
 
   This is a minimal approach, perhaps good enough for a prototype. 
   
-  When the user clicks a link, the action request URL will initially be something like "http://.../productlisting/select.action/99" and the final
+  When the user clicks a link, the action request URL will initially be something like "http://.../productlisting.select/99" and the final
   render request URL will be something like "http://.../productdetails".  Notice that the product id ("99") does not appear in the render request URL.
   
   It has some minor flaws:

Modified: tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/reload.apt
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/reload.apt?view=diff&rev=511066&r1=511065&r2=511066
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/reload.apt (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/reload.apt Fri Feb 23 11:39:28 2007
@@ -34,6 +34,12 @@
   
   Reloading is based on package name; the packages that are reloaded are derived from the {{{conf.html}application configuration}}.
   
+File System Only
+
+  Reloading of classes and other files applies only to files that are actually on the file system, and not files
+  obtained from JAR files.  This is perfect during development, where the files in question are in your local workspace.
+  In a deployed application, you are somewhat subject to the implementation of your servlet container or application server.  
+  
 Class Loader Issues
 
   Tapestry uses an extra class loader to load page and component classes.

Modified: tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/request.apt
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/request.apt?view=diff&rev=511066&r1=511065&r2=511066
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/request.apt (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/request.apt Fri Feb 23 11:39:28 2007
@@ -107,11 +107,18 @@
   
   The URL identifies the name of the page, then a series of component ids (the path from the page down to the specific component), then the name of the event to be
   triggered on the component. The remaining path elements are used as the context for the <event> (not for the page activation, which
-  does not currently apply). For example, "/griddemo.FOO.BAR.action/3" would locate page "griddemo", then component "FOO.BAR", and trigger an event named "action", with
+  does not currently apply). For example, "/griddemo.FOO.BAR/3" would locate page "griddemo", then component "FOO.BAR", and trigger an event named "action" (the default event type,
+  which is omitted from the URL), with
   the context "3".
   
+  If the page in question has an activation context, it is supplied as an additional query parameter on the link.
+  
+  In cases where the event type is not the default, "action", it will appear between the nested component id and the event context, preceded by a colon. Example:
+  "/example/foo.bar:magic/99" would trigger an event of type "magic".  This is not common in the vanilla Tapestry framework, but will likely be more common
+  as Ajax features (which would not use the normal request logic) are implemented.
+    
   The response from a component action request is typically, but not universally, used to send a redirect to the client; the redirect URL is a page render URL
-  to display the response to the event.  
+  to display the response to the event.  This is detailed under {{{pagenav.html}page navigation}}.  
    
    
 RequestGlobals Service

Modified: tapestry/tapestry5/tapestry-core/trunk/src/site/apt/index.apt
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/site/apt/index.apt?view=diff&rev=511066&r1=511065&r2=511066
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/site/apt/index.apt (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/site/apt/index.apt Fri Feb 23 11:39:28 2007
@@ -8,36 +8,17 @@
   
   tapestry-core is built upon the {{{../tapestry-ioc/index.html}Tapestry IoC Container}}.
 
-Changes from Tapestry 4 to Tapestry 5
-
-  Tapestry 5 represents a significant advance over Tapestry 4.  The goal is to make Tapestry 5
-  <significantly> easier to use than Tapestry 4 (or any other Java web framework).
-  We're keeping the <essence> of Tapestry 4, but starting with a brand new code base designed
-  to provide a stable, powerful, extensible platform for many years to come.
-  
-  Here's a few of the planned and implemented features:
-  
-  * Simplified, minimal API based on annotations
-  
-  * <<No>> base class requirement; components are true, pure Pojos (Plain Old Java Objects)
-  
-  * Abstract classes ... gone!  Classes are normal, concrete classes.
-  
-  * <<No>> XML descriptors for pages and components ... just the annotations.
-  
-  * Less configuration all around.
-  
-  * Automatic reloading of templates and even <Java classes>
-  
-  * Super-duper Ajax integration built on {{{http://dojotoolkit.org} Dojo}}
-  
-  * Easy & fast unit testing of individual pages or components
-  
 New And Of Note
 
   Progress on Tapestry 5 is really taking off. This space lists some cool new features that have been added
   recently.
   
+  * The default ExceptionReport page has been improved to show details of the incoming request,
+    and to display file content when an exception includes a location.
+  
+  * Action request URLs have been shortened and simplified for the common case. They may also include a query
+    parameter to identify the page's activation context.
+  
   * {{{component-parameters.html}Component Reference Documentation}}, generated via a Maven plugin, is now available.
   
   * The return values for the "after" set of {{{guide/rendering.html}render phase methods}} have changed: all render phase 
@@ -82,6 +63,31 @@
   
   * The @ComponentClass anntotation, seen in the earlier {{{../screencast.html}screencasts}} has been removed.
   
+Changes from Tapestry 4 to Tapestry 5
+
+  Tapestry 5 represents a significant advance over Tapestry 4.  The goal is to make Tapestry 5
+  <significantly> easier to use than Tapestry 4 (or any other Java web framework).
+  We're keeping the <essence> of Tapestry 4, but starting with a brand new code base designed
+  to provide a stable, powerful, extensible platform for many years to come.
+  
+  Here's a few of the planned and implemented features:
+  
+  * Simplified, minimal API based on annotations
+  
+  * <<No>> base class requirement; components are true, pure Pojos (Plain Old Java Objects)
+  
+  * Abstract classes ... gone!  Classes are normal, concrete classes.
+  
+  * <<No>> XML descriptors for pages and components ... just the annotations.
+  
+  * Less configuration all around.
+  
+  * Automatic reloading of templates and even <Java classes>
+  
+  * Super-duper Ajax integration built on {{{http://dojotoolkit.org} Dojo}}
+  
+  * Easy & fast unit testing of individual pages or components
+    
 Adaptive API
 
   A key feature of Tapestry 5 is <adaptive API>.

Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ComponentActionDispatcherTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ComponentActionDispatcherTest.java?view=diff&rev=511066&r1=511065&r2=511066
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ComponentActionDispatcherTest.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ComponentActionDispatcherTest.java Fri Feb 23 11:39:28 2007
@@ -19,6 +19,7 @@
 
 import java.io.IOException;
 
+import org.apache.tapestry.TapestryConstants;
 import org.apache.tapestry.internal.InternalConstants;
 import org.apache.tapestry.internal.test.InternalBaseTestCase;
 import org.apache.tapestry.services.ActionResponseGenerator;
@@ -30,7 +31,7 @@
 public class ComponentActionDispatcherTest extends InternalBaseTestCase
 {
     @Test
-    public void no_dot_in_path() throws Exception
+    public void no_dot_or_colon_in_path() throws Exception
     {
         ActionLinkHandler handler = newActionLinkHandler();
         Request request = newRequest();
@@ -55,38 +56,102 @@
     @Test
     public void event_on_page() throws Exception
     {
-        test("/foo/MyPage.anevent", "foo/MyPage", "", "anevent");
+        test("/foo/MyPage:anevent", "foo/MyPage", "", "anevent");
     }
 
     @Test
     public void event_on_component_within_page() throws Exception
     {
-        test("/foo/MyPage.fred.anevent", "foo/MyPage", "fred", "anevent");
+        test("/foo/MyPage.fred:anevent", "foo/MyPage", "fred", "anevent");
+    }
+
+    @Test
+    public void default_event_with_nested_id() throws Exception
+    {
+        test("/foo/MyPage.fred", "foo/MyPage", "fred", TapestryConstants.ACTION_EVENT);
+    }
+
+    @Test
+    public void default_event_with_nested_id_and_context() throws Exception
+    {
+        test(
+                "/foo/MyPage.fred/fee/fie/foe/fum",
+                "foo/MyPage",
+                "fred",
+                TapestryConstants.ACTION_EVENT,
+                "fee",
+                "fie",
+                "foe",
+                "fum");
+    }
+
+    @Test
+    public void default_event_with_context_that_includes_a_colon() throws Exception
+    {
+        test(
+                "/foo/MyPage.underdog/a:b:c/d",
+                "foo/MyPage",
+                "underdog",
+                TapestryConstants.ACTION_EVENT,
+                "a:b:c",
+                "d");
     }
 
     @Test
     public void event_on_nested_component_within_page() throws Exception
     {
-        test("/foo/MyPage.barney.fred.anevent", "foo/MyPage", "barney.fred", "anevent");
+        test("/foo/MyPage.barney.fred:anevent", "foo/MyPage", "barney.fred", "anevent");
     }
 
     @Test
     public void page_event_with_context() throws Exception
     {
-        test("/foo/MyPage.trigger/foo", "foo/MyPage", "", "trigger", "foo");
+        test("/foo/MyPage:trigger/foo", "foo/MyPage", "", "trigger", "foo");
     }
 
     @Test
     public void nested_component_event_with_context() throws Exception
     {
         test(
-                "/foo/MyPage.nested.trigger/foo/bar/baz",
+                "/foo/MyPage.nested:trigger/foo/bar/baz",
                 "foo/MyPage",
                 "nested",
                 "trigger",
                 "foo",
                 "bar",
                 "baz");
+    }
+
+    @Test
+    public void page_activation_context_in_request() throws Exception
+    {
+        ActionLinkHandler handler = newActionLinkHandler();
+        Request request = newRequest();
+        Response response = newResponse();
+        ActionResponseGenerator generator = newMock(ActionResponseGenerator.class);
+
+        train_getPath(request, "/mypage:eventname");
+
+        train_getParameter(request, InternalConstants.PAGE_CONTEXT_NAME, "alpha/beta");
+
+        expect(
+                handler.handle(
+                        eq("mypage"),
+                        eq(""),
+                        eq("eventname"),
+                        aryEq(new String[0]),
+                        aryEq(new String[]
+                        { "alpha", "beta" }))).andReturn(generator);
+
+        generator.sendClientResponse(response);
+
+        replay();
+
+        Dispatcher dispatcher = new ComponentActionDispatcher(handler);
+
+        assertTrue(dispatcher.dispatch(request, response));
+
+        verify();
     }
 
     private void test(String requestPath, String logicalPageName, String nestedComponentId,

Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/LinkFactoryImplTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/LinkFactoryImplTest.java?view=diff&rev=511066&r1=511065&r2=511066
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/LinkFactoryImplTest.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/LinkFactoryImplTest.java Fri Feb 23 11:39:28 2007
@@ -67,7 +67,8 @@
                 PAGE_LOGICAL_NAME,
                 "foo.bar",
                 "someaction",
-                "/sub/mypage.foo.bar.someaction");
+                "/sub/mypage.foo.bar:someaction");
+
     }
 
     @Test
@@ -79,10 +80,38 @@
                 PAGE_LOGICAL_NAME,
                 "foo.bar",
                 "publish",
-                "/sub/mypage.foo.bar.publish/fred/5",
+                "/sub/mypage.foo.bar:publish/fred/5",
+                "fred",
+                5);
+    }
+
+    @Test
+    public void action_link_with_default_action()
+    {
+        testActionLink(
+                PAGE_CLASS_NAME,
+                "",
+                PAGE_LOGICAL_NAME,
+                "foo.bar",
+                TapestryConstants.ACTION_EVENT,
+                "/sub/mypage.foo.bar/fred/5",
                 "fred",
                 5);
     }
+    
+    @Test
+    public void page_level_event_always_includes_action()
+    {
+        testActionLink(
+                PAGE_CLASS_NAME,
+                "",
+                PAGE_LOGICAL_NAME,
+                "",
+                TapestryConstants.ACTION_EVENT,
+                "/sub/mypage:action/barney/99",
+                "barney",
+                99);
+    }
 
     @Test
     public void action_link_named_context_no_ids()
@@ -93,7 +122,7 @@
                 PAGE_LOGICAL_NAME,
                 "foo.bar",
                 "someaction",
-                "/fred/sub/mypage.foo.bar.someaction");
+                "/fred/sub/mypage.foo.bar:someaction");
     }
 
     @SuppressWarnings("unchecked")