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

svn commit: r488165 [1/2] - in /tapestry/tapestry5/tapestry-core/trunk/src: main/java/org/apache/tapestry/corelib/components/ main/java/org/apache/tapestry/dom/ main/java/org/apache/tapestry/dom/util/ main/java/org/apache/tapestry/internal/ main/java/o...

Author: freemant
Date: Mon Dec 18 01:13:08 2006
New Revision: 488165

URL: http://svn.apache.org/viewvc?view=rev&rev=488165
Log:
1) Adopted the underscore naming convention for fields and test methods.
2) PageTester can now test action links and page links with contexts.
3) Added page-level unit tests for Loop and ActionLink.

Added:
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/dom/util/
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/dom/util/PrintOutCollector.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/ActionLinkPathSource.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ConstantPathSource.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ContextPathSource.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/PageLinkPathSource.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageRenderer.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PathSource.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/URLEncoder.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/pagelevel/FooContextPathSource.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/pagelevel/NoOpURLEncoder.java
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app2/pages/ResultPageForActionLink.java
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app2/pages/TestPageForActionLink.java
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app2/pages/TestPageForLoop.java
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/pagelevel/ActionLinkTest.java
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/pagelevel/LoopTest.java
    tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/integration/app2/pages/ResultPageForActionLink.html
    tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/integration/app2/pages/TestPageForActionLink.html
    tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/integration/app2/pages/TestPageForLoop.html
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/dom/Node.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/TapestryAppInitializer.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/PageRenderDispatcher.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/Request.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/Response.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/TapestryModule.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/pagelevel/PageTester.java
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/dom/DOMTest.java
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/pagelevel/IfTest.java
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/PageRenderDispatcherTest.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=488165&r1=488164&r2=488165
==============================================================================
--- 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 01:13:08 2006
@@ -12,61 +12,70 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package org.apache.tapestry.corelib.components;
-
-import static org.apache.tapestry.TapestryConstants.DEFAULT_EVENT;
-
-import java.util.List;
-
-import org.apache.tapestry.ComponentResources;
-import org.apache.tapestry.Link;
-import org.apache.tapestry.MarkupWriter;
-import org.apache.tapestry.annotations.AfterRender;
-import org.apache.tapestry.annotations.BeginRender;
-import org.apache.tapestry.annotations.ComponentClass;
-import org.apache.tapestry.annotations.Inject;
-import org.apache.tapestry.annotations.Mixin;
-import org.apache.tapestry.annotations.Parameter;
-import org.apache.tapestry.corelib.mixins.RenderInformals;
-
-/**
- * Component that triggers an action on the server with a subsequent full page refresh.
- * 
- * 
- */
-@ComponentClass
-public class ActionLink
-{
-    /**
-     * The context for the link (optional parameter). This list of values will be converted into
-     * strings and included in the URI. The strings will be coerced back to whatever their values
-     * are and made available to event handler methods.
-     */
-    @Parameter
-    private List<?> _context;
-
-    @Inject
-    private ComponentResources _resources;
-    
-    @SuppressWarnings("unused")
-    @Mixin
-    private RenderInformals _renderInformals;
-
-    @BeginRender
-    void begin(MarkupWriter writer)
-    {
-        Object[] contextArray = _context == null ? new Object[0] : _context.toArray();
-
-        Link link = _resources.createActionLink(DEFAULT_EVENT, false, contextArray);
-
-        writer.element("a", "href", link.toURI());
-        
-        // TODO: Support for informal parameters, etc.
-    }
-
-    @AfterRender
-    void end(MarkupWriter writer)
-    {
-        writer.end(); // <a>
-    }
-}
+package org.apache.tapestry.corelib.components;
+
+import static org.apache.tapestry.TapestryConstants.DEFAULT_EVENT;
+
+import java.util.List;
+
+import org.apache.tapestry.ComponentResources;
+import org.apache.tapestry.Link;
+import org.apache.tapestry.MarkupWriter;
+import org.apache.tapestry.annotations.AfterRender;
+import org.apache.tapestry.annotations.BeginRender;
+import org.apache.tapestry.annotations.ComponentClass;
+import org.apache.tapestry.annotations.Environmental;
+import org.apache.tapestry.annotations.Inject;
+import org.apache.tapestry.annotations.Mixin;
+import org.apache.tapestry.annotations.Parameter;
+import org.apache.tapestry.corelib.mixins.RenderInformals;
+import org.apache.tapestry.dom.Element;
+import org.apache.tapestry.services.PageRenderSupport;
+
+/**
+ * Component that triggers an action on the server with a subsequent full page refresh.
+ */
+@ComponentClass
+public class ActionLink
+{
+    /**
+     * The context for the link (optional parameter). This list of values will be converted into
+     * strings and included in the URI. The strings will be coerced back to whatever their values
+     * are and made available to event handler methods.
+     */
+    @Parameter
+    private List<?> _context;
+
+    @Inject
+    private ComponentResources _resources;
+
+    @SuppressWarnings("unused")
+    @Mixin
+    private RenderInformals _renderInformals;
+
+    @Environmental
+    private PageRenderSupport _support;
+
+    @BeginRender
+    void begin(MarkupWriter writer)
+    {
+        String clientId = _support.allocateClientId(_resources.getId());
+
+        Object[] contextArray = _context == null ? new Object[0] : _context.toArray();
+
+        Link link = _resources.createActionLink(DEFAULT_EVENT, false, contextArray);
+
+        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);
+
+        // TODO: Support for informal parameters, etc.
+    }
+
+    @AfterRender
+    void end(MarkupWriter writer)
+    {
+        writer.end(); // <a>
+    }
+}

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=488165&r1=488164&r2=488165
==============================================================================
--- 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 01:13:08 2006
@@ -40,6 +40,8 @@
 
     private final Document _document;
 
+    private Object _src;
+
     Element(Document container, String name)
     {
         super(container);
@@ -227,5 +229,29 @@
             return null;
         }
         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/dom/Node.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/dom/Node.java?view=diff&rev=488165&r1=488164&r2=488165
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/dom/Node.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/dom/Node.java Mon Dec 18 01:13:08 2006
@@ -17,10 +17,11 @@
 import static org.apache.tapestry.ioc.internal.util.CollectionFactory.newList;
 
 import java.io.PrintWriter;
-import java.io.StringWriter;
 import java.util.Collections;
 import java.util.List;
 
+import org.apache.tapestry.dom.util.PrintOutCollector;
+
 /**
  * A node within the DOM.
  */
