You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tapestry.apache.org by fr...@apache.org on 2006/12/19 07:10:20 UTC

svn commit: r488538 - in /tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry: corelib/components/ dom/ internal/services/ test/pagelevel/

Author: freemant
Date: Mon Dec 18 22:10:18 2006
New Revision: 488538

URL: http://svn.apache.org/viewvc?view=rev&rev=488538
Log:
Use a map to associate an "in-app invocation" object with a link element, instead of storing it into the element.

Added:
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ActionLinkInvocation.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InAppInvocation.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InAppInvocationMap.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InAppInvocationPathSource.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/NoOpInAppInvocationMap.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageLinkInvocation.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/pagelevel/ActionLinkInvoker.java
      - copied, changed from r488300, tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/pagelevel/ActionLinkClicker.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/pagelevel/InAppInvocationMapForPageTester.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/pagelevel/InAppInvoker.java
      - copied, changed from r488300, tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/pagelevel/LinkClicker.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/pagelevel/PageLinkInvoker.java
      - copied, changed from r488300, tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/pagelevel/PageLinkClicker.java
Removed:
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ActionLinkPathSource.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageLinkPathSource.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/pagelevel/ActionLinkClicker.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/pagelevel/PageLinkClicker.java
Modified:
    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/dom/Element.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ActionLinkHandler.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/ComponentEventDispatcher.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InternalModule.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/LinkFactoryImpl.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/LinkImpl.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageLinkHandler.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageLinkHandlerImpl.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageRenderDispatcher.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/pagelevel/PageTester.java

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=488538&r1=488537&r2=488538
==============================================================================
--- 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 Mon Dec 18 22:10:18 2006
@@ -30,6 +30,9 @@
 import org.apache.tapestry.annotations.Parameter;
 import org.apache.tapestry.corelib.mixins.RenderInformals;
 import org.apache.tapestry.dom.Element;
+import org.apache.tapestry.internal.services.InAppInvocationMap;
+import org.apache.tapestry.internal.services.InAppInvocationPathSource;
+import org.apache.tapestry.internal.services.LinkImpl;
 import org.apache.tapestry.services.PageRenderSupport;
 
 /**
@@ -56,6 +59,9 @@
     @Environmental
     private PageRenderSupport _support;
 
+    @Inject("service:tapestry.internal.InAppInvocationMap")
+    private InAppInvocationMap _invocationMap;
+
     @BeginRender
     void begin(MarkupWriter writer)
     {
@@ -67,9 +73,10 @@
 
         Element element = writer.element("a", "href", link.toURI(), "id", clientId);
 
-        // This is to allow the PageTester to simulate a click on the link.
-        element.setSrcObject(link);
-
+        // Allow the PageTester to extract the invocation object to invoke it later.
+        _invocationMap.put(element, ((InAppInvocationPathSource) ((LinkImpl) link).getPathSource())
+                .getInvocation());
+        
         // TODO: Support for informal parameters, etc.
     }
 

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/dom/Element.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/dom/Element.java?view=diff&rev=488538&r1=488537&r2=488538
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/dom/Element.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/dom/Element.java Mon Dec 18 22:10:18 2006
@@ -40,8 +40,6 @@
 
     private final Document _document;
 
-    private Object _src;
-
     Element(Document container, String name)
     {
         super(container);
@@ -231,27 +229,4 @@
         return _attributes.get(attributeName);
     }
 
-    /**
-     * Some elements may have been generated from data in a source object. For example, an <a> may
-     * have been generated from a page name, component id, context and etc. stored in an
-     * {@link org.apache.tapestry.internal.services.LinkImpl}. After creating such a link element,
-     * you should store the source object into the element in order to allow the
-     * {@link org.apache.tapestry.test.pagelevel.PageTester} to easily work on it (e.g., to simulate
-     * the effect of clicking on it).
-     * 
-     * @param srcObject
-     *            The source object whose data is used to generate this element.
-     */
-    public void setSrcObject(Object src)
-    {
-        _src = src;
-    }
-
-    /**
-     * @see #setSrcObject(Object)
-     */
-    public Object getSrc()
-    {
-        return _src;
-    }
 }

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ActionLinkHandler.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ActionLinkHandler.java?view=diff&rev=488538&r1=488537&r2=488538
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ActionLinkHandler.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ActionLinkHandler.java Mon Dec 18 22:10:18 2006
@@ -1,22 +1,22 @@
-// Copyright 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.
-
+// Copyright 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.services;
 
 import org.apache.tapestry.Link;
 
 public interface ActionLinkHandler
 {
-    Link handle(ActionLinkPathSource pathSource);
+    Link handle(ActionLinkInvocation invocation);
 }

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=488538&r1=488537&r2=488538
==============================================================================
--- 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 Mon Dec 18 22:10:18 2006
@@ -35,20 +35,20 @@
         _linkFactory = linkFactory;
     }
 