@@ -69,19 +70,24 @@
     }
 
     /**
+     * @return the concatenation of the String representations {@link #toString()} of its children.
+     */
+    public String getChildText()
+    {
+        PrintOutCollector collector = new PrintOutCollector();
+        writeChildXML(collector.getPrintWriter());
+        return collector.getPrintOut();
+    }
+
+    /**
      * Invokes {@link #toMarkup(PrintWriter)}, collecting output in a string, which is returned.
      */
     @Override
     public String toString()
     {
-        StringWriter stringWriter = new StringWriter();
-        PrintWriter pw = new PrintWriter(stringWriter);
-
-        toMarkup(pw);
-
-        pw.close();
-
-        return stringWriter.toString();
+        PrintOutCollector collector = new PrintOutCollector();
+        toMarkup(collector.getPrintWriter());
+        return collector.getPrintOut();
     }
 
     @SuppressWarnings("unchecked")

Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/dom/util/PrintOutCollector.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/dom/util/PrintOutCollector.java?view=auto&rev=488165
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/dom/util/PrintOutCollector.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/dom/util/PrintOutCollector.java Mon Dec 18 01:13:08 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.dom.util;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+public class PrintOutCollector
+{
+    private StringWriter _stringWriter;
+
+    private PrintWriter _printWriter;
+
+    public PrintOutCollector()
+    {
+        _stringWriter = new StringWriter();
+        _printWriter = new PrintWriter(_stringWriter);
+    }
+
+    public PrintWriter getPrintWriter()
+    {
+        return _printWriter;
+    }
+
+    public String getPrintOut()
+    {
+        _printWriter.close();
+        return _stringWriter.toString();
+
+    }
+
+}

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/TapestryAppInitializer.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/TapestryAppInitializer.java?view=diff&rev=488165&r1=488164&r2=488165
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/TapestryAppInitializer.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/TapestryAppInitializer.java Mon Dec 18 01:13:08 2006
@@ -14,6 +14,9 @@
 
 package org.apache.tapestry.internal;
 
+import java.util.Map;
+import java.util.Map.Entry;
+
 import org.apache.tapestry.ioc.IOCUtilities;
 import org.apache.tapestry.ioc.Registry;
 import org.apache.tapestry.ioc.RegistryBuilder;