-    public Link handle(ActionLinkPathSource pathSource)
+    public Link handle(ActionLinkInvocation invocation)
     {
-        Page page = _cache.get(pathSource.getPageName());
+        Page page = _cache.get(invocation.getPageName());
 
         // This is the active page, until we know better.
 
         _cache.setActive(page);
 
-        ComponentPageElement element = page.getComponentElementByNestedId(pathSource
+        ComponentPageElement element = page.getComponentElementByNestedId(invocation
                 .getComponentNestedId());
 
         element.triggerEvent(
-                pathSource.getAction(),
-                pathSource.getContext(),
+                invocation.getAction(),
+                invocation.getContext(),
                 _componentEventHandler);
 
         // It's possible that the component event will have changed the active page.

Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ActionLinkInvocation.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ActionLinkInvocation.java?view=auto&rev=488538
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ActionLinkInvocation.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ActionLinkInvocation.java Mon Dec 18 22:10:18 2006
@@ -0,0 +1,69 @@
+// Copyright 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.services;
+
+/**
+ * It represents an in-app invocation for a page link. It is passed to an
+ * {@link org.apache.tapestry.internal.services.PageLinkHandler} by both the
+ * {@link org.apache.tapestry.test.pagelevel.PageTester} and the real Tapestry code
+ * {@link org.apache.tapestry.internal.services.PageRenderDispatcher} in order to invoke an action *
+ * link.
+ */
+public class ActionLinkInvocation extends InAppInvocation
+{
+    private final String _action;
+
+    private final String _pageName;
+
+    private final String _componentNestedId;
+
+    public ActionLinkInvocation(String action, String pageName, String componentNestedId,
+            Object[] context)
+    {
+        super(context);
+        _action = action;
+        _pageName = pageName;
+        _componentNestedId = componentNestedId;
+
+    }
+
+    @Override
+    public String getTargetPath()
+    {
+        StringBuilder builder = new StringBuilder();
+        builder.append(_pageName);
+        builder.append(".");
+        builder.append(_action);
+        builder.append("/");
+        builder.append(_componentNestedId);
+        return builder.toString();
+    }
+
+    public String getAction()
+    {
+        return _action;
+    }
+
+    public String getComponentNestedId()
+    {
+        return _componentNestedId;
+    }
+
+    public String getPageName()
+    {
+        return _pageName;
+    }
+
+}

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ComponentEventDispatcher.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ComponentEventDispatcher.java?view=diff&rev=488538&r1=488537&r2=488538
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ComponentEventDispatcher.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ComponentEventDispatcher.java Mon Dec 18 22:10:18 2006
@@ -61,8 +61,8 @@
         for (int i = 1; i < chunks.length; i++)
             context[i - 1] = chunks[i];
 
-        Link link = _actionLinkHandler.handle(new ActionLinkPathSource(null, eventType,
-                logicalPageName, nestedComponentId, context));
+        Link link = _actionLinkHandler.handle(new ActionLinkInvocation(eventType, logicalPageName,
+                nestedComponentId, context));
 
         String URL = link.toRedirectURI();
 

Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InAppInvocation.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InAppInvocation.java?view=auto&rev=488538
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InAppInvocation.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InAppInvocation.java Mon Dec 18 22:10:18 2006
@@ -0,0 +1,60 @@
+// Copyright 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.services;
+
+/**
+ * It represents an invocation for a page or a component within the current app. Each invocation may
+ * provide a context (Object[]) to the invocation target.
+ */
+public abstract class InAppInvocation
+{
+    private final Object[] _context;
+
+    public InAppInvocation(Object[] context)
+    {
+        _context = context;
+    }
+
+    /**
+     * @see #getPath()
+     */
+    public abstract String getTargetPath();
+
+    /**
+     * @return A path taking the format <em>target-path</em>/context-element1/context-element2.
+     *         where the <em>target-path</em> is provided by the subclass.
+     */
+    public String getPath()
+    {
+        StringBuilder builder = new StringBuilder();
+        builder.append(getTargetPath());
+
+        for (Object id : _context)
+        {
+            builder.append("/");
+
+            // TODO: Need to encode this for URLs? What if the string contains slashes, etc.?
+
+            builder.append(id.toString());
+        }
+        return builder.toString();
+    }
+
+    public Object[] getContext()
+    {
+        return _context;
+    }
+
+}

Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InAppInvocationMap.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InAppInvocationMap.java?view=auto&rev=488538
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InAppInvocationMap.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InAppInvocationMap.java Mon Dec 18 22:10:18 2006
@@ -0,0 +1,26 @@
+// Copyright 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.services;
+
+import org.apache.tapestry.dom.Element;
+
+public interface InAppInvocationMap
+{
+    void clear();
+
+    void put(Element link, InAppInvocation invocation);
+
+    InAppInvocation get(Element link);
+}

Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InAppInvocationPathSource.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InAppInvocationPathSource.java?view=auto&rev=488538
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InAppInvocationPathSource.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InAppInvocationPathSource.java Mon Dec 18 22:10:18 2006
@@ -0,0 +1,49 @@
+// Copyright 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.services;
+
+/**
+ * It combines a context path and an in-app invocation to form a full path in a URL.
+ */
+public class InAppInvocationPathSource implements PathSource
+{
+    private final String _contextPath;
+
+    private final InAppInvocation _invocation;
+
+    public InAppInvocationPathSource(String contextPath, InAppInvocation invocation)
+    {
+        _contextPath = contextPath;
+        _invocation = invocation;
+    }
+
+    /**
+     * @return The full path containing the context path and the part contributed by the in-app
+     *         invication. It doesn't start with a slash unless the context path is the ROOT.
+     */
+    public String getPath()
+    {
+        StringBuilder builder = new StringBuilder();
+        builder.append(_contextPath);
+        builder.append("/");
+        builder.append(_invocation.getPath());
+        return builder.toString();
+    }
+
+    public InAppInvocation getInvocation()
+    {
+        return _invocation;
+    }
+}

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InternalModule.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InternalModule.java?view=diff&rev=488538&r1=488537&r2=488538
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InternalModule.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InternalModule.java Mon Dec 18 22:10:18 2006
@@ -552,4 +552,17 @@
 
         return service;
     }
+
+    /**
+     * It is a map from a {@link org.apache.tapestry.dom.Element} to a {@link InAppInvocation}
+     * Components rendering a link element that is intended to be "clickable" by the
+     * {@link org.apache.tapestry.test.pagelevel.PageTester} must map that element to an 
+     * InAppInvocation so that the PageTester can find it.
+     * <p>
+     * By default (production mode), the map does nothing.
+     */
+    public static InAppInvocationMap buildInAppInvocationMap()
+    {
+        return new NoOpInAppInvocationMap();
+    }
 }

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/LinkFactoryImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/LinkFactoryImpl.java?view=diff&rev=488538&r1=488537&r2=488538
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/LinkFactoryImpl.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/LinkFactoryImpl.java Mon Dec 18 22:10:18 2006
@@ -104,8 +104,10 @@
 
         String logicalPageName = _componentClassResolver.resolvePageClassNameToPageName(pageName);
 
-        ActionLinkPathSource pathSource = new ActionLinkPathSource(_contextPathSource
-                .getContextPath(), action, logicalPageName, component.getNestedId(), context);
+        ActionLinkInvocation invocation = new ActionLinkInvocation(action, logicalPageName,
+                component.getNestedId(), context);
+        InAppInvocationPathSource pathSource = new InAppInvocationPathSource(_contextPathSource
+                .getContextPath(), invocation);
 
         Link link = new LinkImpl(_encoder, pathSource);
 
@@ -142,8 +144,9 @@
 
         rootElement.triggerEvent(TapestryConstants.PASSIVATE_EVENT, null, handler);
 
-        PageLinkPathSource pathSource = new PageLinkPathSource(_contextPathSource.getContextPath(),
-                logicalPageName, context.toArray());
+        PageLinkInvocation invocation = new PageLinkInvocation(logicalPageName, context.toArray());
+        InAppInvocationPathSource pathSource = new InAppInvocationPathSource(_contextPathSource
+                .getContextPath(), invocation);
 
         Link link = new LinkImpl(_encoder, pathSource);
 

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/LinkImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/LinkImpl.java?view=diff&rev=488538&r1=488537&r2=488538
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/LinkImpl.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/LinkImpl.java Mon Dec 18 22:10:18 2006
@@ -29,7 +29,7 @@
  */
 public class LinkImpl implements Link
 {
-    private URLEncoder _encoder;
+    private final URLEncoder _encoder;
 
     private final PathSource _pathSource;
 

Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/NoOpInAppInvocationMap.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/NoOpInAppInvocationMap.java?view=auto&rev=488538
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/NoOpInAppInvocationMap.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/NoOpInAppInvocationMap.java Mon Dec 18 22:10:18 2006
@@ -0,0 +1,37 @@
+// Copyright 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.services;
+
+import org.apache.tapestry.dom.Element;
+
+public class NoOpInAppInvocationMap implements InAppInvocationMap
+{
+
+    public void clear()
+    {
+        
+    }
+
+    public void put(Element link, InAppInvocation invocation)
+    {
+        
+    }
+
+    public InAppInvocation get(Element link)
+    {
+        return null;
+    }
+
+}

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageLinkHandler.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageLinkHandler.java?view=diff&rev=488538&r1=488537&r2=488538
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageLinkHandler.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageLinkHandler.java Mon Dec 18 22:10:18 2006
@@ -1,20 +1,20 @@
-// Copyright 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.
-
+// Copyright 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.services;
 
 public interface PageLinkHandler
 {
-    void handle(PageLinkPathSource pathSource, PageRenderer renderer);
+    void handle(PageLinkInvocation invocation, PageRenderer renderer);
 }

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageLinkHandlerImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageLinkHandlerImpl.java?view=diff&rev=488538&r1=488537&r2=488538
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageLinkHandlerImpl.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageLinkHandlerImpl.java Mon Dec 18 22:10:18 2006
@@ -30,14 +30,14 @@
         _cache = cache;
     }
 