@@ -34,26 +37,35 @@
  */
 public class TapestryAppInitializer
 {
-    private String appPackage;
+    private String _appPackage;
+
+    private String _appName;
 
-    private String appName;
+    private String _infrastructureMode;
 
-    private String infrastructureMode;
+    private Registry _registry;
 
-    private Registry registry;
+    private long _startTime;
 
-    private long startTime;
+    private long _registryCreatedTime;
 
-    private long registryCreatedTime;
+    private final Map<String, Object> _serviceOverrides;
 
     public TapestryAppInitializer(String appPackage, String appName, String infrastructureMode)
     {
-        this.appPackage = appPackage;
-        this.appName = appName;
-        this.infrastructureMode = infrastructureMode;
-        startTime = System.currentTimeMillis();
+        this(appPackage, appName, infrastructureMode, null);
+    }
+
+    public TapestryAppInitializer(String appPackage, String appName, String infrastructureMode,
+            Map<String, Object> serviceOverrides)
+    {
+        _appPackage = appPackage;
+        _appName = appName;
+        _infrastructureMode = infrastructureMode;
+        _serviceOverrides = serviceOverrides;
+        _startTime = System.currentTimeMillis();
         createRegistry();
-        registryCreatedTime = System.currentTimeMillis();
+        _registryCreatedTime = System.currentTimeMillis();
         setupServices();
     }
 
@@ -63,7 +75,8 @@
 
         builder.add(TapestryModule.class);
 
-        String className = appPackage + ".services." + InternalUtils.capitalize(appName) + "Module";
+        String className = _appPackage + ".services." + InternalUtils.capitalize(_appName)
+                + "Module";
 
         try
         {
@@ -82,19 +95,33 @@
 
         addModules(builder);
 
-        registry = builder.build();
+        overrideServices(builder);
+
+        _registry = builder.build();
+    }
+
+    private void overrideServices(RegistryBuilder builder)
+    {
+        if (_serviceOverrides != null)
+        {
+            for (Entry<String, Object> e : _serviceOverrides.entrySet())
+            {
+                builder.addServiceOverride(e.getKey(), e.getValue());
+            }
+        }
     }
 
     private void setupServices()
     {
-        Infrastructure infra = registry.getService("tapestry.Infrastructure", Infrastructure.class);
-        infra.setMode(infrastructureMode);
+        Infrastructure infra = _registry
+                .getService("tapestry.Infrastructure", Infrastructure.class);
+        infra.setMode(_infrastructureMode);
 
-        ComponentClassResolver resolver = registry.getService(
+        ComponentClassResolver resolver = _registry.getService(
                 "tapestry.ComponentClassResolver",
                 ComponentClassResolver.class);
 
-        resolver.setApplicationPackage(appPackage);
+        resolver.setApplicationPackage(_appPackage);
     }
 
     /**
@@ -113,7 +140,7 @@
 
     public Registry getRegistry()
     {
-        return registry;
+        return _registry;
     }
 
     /**
@@ -121,7 +148,7 @@
      */
     public long getRegistryCreatedTime()
     {
-        return registryCreatedTime;
+        return _registryCreatedTime;
     }
 
     /**
@@ -129,6 +156,6 @@
      */
     public long getStartTime()
     {
-        return startTime;
+        return _startTime;
     }
 }

Added: 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=auto&rev=488165
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ActionLinkHandler.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ActionLinkHandler.java Mon Dec 18 01:13:08 2006
@@ -0,0 +1,8 @@
+package org.apache.tapestry.internal.services;
+
+import org.apache.tapestry.Link;
+
+public interface ActionLinkHandler
+{
+    Link handle(ActionLinkPathSource pathSource);
+}

Added: 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=auto&rev=488165
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ActionLinkHandlerImpl.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ActionLinkHandlerImpl.java Mon Dec 18 01:13:08 2006
@@ -0,0 +1,49 @@
+package org.apache.tapestry.internal.services;
+
+import org.apache.tapestry.ComponentEventHandler;
+import org.apache.tapestry.Link;
+import org.apache.tapestry.internal.structure.ComponentPageElement;
+import org.apache.tapestry.internal.structure.Page;
+
+public class ActionLinkHandlerImpl implements ActionLinkHandler
+{
+    private final ComponentEventHandler _componentEventHandler;
+
+    private final RequestPageCache _cache;
+
+    private final LinkFactory _linkFactory;
+
+    public ActionLinkHandlerImpl(ComponentEventHandler componentEventHandler,
+            RequestPageCache cache, LinkFactory linkFactory)
+    {
+        _componentEventHandler = componentEventHandler;
+        _cache = cache;
+        _linkFactory = linkFactory;
+    }
+
+    public Link handle(ActionLinkPathSource pathSource)
+    {
+        Page page = _cache.get(pathSource.getPageName());
+
+        // This is the active page, until we know better.
+
+        _cache.setActive(page);
+
+        ComponentPageElement element = page.getComponentElementByNestedId(pathSource
+                .getComponentNestedId());
+
+        element.triggerEvent(
+                pathSource.getAction(),
+                pathSource.getContext().toArray(),
+                _componentEventHandler);
+
+        // It's possible that the component event will have changed the active page.
+        // Whatever the active page is NOW is what we'll send back (as a client redirect)
+        // to render.
+
+        page = _cache.getActive();
+
+        return _linkFactory.createPageLink(page);
+    }
+
+}

Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ActionLinkPathSource.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ActionLinkPathSource.java?view=auto&rev=488165
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ActionLinkPathSource.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ActionLinkPathSource.java Mon Dec 18 01:13:08 2006
@@ -0,0 +1,91 @@
+// 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 java.util.List;
+
+public class ActionLinkPathSource implements PathSource
+{
+
+    private final String _contextPath;
+
+    private final String _action;
+
+    private final String _pageName;
+
+    private final String _componentNestedId;
+
+    private final List<?> _context;
+
+    public ActionLinkPathSource(String contextPath, String action, String pageName, String componentNestedId,
+            List<?> context)
+    {
+        _contextPath = contextPath;
+        _action = action;
+        _pageName = pageName;
+        _componentNestedId = componentNestedId;
+        _context = context;
+
+    }
+
+    public String getPath()
+    {
+        StringBuilder builder = new StringBuilder();
+
+        builder.append(_contextPath);
+        builder.append("/");
+        builder.append(_pageName);
+        builder.append(".");
+        builder.append(_action);
+        builder.append("/");
+        builder.append(_componentNestedId);
+
+        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 String getAction()
+    {
+        return _action;
+    }
+
+    public String getComponentNestedId()
+    {
+        return _componentNestedId;
+    }
+
+    public List<?> getContext()
+    {
+        return _context;
+    }
+
+    public String getContextPath()
+    {
+        return _contextPath;
+    }
+
+    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=488165&r1=488164&r2=488165
==============================================================================
--- 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 01:13:08 2006
@@ -12,87 +12,64 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package org.apache.tapestry.internal.services;
-
+package org.apache.tapestry.internal.services;
+
 import java.io.IOException;
+import java.util.Arrays;
 
-import org.apache.tapestry.ComponentEventHandler;
 import org.apache.tapestry.Link;
-import org.apache.tapestry.internal.structure.ComponentPageElement;
-import org.apache.tapestry.internal.structure.Page;
 import org.apache.tapestry.services.Dispatcher;
 import org.apache.tapestry.services.Request;
 import org.apache.tapestry.services.Response;
-
-/**
- * Processes component action events sent as requests from the client. Action events include an
- * event type, identify a page and a component, and may provide additional context strings.
- */
-public class ComponentEventDispatcher implements Dispatcher
-{
-    private final ComponentEventHandler _componentEventHandler;
-    
-    private final RequestPageCache _cache;
-
-    private final LinkFactory _linkFactory;
-    
-    public ComponentEventDispatcher(ComponentEventHandler componentEventHandler, final RequestPageCache cache, LinkFactory linkFactory)
+
+/**
+ * Processes component action events sent as requests from the client. Action events include an
+ * event type, identify a page and a component, and may provide additional context strings.
+ */
+public class ComponentEventDispatcher implements Dispatcher
+{
+    private final ActionLinkHandler _actionLinkHandler;
+
+    public ComponentEventDispatcher(ActionLinkHandler actionLinkHandler)
+    {
+        _actionLinkHandler = actionLinkHandler;
+    }
+
+    public boolean dispatch(Request request, Response response) throws IOException
     {
-        _componentEventHandler = componentEventHandler;
-        _cache = cache;
-        _linkFactory = linkFactory;
-    }
-
-    public boolean dispatch(Request request, Response response) throws IOException
-    {
-        String path = request.getPath();
-
-        int dotx = path.indexOf('.');
-
-        if (dotx < 0)
-            return false;
-
-        // Skip the leading slash, the rest is logical page name.
-
-        String logicalPageName = path.substring(1, dotx);
-
-        Page page = _cache.get(logicalPageName);
-        
-        // This is the active page, until we know better.
-        
-        _cache.setActive(page);
-
-        int slashx = path.indexOf('/', dotx + 1);
-
-        String eventType = path.substring(dotx + 1, slashx);
-
-        String remainder = path.substring(slashx + 1);
-
-        String[] chunks = remainder.split("/");
-
-        String nestedComponentId = chunks[0];
-
-        String[] context = new String[chunks.length - 1];
-        for (int i = 1; i < chunks.length; i++)
-            context[i - 1] = chunks[i];
-
-        ComponentPageElement element = page.getComponentElementByNestedId(nestedComponentId);
-
-        element.triggerEvent(eventType, context, _componentEventHandler);
-        
-        // It's possible that the component event will have changed the active page.
-        // Whatever the active page is NOW is what we'll send back (as a client redirect)
-        // to render.
-        
-        page = _cache.getActive();
-        
-        Link link = _linkFactory.createPageLink(page);
-
-        String URL = link.toRedirectURI();
-
-        response.sendRedirect(URL);
-
-        return true;
-    }
-
-}
+        String path = request.getPath();
+
+        int dotx = path.indexOf('.');
+
+        if (dotx < 0)
+            return false;
+
+        // Skip the leading slash, the rest is logical page name.
+
+        String logicalPageName = path.substring(1, dotx);
+
+        int slashx = path.indexOf('/', dotx + 1);
+
+        String eventType = path.substring(dotx + 1, slashx);
+
+        String remainder = path.substring(slashx + 1);
+
+        String[] chunks = remainder.split("/");
+
+        String nestedComponentId = chunks[0];
+
+        String[] context = new String[chunks.length - 1];
+        for (int i = 1; i < chunks.length; i++)
+            context[i - 1] = chunks[i];
+
+        Link link = _actionLinkHandler.handle(new ActionLinkPathSource(null, eventType,
+                logicalPageName, nestedComponentId, Arrays.asList(context)));
+
+        String URL = link.toRedirectURI();
+
+        response.sendRedirect(URL);
+
+        return true;
+    }
+
+}

Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ConstantPathSource.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ConstantPathSource.java?view=auto&rev=488165
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ConstantPathSource.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ConstantPathSource.java Mon Dec 18 01:13:08 2006
@@ -0,0 +1,31 @@
+// 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 class ConstantPathSource implements PathSource
+{
+    private String _path;
+
+    public ConstantPathSource(String path)
+    {
+        this._path = path;
+    }
+
+    public String getPath()
+    {
+        return _path;
+    }
+
+}

Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ContextPathSource.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ContextPathSource.java?view=auto&rev=488165
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ContextPathSource.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ContextPathSource.java Mon Dec 18 01:13:08 2006
@@ -0,0 +1,29 @@
+// 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 is an object that can provide the context path of the web app. For example, the
+ * {@link org.apache.tapestry.services.Request} is one such object.
+ */
+public interface ContextPathSource
+{
+    /**
+     * Returns the context path. This always starts with a "/" character and does not end with one,
+     * with the exception of servlets in the root context, which return the empty string.
+     */
+    String getContextPath();
+
+}

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=488165&r1=488164&r2=488165
==============================================================================
--- 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 01:13:08 2006
@@ -241,8 +241,7 @@
 
     public static PageResponseRenderer buildPageResponseRenderer(
             @InjectService("PageMarkupRenderer")
-            PageMarkupRenderer markupRenderer,
-            @InjectService("tapestry.MarkupWriterFactory")
+            PageMarkupRenderer markupRenderer, @InjectService("tapestry.MarkupWriterFactory")
             MarkupWriterFactory markupWriterFactory)
     {
         return new PageResponseRendererImpl(markupWriterFactory, markupRenderer);
@@ -503,9 +502,21 @@
     }
 
     /** Service used to create links for components and pages. */
-    public LinkFactory buildLinkFactory()
+    public LinkFactory buildLinkFactory(@InjectService("ContextPathSource")
+    ContextPathSource contextPathSource, @InjectService("URLEncoder")
+    URLEncoder encoder)
     {
-        return new LinkFactoryImpl(_request, _response, _componentClassResolver);
+        return new LinkFactoryImpl(contextPathSource, encoder, _componentClassResolver);
+    }
+
+    public ContextPathSource buildContextPathSource()
+    {
+        return _request;
+    }
+
+    public URLEncoder buildURLEncoder()
+    {
+        return _response;
     }
 
     public ResourceStreamer buildResourceStreamer()

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=488165&r1=488164&r2=488165
==============================================================================
--- 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 01:13:08 2006
@@ -18,6 +18,7 @@
 import static org.apache.tapestry.ioc.internal.util.CollectionFactory.newMap;
 import static org.apache.tapestry.ioc.internal.util.CollectionFactory.newThreadSafeList;
 
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.List;
 import java.util.Map;
@@ -31,14 +32,12 @@
 import org.apache.tapestry.ioc.util.StrategyRegistry;
 import org.apache.tapestry.runtime.Component;
 import org.apache.tapestry.services.ComponentClassResolver;
-import org.apache.tapestry.services.Request;
-import org.apache.tapestry.services.Response;
 
 public class LinkFactoryImpl implements LinkFactory
 {
-    private final Request _request;
+    private final ContextPathSource _contextPathSource;
 
-    private final Response _response;
+    private final URLEncoder _encoder;
 
     private final ComponentClassResolver _componentClassResolver;
 
@@ -51,11 +50,11 @@
         void handle(T result, List context);
     }
 
-    public LinkFactoryImpl(Request request, Response response,
+    public LinkFactoryImpl(ContextPathSource contextPathSource, URLEncoder encoder,
             ComponentClassResolver componentClassResolver)
     {
-        _request = request;
-        _response = response;
+        _contextPathSource = contextPathSource;
+        _encoder = encoder;
         _componentClassResolver = componentClassResolver;
 
         Map<Class, PassivateContextHandler> registrations = newMap();
@@ -106,26 +105,11 @@
 
         String logicalPageName = _componentClassResolver.resolvePageClassNameToPageName(pageName);
 
-        StringBuilder builder = new StringBuilder();
+        ActionLinkPathSource pathSource = new ActionLinkPathSource(_contextPathSource
+                .getContextPath(), action, logicalPageName, component.getNestedId(), Arrays
+                .asList(context));
 
-        builder.append(_request.getContextPath());
-        builder.append("/");
-        builder.append(logicalPageName);
-        builder.append(".");
-        builder.append(action);
-        builder.append("/");
-        builder.append(component.getNestedId());
-
-        for (Object id : context)
-        {
-            builder.append("/");
-
-            // TODO: Need to encode this for URLs? What if the string contains slashes, etc.?
-
-            builder.append(id.toString());
-        }
-
-        Link link = new LinkImpl(_response, builder.toString());
+        Link link = new LinkImpl(_encoder, pathSource);
 
         for (LinkFactoryListener listener : _listeners)
             listener.createdActionLink(link);
@@ -143,13 +127,6 @@
         String pageName = page.getName();
         String logicalPageName = _componentClassResolver.resolvePageClassNameToPageName(pageName);
 
-        StringBuilder builder = new StringBuilder();
-
-        builder.append(_request.getContextPath());
-        builder.append("/");
-        builder.append(logicalPageName);
-        builder.append(".html");
-
         final List context = newList();
 
         ComponentEventHandler handler = new ComponentEventHandler()
@@ -167,16 +144,9 @@
 
         rootElement.triggerEvent(TapestryConstants.PASSIVATE_EVENT, null, handler);
 
-        for (Object id : context)
-        {
-            builder.append("/");
-
-            // TODO: Need to encode this for URLs? What if the string contains slashes, etc.?
-
-            builder.append(id.toString());
-        }
+        PageLinkPathSource pathSource = new PageLinkPathSource(_contextPathSource.getContextPath(), logicalPageName, context);
 
-        Link link = new LinkImpl(_response, builder.toString());
+        Link link = new LinkImpl(_encoder, pathSource);
 
         for (LinkFactoryListener listener : _listeners)
             listener.createdPageLink(link);

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=488165&r1=488164&r2=488165
==============================================================================
--- 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 01:13:08 2006
@@ -12,109 +12,120 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package org.apache.tapestry.internal.services;
-
+package org.apache.tapestry.internal.services;
+
 import static org.apache.tapestry.ioc.internal.util.CollectionFactory.newMap;
-
-import java.util.List;
-import java.util.Map;
-
-import org.apache.commons.codec.EncoderException;
-import org.apache.commons.codec.net.URLCodec;
-import org.apache.tapestry.Link;
+
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.codec.EncoderException;
+import org.apache.commons.codec.net.URLCodec;
+import org.apache.tapestry.Link;
 import org.apache.tapestry.ioc.internal.util.InternalUtils;
-import org.apache.tapestry.services.Response;
-
-/**
- * Starting implementation of {@link Link}. Currently does not support query parameters.
- */
-public class LinkImpl implements Link
-{
-    private final Response _response;
-
-    private final String _path;
-
-    private Map<String, String> _parameters;
-
-    public LinkImpl(Response response, String path)
-    {
-        _response = response;
-        _path = path;
-    }
-
-    public void addParameter(String parameterName, String value)
-    {
-        if (_parameters == null)
-            _parameters = newMap();
-
-        if (_parameters.containsKey(parameterName))
-            throw new IllegalArgumentException(ServicesMessages.parameterNameMustBeUnique(
-                    parameterName,
-                    _parameters.get(parameterName)));
-
-        _parameters.put(parameterName, value);
-    }
-
-    public String toFormURI()
-    {
-        return _response.encodeURL(_path);
-    }
-
-    public List<String> getParameterNames()
-    {
-        return InternalUtils.sortedKeys(_parameters);
-    }
-
-    public String getParameterValue(String name)
-    {
-        return InternalUtils.get(_parameters, name);
-    }
-
-    public String toURI()
-    {
-        return _response.encodeURL(buildURI());
-    }
-
-    private String buildURI()
-    {
-        if (_parameters == null)
-            return _path;
-
-        StringBuilder builder = new StringBuilder();
-
-        builder.append(_path);
-
-        try
-        {
-            URLCodec codec = new URLCodec();
-
-            String sep = "?";
-
-            for (String name : getParameterNames())
-            {
-                String value = _parameters.get(name);
-
-                builder.append(sep);
-
-                // TODO: encode the parameter name?
-
-                builder.append(name);
-                builder.append("=");
-                builder.append(codec.encode(value));
-
-                sep = "&";
-            }
-        }
-        catch (EncoderException ex)
-        {
-            throw new RuntimeException(ex);
-        }
-
-        return builder.toString();
-    }
-
-    public String toRedirectURI()
-    {
-        return _response.encodeRedirectURL(buildURI());
-    }
-}
+
+/**
+ * Starting implementation of {@link Link}. Currently does not support query parameters.
+ */
+public class LinkImpl implements Link
+{
+    private URLEncoder _encoder;
+
+    private final PathSource _pathSource;
+
+    private Map<String, String> _parameters;
+
+    public LinkImpl(URLEncoder encoder, String path)
+    {
+        _encoder = encoder;
+        _pathSource = new ConstantPathSource(path);
+    }
+
+    public LinkImpl(URLEncoder encoder, PathSource pathSource)
+    {
+        _encoder = encoder;
+        _pathSource = pathSource;
+    }
+
+    public void addParameter(String parameterName, String value)
+    {
+        if (_parameters == null)
+            _parameters = newMap();
+
+        if (_parameters.containsKey(parameterName))
+            throw new IllegalArgumentException(ServicesMessages.parameterNameMustBeUnique(
+                    parameterName,
+                    _parameters.get(parameterName)));
+
+        _parameters.put(parameterName, value);
+    }
+
+    public String toFormURI()
+    {
+        return _encoder.encodeURL(_pathSource.getPath());
+    }
+
+    public List<String> getParameterNames()
+    {
+        return InternalUtils.sortedKeys(_parameters);
+    }
+
+    public String getParameterValue(String name)
+    {
+        return InternalUtils.get(_parameters, name);
+    }
+
+    public String toURI()
+    {
+        return _encoder.encodeURL(buildURI());
+    }
+
+    private String buildURI()
+    {
+        String path = _pathSource.getPath();
+        if (_parameters == null)
+            return path;
+
+        StringBuilder builder = new StringBuilder();
+
+        builder.append(path);
+
+        try
+        {
+            URLCodec codec = new URLCodec();
+
+            String sep = "?";
+
+            for (String name : getParameterNames())
+            {
+                String value = _parameters.get(name);
+
+                builder.append(sep);
+
+                // TODO: encode the parameter name?
+
+                builder.append(name);
+                builder.append("=");
+                builder.append(codec.encode(value));
+
+                sep = "&";
+            }
+        }
+        catch (EncoderException ex)
+        {
+            throw new RuntimeException(ex);
+        }
+
+        return builder.toString();
+    }
+
+    public String toRedirectURI()
+    {
+        return _encoder.encodeRedirectURL(buildURI());
+    }
+
+    public PathSource getPathSource()
+    {
+        return _pathSource;
+    }
+}

Added: 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=auto&rev=488165
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageLinkHandler.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageLinkHandler.java Mon Dec 18 01:13:08 2006
@@ -0,0 +1,6 @@
+package org.apache.tapestry.internal.services;
+
+public interface PageLinkHandler
+{
+    void handle(PageLinkPathSource pathSource, PageRenderer renderer);
+}

Added: 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=auto&rev=488165
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageLinkHandlerImpl.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageLinkHandlerImpl.java Mon Dec 18 01:13:08 2006
@@ -0,0 +1,46 @@
+// 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.TapestryConstants;
+import org.apache.tapestry.internal.structure.Page;
+
+/**
+ * Handles a PageLink as specified by a PageLinkPathSource by activating and then rendering the
+ * page.
+ */
+public class PageLinkHandlerImpl implements PageLinkHandler
+{
+    private final RequestPageCache _cache;
+
+    public PageLinkHandlerImpl(RequestPageCache cache)
+    {
+        _cache = cache;
+    }
+
+    public void handle(PageLinkPathSource pathSource, PageRenderer renderer)
+    {
+        Page page = _cache.get(pathSource.getPageName());
+        // Fire a notification so that the page can set itself up for the given context
+
+        page.getRootElement().triggerEvent(
+                TapestryConstants.ACTIVATE_EVENT,
+                pathSource.getContext().toArray(),
+                null);
+
+        renderer.renderPage(page);
+
+    }
+}

Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageLinkPathSource.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageLinkPathSource.java?view=auto&rev=488165
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageLinkPathSource.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageLinkPathSource.java Mon Dec 18 01:13:08 2006
@@ -0,0 +1,71 @@
+// 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 java.util.List;
+
+public class PageLinkPathSource implements PathSource
+{
+
+    private final String _contextPath;
+
+    private final String _pageName;
+
+    private final List<?> _context;
+
+    public PageLinkPathSource(String contextPath, String pageName, List<?> context)
+    {
+        _contextPath = contextPath;
+        _pageName = pageName;
+        _context = context;
+
+    }
+
+    public String getPath()
+    {
+        StringBuilder builder = new StringBuilder();
+
+        builder.append(_contextPath);
+        builder.append("/");
+        builder.append(_pageName);
+        builder.append(".html");
+
+        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 List<?> getContext()
+    {
+        return _context;
+    }
+
+    public String getContextPath()
+    {
+        return _contextPath;
+    }
+
+    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=488165&r1=488164&r2=488165
==============================================================================
--- 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 01:13:08 2006
@@ -15,8 +15,8 @@
 package org.apache.tapestry.internal.services;
 
 import java.io.IOException;
+import java.util.Arrays;
 
-import org.apache.tapestry.TapestryConstants;
 import org.apache.tapestry.internal.structure.Page;
 import org.apache.tapestry.services.Dispatcher;
 import org.apache.tapestry.services.Request;
@@ -28,17 +28,18 @@
  */
 public class PageRenderDispatcher implements Dispatcher
 {
-    private final PageResponseRenderer _renderer;
+    private final PageLinkHandler _handler;
 
-    private final RequestPageCache _cache;
+    private PageResponseRenderer _renderer;
 
-    public PageRenderDispatcher(PageResponseRenderer renderer, RequestPageCache cache)
+    public PageRenderDispatcher(PageLinkHandler handler, PageResponseRenderer renderer)
     {
+        _handler = handler;
         _renderer = renderer;
-        _cache = cache;
+
     }
 
-    public boolean dispatch(Request request, Response response) throws IOException
+    public boolean dispatch(Request request, final Response response) throws IOException
     {
         String path = request.getPath();
 
@@ -55,8 +56,6 @@
 
         String logicalPageName = path.substring(1, pos);
 
-        Page page = _cache.get(logicalPageName);
-
         String[] terms = path.substring(pos).split("/");
 
         Object[] context = new Object[terms.length - 1];
@@ -66,12 +65,24 @@
             // TODO: Decode strings?
             context[i - 1] = terms[i];
         }
+        _handler.handle(
+                new PageLinkPathSource(null, logicalPageName, Arrays.asList(context)),
+                new PageRenderer()
+                {
+
+                    public void renderPage(Page page)
+                    {
+                        try
+                        {
+                            _renderer.renderPageResponse(page, response);
+                        }
+                        catch (IOException ex)
+                        {
+                            new RuntimeException(ex);
+                        }
 
-        // Fire a notification so that the page can set itself up for the given context
-
-        page.getRootElement().triggerEvent(TapestryConstants.ACTIVATE_EVENT, context, null);
-
-        _renderer.renderPageResponse(page, response);
+                    }
+                });
 
         return true;
     }

Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageRenderer.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageRenderer.java?view=auto&rev=488165
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageRenderer.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageRenderer.java Mon Dec 18 01:13:08 2006
@@ -0,0 +1,27 @@
+// 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.internal.structure.Page;
+
+/**
+ * Service responsible for writing a full page markup response.
+ * 
+ * 
+ */
+public interface PageRenderer
+{
+    void renderPage(Page page);
+}

Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PathSource.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PathSource.java?view=auto&rev=488165
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PathSource.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PathSource.java Mon Dec 18 01:13:08 2006
@@ -0,0 +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.
+
+package org.apache.tapestry.internal.services;
+
+public interface PathSource
+{
+    String getPath();
+}

Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/URLEncoder.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/URLEncoder.java?view=auto&rev=488165
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/URLEncoder.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/URLEncoder.java Mon Dec 18 01:13:08 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;
+
+public interface URLEncoder
+{
+    /**
+     * Encodes the URL, ensuring that a session id is included (if a session exists, and as
+     * necessary depending on the client browser's use of cookies).
+     * 
+     * @param URL
+     * @return the same URL or a different one with additional information to track the user session
+     */
+    String encodeURL(String URL);
+
+    /**
+     * Encodes the URL for use as a redirect, ensuring that a session id is included (if a session
+     * exists, and as necessary depending on the client browser's use of cookies).
+     * 
+     * @param URL
+     * @return the same URL or a different one with additional information to track the user session
+     */
+    String encodeRedirectURL(String URL);
+
+}

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/Request.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/Request.java?view=diff&rev=488165&r1=488164&r2=488165
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/Request.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/Request.java Mon Dec 18 01:13:08 2006
@@ -17,11 +17,13 @@
 import java.util.List;
 import java.util.Locale;
 
+import org.apache.tapestry.internal.services.ContextPathSource;
+
 /**
  * Generic version of {@link javax.servlet.http.HttpServletRequest}, used to encapsulate the
  * Servlet API version, and to help bridge the differences between Servlet API and Porlet API.
  */
-public interface Request
+public interface Request extends ContextPathSource
 {
     /** Returns a list of query parameter names, in alphabetical order. */
     List<String> getParameterNames();
@@ -45,13 +47,6 @@
      * @return
      */
     String getPath();
-
-    /**
-     * Returns the context path portion of the URI. This always starts with a "/" character and does
-     * not end with one, with the exception of servlets in the root context, which return the empty
-     * string.
-     */
-    String getContextPath();
 
     /**
      * Gets the {@link Session}. If create is false and the session has not be created

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/Response.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/Response.java?view=diff&rev=488165&r1=488164&r2=488165
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/Response.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/Response.java Mon Dec 18 01:13:08 2006
@@ -18,11 +18,13 @@
 import java.io.OutputStream;
 import java.io.PrintWriter;
 
+import org.apache.tapestry.internal.services.URLEncoder;
+
 /**
  * API agnostic wrapper for generating a response. Bridges the gaps between the Servlet API and the
  * Portlet API.
  */
-public interface Response
+public interface Response extends URLEncoder
 {
     /**
      * Returns a PrintWriter object to which output may be sent. Invoking flush() on the writer will
@@ -35,24 +37,6 @@
      * stream will commit the output.
      */
     OutputStream getOutputStream() throws IOException;
-
-    /**
-     * Encodes the URL, ensuring that a session id is included (if a session exists, and as
-     * necessary depending on the client browser's use of cookies).
-     * 
-     * @param URL
-     * @return the same URL or a different one with additional information to track the user session
-     */
-    String encodeURL(String URL);
-
-    /**
-     * Encodes the URL for use as a redirect, ensuring that a session id is included (if a session
-     * exists, and as necessary depending on the client browser's use of cookies).
-     * 
-     * @param URL
-     * @return the same URL or a different one with additional information to track the user session
-     */
-    String encodeRedirectURL(String URL);
 
     /**
      * Sends a redirect to the client.

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/TapestryModule.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/TapestryModule.java?view=diff&rev=488165&r1=488164&r2=488165
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/TapestryModule.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/TapestryModule.java Mon Dec 18 01:13:08 2006
@@ -43,6 +43,8 @@
 import org.apache.tapestry.internal.bindings.ComponentBindingFactory;
 import org.apache.tapestry.internal.bindings.LiteralBindingFactory;
 import org.apache.tapestry.internal.bindings.MessageBindingFactory;
+import org.apache.tapestry.internal.services.ActionLinkHandler;
+import org.apache.tapestry.internal.services.ActionLinkHandlerImpl;
 import org.apache.tapestry.internal.services.ApplicationGlobalsImpl;
 import org.apache.tapestry.internal.services.AssetDispatcher;
 import org.apache.tapestry.internal.services.AssetInjectWorker;
@@ -75,6 +77,8 @@
 import org.apache.tapestry.internal.services.MarkupWriterImpl;
 import org.apache.tapestry.internal.services.MixinWorker;
 import org.apache.tapestry.internal.services.OnEventWorker;
+import org.apache.tapestry.internal.services.PageLinkHandler;
+import org.apache.tapestry.internal.services.PageLinkHandlerImpl;
 import org.apache.tapestry.internal.services.PageRenderDispatcher;
 import org.apache.tapestry.internal.services.PageRenderSupportImpl;
 import org.apache.tapestry.internal.services.PageResponseRenderer;
@@ -441,14 +445,13 @@
     }
 
     public void contributeMasterDispatcher(OrderedConfiguration<Dispatcher> configuration,
-            @InjectService("tapestry.internal.LinkFactory")
-            LinkFactory linkFactory, @InjectService("ComponentEventHandler")
-            ComponentEventHandler componentEventHandler,
             @Inject("infrastructure:ClasspathAssetAliasManager")
             ClasspathAssetAliasManager aliasManager,
             @InjectService("tapestry.internal.ResourceCache")
             ResourceCache resourceCache, @InjectService("tapestry.internal.ResourceStreamer")
-            ResourceStreamer streamer)
+            ResourceStreamer streamer, @InjectService("PageLinkHandler")
+            PageLinkHandler pageLinkHandler, @InjectService("ActionLinkHandler")
+            ActionLinkHandler actionLinkHandler)
     {
         // This goes first because an asset to be streamed may have an file extension, such as
         // ".html", that will confuse the later dispatchers.
@@ -458,13 +461,28 @@
                 new AssetDispatcher(streamer, aliasManager, resourceCache),
                 "before:PageRender");
 
-        configuration.add("PageRender", new PageRenderDispatcher(_pageResponseRenderer,
-                _requestPageCache));
+        configuration.add("PageRender", new PageRenderDispatcher(pageLinkHandler,
+                _pageResponseRenderer));
 
         // This goes after the HTML one so that the "." in ".html" doesn't confuse it.
 
-        configuration.add("ComponentEvent", new ComponentEventDispatcher(componentEventHandler,
-                _requestPageCache, linkFactory), "after:PageRender");
+        configuration.add(
+                "ComponentEvent",
+                new ComponentEventDispatcher(actionLinkHandler),
+                "after:PageRender");
+    }
+
+    public PageLinkHandler buildPageLinkHandler(@InjectService("Response")
+    final Response response)
+    {
+        return new PageLinkHandlerImpl(_requestPageCache);
+    }
+
+    public ActionLinkHandler buildActionLinkHandler(@InjectService("ComponentEventHandler")
+    ComponentEventHandler componentEventHandler, @InjectService("tapestry.internal.LinkFactory")
+    LinkFactory linkFactory)
+    {
+        return new ActionLinkHandlerImpl(componentEventHandler, _requestPageCache, linkFactory);
     }
 
     public static ComponentClassResolver buildComponentClassResolver(

Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/pagelevel/FooContextPathSource.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/pagelevel/FooContextPathSource.java?view=auto&rev=488165
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/pagelevel/FooContextPathSource.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/pagelevel/FooContextPathSource.java Mon Dec 18 01:13:08 2006
@@ -0,0 +1,13 @@
+package org.apache.tapestry.test.pagelevel;
+
+import org.apache.tapestry.internal.services.ContextPathSource;
+
+public class FooContextPathSource implements ContextPathSource
+{
+
+    public String getContextPath()
+    {
+        return "/foo";
+    }
+
+}

Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/pagelevel/NoOpURLEncoder.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/pagelevel/NoOpURLEncoder.java?view=auto&rev=488165
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/pagelevel/NoOpURLEncoder.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/pagelevel/NoOpURLEncoder.java Mon Dec 18 01:13:08 2006
@@ -0,0 +1,18 @@
+package org.apache.tapestry.test.pagelevel;
+
+import org.apache.tapestry.internal.services.URLEncoder;
+
+public class NoOpURLEncoder implements URLEncoder
+{
+
+    public String encodeURL(String URL)
+    {
+        return URL;
+    }
+
+    public String encodeRedirectURL(String URL)
+    {
+        return URL;
+    }
+
+}

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=488165&r1=488164&r2=488165
==============================================================================
--- 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 01:13:08 2006
@@ -14,13 +14,27 @@
 
 package org.apache.tapestry.test.pagelevel;
 
+import static org.apache.tapestry.ioc.internal.util.CollectionFactory.newMap;
+
+import java.util.Collections;
+import java.util.Map;
+
+import org.apache.tapestry.Link;
 import org.apache.tapestry.dom.Document;
+import org.apache.tapestry.dom.Element;
 import org.apache.tapestry.internal.TapestryAppInitializer;
+import org.apache.tapestry.internal.services.ActionLinkHandler;
+import org.apache.tapestry.internal.services.ActionLinkPathSource;
+import org.apache.tapestry.internal.services.LinkImpl;
 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.PageMarkupRenderer;
-import org.apache.tapestry.internal.services.RequestPageCache;
+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;
+import org.apache.tapestry.ioc.internal.util.Defense;
 
 /**
  * This class is used to run a Tapestry app in an in-process testing environment. You can ask it to
@@ -29,34 +43,72 @@
  */
 public class PageTester
 {
-    private Registry registry;
+    private Registry _registry;
 
-    private PageMarkupRenderer renderer;
+    private PageMarkupRenderer _renderer;
 
-    private RequestPageCache cache;
+    private PageLinkHandler _pageLinkHandler;
+
+    private ActionLinkHandler _actionLinkHandler;
+
+    /**
+     * Initializes a PageTester without overriding any services.
+     * 
+     * @see #PageTester(String, String, Map)
+     */
+    @SuppressWarnings("unchecked")
+    public PageTester(String appPackage, String appName)
+    {
+        this(appPackage, appName, Collections.EMPTY_MAP);
+    }
 
     /**
      * @param appPackage
-     *            the same value you would specify using the tapestry.app-package context parameter.
+     *            The same value you would specify using the tapestry.app-package context parameter.
      *            As this testing environment is not run in a servlet container, you need to specify
      *            it.
      * @param appName
-     *            the same value you would specify as the filter name. It is used to form the name
+     *            The same value you would specify as the filter name. It is used to form the name
      *            of the module builder for your app. If you don't have one, pass an empty string.
+     * @param serviceOverrides
+     *            The mock implementation (value) for some services (key).
      */
-    public PageTester(String appPackage, String appName)
+    public PageTester(String appPackage, String appName, Map<String, Object> serviceOverrides)
     {
-        registry = new TapestryAppInitializer(appPackage, appName, "test").getRegistry();
-        renderer = registry.getService(PageMarkupRenderer.class);
-        cache = registry.getService(RequestPageCache.class);
+        _registry = new TapestryAppInitializer(appPackage, appName, "test",
+                addDefaultOverrides(serviceOverrides)).getRegistry();
+        _pageLinkHandler = _registry.getService(PageLinkHandler.class);
+        _actionLinkHandler = _registry.getService(ActionLinkHandler.class);
+        _renderer = _registry.getService(PageMarkupRenderer.class);
+    }
+
+    private Map<String, Object> addDefaultOverrides(Map<String, Object> serviceOverrides)
+    {
+        Map<String, Object> modifiedOverrides = newMap(serviceOverrides);
+        addDefaultOverride(
+                modifiedOverrides,
+                "tapestry.internal.ContextPathSource",
+                new FooContextPathSource());
+        addDefaultOverride(modifiedOverrides, "tapestry.internal.URLEncoder", new NoOpURLEncoder());
+        return modifiedOverrides;
+    }
+
+    private void addDefaultOverride(Map<String, Object> serviceOverrides, String serviceId,
+            Object overridingImpl)
+    {
+        if (!serviceOverrides.containsKey(serviceId))
+        {
+            serviceOverrides.put(serviceId, overridingImpl);
+        }
+
     }
 
     /** You should call it after use */
     public void shutdown()
     {
-        if (registry != null)
+        if (_registry != null)
         {
-            registry.shutdown();
+            _registry.shutdown();
         }
     }
 
@@ -65,13 +117,91 @@
      * 
      * @param pageName
      *            the name of the page to be rendered.
-     * @return the DOM created. Typically you to assert against it.
+     * @return the DOM created. Typically you will assert against it.
      */
     public Document renderPage(String pageName)
     {
-        Page page = cache.get(pageName);
-        MarkupWriterImpl writer = new MarkupWriterImpl();
-        renderer.renderPageMarkup(page, writer);
-        return writer.getDocument();
+        return clickPageLink(new PageLinkPathSource(null, pageName, Collections.EMPTY_LIST));
+    }
+
+    /**
+     * Simulates a click on a link.
+     * 
+     * @param link
+     *            The Link object to be "clicked" on.
+     * @return The DOM created. Typically you will assert against it.
+     */
+    public Document clickLink(Element link)
+    {
+        Defense.notNull(link, "link");
+        if (!(link.getSrc() instanceof LinkImpl))
+        {
+            throw new IllegalArgumentException("No source object is associated with the Element");
+        }
+        return clickLink((LinkImpl) link.getSrc());
     }
+
+    private Document clickLink(Link link)
+    {
+        PathSource pathSource = ((LinkImpl) link).getPathSource();
+        if (pathSource instanceof ActionLinkPathSource)
+        {
+            return clickLink(clickActionLink((ActionLinkPathSource) pathSource));
+        }
+        if (pathSource instanceof PageLinkPathSource)
+        {
+            return clickPageLink((PageLinkPathSource) pathSource);
+        }
+        throw new IllegalArgumentException("The type of the path source is not supported: "
+                + pathSource.getClass().getName());
+    }
+
+    /**
+     * Simulates a click on an action link. No redirection is performed.
+     * 
+     * @param pageSource
+     *            The path source for the action link.
+     * @return The page Link created.
+     */
+    private Link clickActionLink(ActionLinkPathSource pathSource)
+    {
+        try
+        {
+            return _actionLinkHandler.handle(pathSource);
+        }
+        finally
+        {
+            _registry.cleanupThread();
+        }
+    }
+
+    /**
+     * Simulates a click on a page link.
+     * 
+     * @param pageSource
+     *            The path source for the page link.
+     * @return The DOM created. Typically you will assert against it.
+     */
+    private Document clickPageLink(PageLinkPathSource pathSource)
+    {
+        try
+        {
+            final MarkupWriterImpl writer = new MarkupWriterImpl();
+            _pageLinkHandler.handle(pathSource, new PageRenderer()
+            {
+
+                public void renderPage(Page page)
+                {
+                    _renderer.renderPageMarkup(page, writer);
+                }
+
+            });
+            return writer.getDocument();
+        }
+        finally
+        {
+            _registry.cleanupThread();
+        }
+    }
+
 }

Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/dom/DOMTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/dom/DOMTest.java?view=diff&rev=488165&r1=488164&r2=488165
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/dom/DOMTest.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/dom/DOMTest.java Mon Dec 18 01:13:08 2006
@@ -237,4 +237,15 @@
         assertSame(e.getElementById("y"), e2);
         assertNull(e.getElementById("z"));
     }
+    
+    @Test
+    public void get_child_markup()
+    {
+        Document d = new Document();
+        Element e0 = d.newRootElement("root");
+        Element e1 = e0.element("e1");
+        e1.text("123");
+        assertEquals(e1.getChildText(), "123");
+        assertEquals(e0.getChildText(), "<e1>123</e1>");
+    }
 }

Added: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app2/pages/ResultPageForActionLink.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app2/pages/ResultPageForActionLink.java?view=auto&rev=488165
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app2/pages/ResultPageForActionLink.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app2/pages/ResultPageForActionLink.java Mon Dec 18 01:13:08 2006
@@ -0,0 +1,21 @@
+package org.apache.tapestry.integration.app2.pages;
+
+import org.apache.tapestry.annotations.ComponentClass;
+import org.apache.tapestry.annotations.OnEvent;
+
+@ComponentClass
+public class ResultPageForActionLink
+{
+    private int number;
+    
+    @OnEvent("passivate")
+    public int getNumber()
+    {
+        return number;
+    }
+    @OnEvent("activate")
+    public void setNumber(int number)
+    {
+        this.number = number;
+    }
+}

Added: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app2/pages/TestPageForActionLink.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app2/pages/TestPageForActionLink.java?view=auto&rev=488165
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app2/pages/TestPageForActionLink.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app2/pages/TestPageForActionLink.java Mon Dec 18 01:13:08 2006
@@ -0,0 +1,19 @@
+package org.apache.tapestry.integration.app2.pages;
+
+import org.apache.tapestry.annotations.ComponentClass;
+import org.apache.tapestry.annotations.InjectPage;
+import org.apache.tapestry.annotations.OnEvent;
+
+@ComponentClass
+public class TestPageForActionLink
+{
+    @InjectPage("ResultPageForActionLink")
+    private ResultPageForActionLink resultPage;
+
+    @OnEvent(component = "link1")
+    public ResultPageForActionLink onClick(int number)
+    {
+        resultPage.setNumber(number);
+        return resultPage;
+    }
+}

Added: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app2/pages/TestPageForLoop.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app2/pages/TestPageForLoop.java?view=auto&rev=488165
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app2/pages/TestPageForLoop.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app2/pages/TestPageForLoop.java Mon Dec 18 01:13:08 2006
@@ -0,0 +1,27 @@
+package org.apache.tapestry.integration.app2.pages;
+
+import org.apache.tapestry.annotations.ComponentClass;
+
+@ComponentClass
+public class TestPageForLoop
+{
+    private String[] _array =
+    { "x", "y", "z" };
+
+    private String _value;
+
+    public String[] getArray()
+    {
+        return _array;
+    }
+
+    public String getValue()
+    {
+        return _value;
+    }
+
+    public void setValue(String value)
+    {
+        this._value = value;
+    }
+}

Added: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/pagelevel/ActionLinkTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/pagelevel/ActionLinkTest.java?view=auto&rev=488165
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/pagelevel/ActionLinkTest.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/pagelevel/ActionLinkTest.java Mon Dec 18 01:13:08 2006
@@ -0,0 +1,46 @@
+// 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.integration.pagelevel;
+
+import org.apache.tapestry.dom.Document;
+import org.apache.tapestry.dom.Element;
+import org.apache.tapestry.test.pagelevel.PageTester;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+public class ActionLinkTest extends Assert
+{
+    private PageTester _tester;
+
+    @Test
+    public void click_link()
+    {
+        String appPackage = "org.apache.tapestry.integration.app2";
+        String appName = "";
+        _tester = new PageTester(appPackage, appName);
+        Document doc = _tester.renderPage("TestPageForActionLink");
+        Element link = doc.getElementById("link1");
+        doc = _tester.clickLink(link);
+        assertTrue(doc.toString().contains("You chose: 123"));
+    }
+
+    public void after()
+    {
+        if (_tester != null)
+        {
+            _tester.shutdown();
+        }
+    }
+}

Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/pagelevel/IfTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/pagelevel/IfTest.java?view=diff&rev=488165&r1=488164&r2=488165
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/pagelevel/IfTest.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/pagelevel/IfTest.java Mon Dec 18 01:13:08 2006
@@ -24,7 +24,7 @@
     private PageTester tester;
 
     @Test
-    public void testRender()
+    public void render()
     {
         String appPackage = "org.apache.tapestry.integration.app2";
         String appName = "";

Added: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/pagelevel/LoopTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/pagelevel/LoopTest.java?view=auto&rev=488165
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/pagelevel/LoopTest.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/pagelevel/LoopTest.java Mon Dec 18 01:13:08 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.integration.pagelevel;
+
+import org.apache.tapestry.dom.Document;
+import org.apache.tapestry.test.pagelevel.PageTester;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+public class LoopTest extends Assert
+{
+    private PageTester _tester;
+
+    @Test
+    public void render()
+    {
+        String appPackage = "org.apache.tapestry.integration.app2";
+        String appName = "";
+        _tester = new PageTester(appPackage, appName);
+        Document doc = _tester.renderPage("TestPageForLoop");
+        assertTrue(doc.toString().contains("abcabcabc"));
+        assertEquals(doc.getElementById("1").getChildText(), "xyz");
+    }
+
+    public void after()
+    {
+        if (_tester != null)
+        {
+            _tester.shutdown();
+        }
+    }
+}