-    public void handle(PageLinkPathSource pathSource, PageRenderer renderer)
+    public void handle(PageLinkInvocation invocation, PageRenderer renderer)
     {
-        Page page = _cache.get(pathSource.getPageName());
+        Page page = _cache.get(invocation.getPageName());
         // Fire a notification so that the page can set itself up for the given context
 
         page.getRootElement().triggerEvent(
                 TapestryConstants.ACTIVATE_EVENT,
-                pathSource.getContext(),
+                invocation.getContext(),
                 null);
 
         renderer.renderPage(page);

Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageLinkInvocation.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageLinkInvocation.java?view=auto&rev=488538
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageLinkInvocation.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageLinkInvocation.java Mon Dec 18 22:10:18 2006
@@ -0,0 +1,50 @@
+// Copyright 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.services;
+
+/**
+ * It represents an in-app invocation for a page link. It is passed to an
+ * {@link org.apache.tapestry.internal.services.ActionLinkHandler} by both the
+ * {@link org.apache.tapestry.test.pagelevel.PageTester} and the real Tapestry code
+ * {@link org.apache.tapestry.internal.services.PageRenderDispatcher} in order to invoke a page
+ * link.
+ */
+public class PageLinkInvocation extends InAppInvocation
+{
+
+    private final String _pageName;
+
+    public PageLinkInvocation(String pageName, Object[] context)
+    {
+        super(context);
+        _pageName = pageName;
+
+    }
+
+    @Override
+    public String getTargetPath()
+    {
+        StringBuilder builder = new StringBuilder();
+        builder.append(_pageName);
+        builder.append(".html");
+        return builder.toString();
+    }
+
+    public String getPageName()
+    {
+        return _pageName;
+    }
+
+}

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageRenderDispatcher.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageRenderDispatcher.java?view=diff&rev=488538&r1=488537&r2=488538
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageRenderDispatcher.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageRenderDispatcher.java Mon Dec 18 22:10:18 2006
@@ -64,7 +64,7 @@
             // TODO: Decode strings?
             context[i - 1] = terms[i];
         }
-        _handler.handle(new PageLinkPathSource(null, logicalPageName, context), new PageRenderer()
+        _handler.handle(new PageLinkInvocation(logicalPageName, context), new PageRenderer()
         {
 
             public void renderPage(Page page)

Copied: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/pagelevel/ActionLinkInvoker.java (from r488300, tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/pagelevel/ActionLinkClicker.java)
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/pagelevel/ActionLinkInvoker.java?view=diff&rev=488538&p1=tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/pagelevel/ActionLinkClicker.java&r1=488300&p2=tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/pagelevel/ActionLinkInvoker.java&r2=488538
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/pagelevel/ActionLinkClicker.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/pagelevel/ActionLinkInvoker.java Mon Dec 18 22:10:18 2006
@@ -17,48 +17,50 @@
 import org.apache.tapestry.Link;
 import org.apache.tapestry.dom.Document;
 import org.apache.tapestry.internal.services.ActionLinkHandler;
-import org.apache.tapestry.internal.services.ActionLinkPathSource;
+import org.apache.tapestry.internal.services.ActionLinkInvocation;
+import org.apache.tapestry.internal.services.InAppInvocation;
+import org.apache.tapestry.internal.services.InAppInvocationPathSource;
 import org.apache.tapestry.internal.services.LinkImpl;
-import org.apache.tapestry.internal.services.PathSource;
 import org.apache.tapestry.ioc.Registry;
 
 /**
  * Simulates a click on an action link.
  */
-public class ActionLinkClicker implements LinkClicker
+public class ActionLinkInvoker implements InAppInvoker
 {
     private final Registry _registry;
 
-    private final PageLinkClicker _pageLinkClicker;
+    private final InAppInvoker _followupInvoker;
 
     private final ActionLinkHandler _actionLinkHandler;
 
-    public ActionLinkClicker(Registry registry, PageLinkClicker pageLinkClicker)
+    public ActionLinkInvoker(Registry registry, InAppInvoker followupInvoker)
     {
         _registry = registry;
-        _pageLinkClicker = pageLinkClicker;
+        _followupInvoker = followupInvoker;
         _actionLinkHandler = _registry.getService(ActionLinkHandler.class);
     }
 
     /**
-     * Click on the action link and get a page link in return. Then use the {@link PageLinkClicker}
-     * to click the page link.
+     * Click on the action link and get another link in return. Then follow up the link with another
+     * {@link InAppInvoker}.
      * 
-     * @param pageSource
-     *            The path source for the action link.
+     * @param invocation
+     *            The in-app invocation object corresponding to the action link.
      * @return The DOM created. Typically you will assert against it.
      */
-    public Document click(PathSource pathSource)
+    public Document invoke(InAppInvocation invocation)
     {
-        Link pageLink = click((ActionLinkPathSource) pathSource);
-        return _pageLinkClicker.click(((LinkImpl) pageLink).getPathSource());
+        Link followupLink = click((ActionLinkInvocation) invocation);
+        return _followupInvoker.invoke(((InAppInvocationPathSource) ((LinkImpl) followupLink)
+                .getPathSource()).getInvocation());
     }
 
-    private Link click(ActionLinkPathSource pathSource)
+    private Link click(ActionLinkInvocation invocation)
     {
         try
         {
-            return _actionLinkHandler.handle(pathSource);
+            return _actionLinkHandler.handle(invocation);
         }
         finally
         {

Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/pagelevel/InAppInvocationMapForPageTester.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/pagelevel/InAppInvocationMapForPageTester.java?view=auto&rev=488538
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/pagelevel/InAppInvocationMapForPageTester.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/pagelevel/InAppInvocationMapForPageTester.java Mon Dec 18 22:10:18 2006
@@ -0,0 +1,44 @@
+// Copyright 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.test.pagelevel;
+
+import static org.apache.tapestry.ioc.internal.util.CollectionFactory.newMap;
+
+import java.util.Map;
+
+import org.apache.tapestry.dom.Element;
+import org.apache.tapestry.internal.services.InAppInvocation;
+import org.apache.tapestry.internal.services.InAppInvocationMap;
+
+public class InAppInvocationMapForPageTester implements InAppInvocationMap
+{
+    private Map<Element, InAppInvocation> map = newMap();
+
+    public void clear()
+    {
+        map.clear();
+    }
+
+    public void put(Element link, InAppInvocation invocation)
+    {
+        map.put(link, invocation);
+    }
+
+    public InAppInvocation get(Element link)
+    {
+        return map.get(link);
+    }
+
+}

Copied: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/pagelevel/InAppInvoker.java (from r488300, tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/pagelevel/LinkClicker.java)
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/pagelevel/InAppInvoker.java?view=diff&rev=488538&p1=tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/pagelevel/LinkClicker.java&r1=488300&p2=tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/pagelevel/InAppInvoker.java&r2=488538
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/pagelevel/LinkClicker.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/pagelevel/InAppInvoker.java Mon Dec 18 22:10:18 2006
@@ -15,18 +15,18 @@
 package org.apache.tapestry.test.pagelevel;
 
 import org.apache.tapestry.dom.Document;
-import org.apache.tapestry.internal.services.PathSource;
+import org.apache.tapestry.internal.services.InAppInvocation;
 
 /**
- * Simulates a click on a link.
+ * Invokes an in-app invocation.
  */
-public interface LinkClicker
+public interface InAppInvoker
 {
     /**
-     * @param pageSource
-     *            The path source for the link.
+     * @param invocation
+     *            The in-app invocation object to be invoked.
      * @return The DOM created. Typically you will assert against it.
      */
-    Document click(PathSource pathSource);
+    Document invoke(InAppInvocation invocation);
 
 }

Copied: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/pagelevel/PageLinkInvoker.java (from r488300, tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/pagelevel/PageLinkClicker.java)
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/pagelevel/PageLinkInvoker.java?view=diff&rev=488538&p1=tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/pagelevel/PageLinkClicker.java&r1=488300&p2=tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/pagelevel/PageLinkInvoker.java&r2=488538
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/pagelevel/PageLinkClicker.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/pagelevel/PageLinkInvoker.java Mon Dec 18 22:10:18 2006
@@ -15,19 +15,19 @@
 package org.apache.tapestry.test.pagelevel;
 
 import org.apache.tapestry.dom.Document;
+import org.apache.tapestry.internal.services.InAppInvocation;
 import org.apache.tapestry.internal.services.MarkupWriterImpl;
 import org.apache.tapestry.internal.services.PageLinkHandler;
-import org.apache.tapestry.internal.services.PageLinkPathSource;
+import org.apache.tapestry.internal.services.PageLinkInvocation;
 import org.apache.tapestry.internal.services.PageMarkupRenderer;
 import org.apache.tapestry.internal.services.PageRenderer;
-import org.apache.tapestry.internal.services.PathSource;
 import org.apache.tapestry.internal.structure.Page;
 import org.apache.tapestry.ioc.Registry;
 
 /**
  * Simulates a click on a page link.
  */
-public class PageLinkClicker implements LinkClicker
+public class PageLinkInvoker implements InAppInvoker
 {
     private final Registry _registry;
 
@@ -35,7 +35,7 @@
 
     private final PageMarkupRenderer _renderer;
 
-    public PageLinkClicker(Registry registry)
+    public PageLinkInvoker(Registry registry)
     {
         _registry = registry;
         _pageLinkHandler = _registry.getService(PageLinkHandler.class);
@@ -45,16 +45,16 @@
     /**
      * Click on the page link.
      * 
-     * @param pageSource
-     *            The path source for the page link.
+     * @param invocation
+     *            The in-app invocation object corresponding to the page link.
      * @return The DOM created. Typically you will assert against it.
      */
-    public Document click(PathSource pathSource)
+    public Document invoke(InAppInvocation invocation)
     {
         try
         {
             final MarkupWriterImpl writer = new MarkupWriterImpl();
-            _pageLinkHandler.handle((PageLinkPathSource) pathSource, new PageRenderer()
+            _pageLinkHandler.handle((PageLinkInvocation) invocation, new PageRenderer()
             {
 
                 public void renderPage(Page page)

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/pagelevel/PageTester.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/pagelevel/PageTester.java?view=diff&rev=488538&r1=488537&r2=488538
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/pagelevel/PageTester.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/pagelevel/PageTester.java Mon Dec 18 22:10:18 2006
@@ -22,10 +22,10 @@
 import org.apache.tapestry.dom.Document;
 import org.apache.tapestry.dom.Element;
 import org.apache.tapestry.internal.TapestryAppInitializer;
-import org.apache.tapestry.internal.services.ActionLinkPathSource;
-import org.apache.tapestry.internal.services.LinkImpl;
-import org.apache.tapestry.internal.services.PageLinkPathSource;
-import org.apache.tapestry.internal.services.PathSource;
+import org.apache.tapestry.internal.services.ActionLinkInvocation;
+import org.apache.tapestry.internal.services.InAppInvocation;
+import org.apache.tapestry.internal.services.InAppInvocationMap;
+import org.apache.tapestry.internal.services.PageLinkInvocation;
 import org.apache.tapestry.ioc.Registry;
 import org.apache.tapestry.ioc.internal.util.Defense;
 import org.apache.tapestry.ioc.util.StrategyRegistry;
@@ -36,11 +36,13 @@
  * element in the DOM object to get the next page. Because no servlet container is required, it is
  * very fast and you can directly debug into your code in your IDE.
  */
-public class PageTester
+public class PageTester implements InAppInvoker
 {
     private Registry _registry;
 
-    private StrategyRegistry<LinkClicker> _clickerRegistry;
+    private InAppInvocationMap _invocationMap;
+
+    private StrategyRegistry<InAppInvoker> _invokerRegistry;
 
     /**
      * Initializes a PageTester without overriding any services.
@@ -68,26 +70,30 @@
     {
         _registry = new TapestryAppInitializer(appPackage, appName, "test",
                 addDefaultOverrides(serviceOverrides)).getRegistry();
-        buildLinkClickersRegistry();
+        buildInvokersRegistry();
     }
 
-    private void buildLinkClickersRegistry()
+    private void buildInvokersRegistry()
     {
-        PageLinkClicker pageLinkClicker = new PageLinkClicker(_registry);
-        Map<Class, LinkClicker> map = newMap();
-        map.put(PageLinkPathSource.class, pageLinkClicker);
-        map.put(ActionLinkPathSource.class, new ActionLinkClicker(_registry, pageLinkClicker));
-        _clickerRegistry = new StrategyRegistry<LinkClicker>(LinkClicker.class, map);
+        Map<Class, InAppInvoker> map = newMap();
+        map.put(PageLinkInvocation.class, new PageLinkInvoker(_registry));
+        map.put(ActionLinkInvocation.class, new ActionLinkInvoker(_registry, this));
+        _invokerRegistry = new StrategyRegistry<InAppInvoker>(InAppInvoker.class, map);
     }
 
     private Map<String, Object> addDefaultOverrides(Map<String, Object> serviceOverrides)
     {
+        _invocationMap = new InAppInvocationMapForPageTester();
         Map<String, Object> modifiedOverrides = newMap(serviceOverrides);
         addDefaultOverride(
                 modifiedOverrides,
                 "tapestry.internal.ContextPathSource",
                 new FooContextPathSource());
         addDefaultOverride(modifiedOverrides, "tapestry.internal.URLEncoder", new NoOpURLEncoder());
+        addDefaultOverride(
+                modifiedOverrides,
+                "tapestry.internal.InAppInvocationMap",
+                _invocationMap);
         return modifiedOverrides;
     }
 
@@ -119,7 +125,7 @@
      */
     public Document renderPage(String pageName)
     {
-        return clickLink(new PageLinkPathSource(null, pageName, new Object[0]));
+        return invoke(new PageLinkInvocation(pageName, new Object[0]));
     }
 
     /**
@@ -132,17 +138,22 @@
     public Document clickLink(Element link)
     {
         Defense.notNull(link, "link");
-        if (!(link.getSrc() instanceof LinkImpl))
+        InAppInvocation invocation = _invocationMap.get(link);
+        if (invocation == null)
         {
-            throw new IllegalArgumentException("No source object is associated with the Element");
+            throw new IllegalArgumentException(
+                    "No in-app invocation object is associated with the Element");
         }
-        return clickLink(((LinkImpl) link.getSrc()).getPathSource());
+        return invoke(invocation);
     }
 
-    private Document clickLink(PathSource pathSource)
+    public Document invoke(InAppInvocation invocation)
     {
-        LinkClicker clicker = _clickerRegistry.getByInstance(pathSource);
-        return clicker.click(pathSource);
+        // It is critical to clear the map before invoking an invocation (render a page or click a
+        // link).
+        _invocationMap.clear();
+        InAppInvoker invoker = _invokerRegistry.getByInstance(invocation);
+        return invoker.invoke(invocation);
     }
 
 }