You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tapestry.apache.org by hl...@apache.org on 2008/03/04 19:52:34 UTC

svn commit: r633583 - in /tapestry/tapestry5/trunk/tapestry-core/src: main/java/org/apache/tapestry/dom/ main/java/org/apache/tapestry/internal/ main/java/org/apache/tapestry/internal/services/ test/app3/ test/java/org/apache/tapestry/integration/ test...

Author: hlship
Date: Tue Mar  4 10:52:30 2008
New Revision: 633583

URL: http://svn.apache.org/viewvc?rev=633583&view=rev
Log:
TAPESTRY-2226: Requests for the root index page that include a page activation context fail with a 404 error

Added:
    tapestry/tapestry5/trunk/tapestry-core/src/test/app3/Index.tml
      - copied, changed from r633150, tapestry/tapestry5/trunk/tapestry-core/src/test/app3/Start.tml
    tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/integration/AdditionalIntegrationTests.java
      - copied, changed from r633150, tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/integration/RootPathRedirectTest.java
Removed:
    tapestry/tapestry5/trunk/tapestry-core/src/test/app3/Start.tml
    tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/integration/RootPathRedirectTest.java
Modified:
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/dom/Element.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/TapestryInternalUtils.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/ComponentEventDispatcher.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/PageRenderDispatcher.java
    tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/integration/app3/pages/Index.java
    tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/services/PageRenderDispatcherTest.java

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/dom/Element.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/dom/Element.java?rev=633583&r1=633582&r2=633583&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/dom/Element.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/dom/Element.java Tue Mar  4 10:52:30 2008
@@ -1,4 +1,4 @@
-// Copyright 2006, 2007 The Apache Software Foundation
+// Copyright 2006, 2007, 2008 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.
@@ -14,6 +14,7 @@
 
 package org.apache.tapestry.dom;
 
+import org.apache.tapestry.internal.TapestryInternalUtils;
 import org.apache.tapestry.ioc.internal.util.CollectionFactory;
 import static org.apache.tapestry.ioc.internal.util.CollectionFactory.newLinkedList;
 import static org.apache.tapestry.ioc.internal.util.CollectionFactory.newMap;
@@ -417,7 +418,7 @@
 
         Element search = this;
 
-        for (String name : path.split("/"))
+        for (String name : TapestryInternalUtils.splitPath(path))
         {
             search = search.findChildWithElementName(name);
 

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/TapestryInternalUtils.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/TapestryInternalUtils.java?rev=633583&r1=633582&r2=633583&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/TapestryInternalUtils.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/TapestryInternalUtils.java Tue Mar  4 10:52:30 2008
@@ -570,4 +570,12 @@
         return left.equals(right);
     }
 
+
+    /**
+     * Splits a path at each slash.
+     */
+    public static String[] splitPath(String path)
+    {
+        return SLASH_PATTERN.split(path);
+    }
 }

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/ComponentEventDispatcher.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/ComponentEventDispatcher.java?rev=633583&r1=633582&r2=633583&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/ComponentEventDispatcher.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/ComponentEventDispatcher.java Tue Mar  4 10:52:30 2008
@@ -91,10 +91,6 @@
     private static final int EVENT_NAME = 9;
     private static final int CONTEXT = 11;
 
-    // Used to split a context into individual chunks.
-
-    private final Pattern SLASH_PATTERN = Pattern.compile("/");
-
     public boolean dispatch(Request request, Response response) throws IOException
     {
         Matcher matcher = PATH_PATTERN.matcher(request.getPath());
@@ -117,7 +113,7 @@
         // (TAPESTRY-1605)
 
         _requestEncodingInitializer.initializeRequestEncoding(activePageName);
-        
+
         EventContext activationContext = decodeContext(request.getParameter(InternalConstants.PAGE_CONTEXT_NAME));
 
         // The event type is often omitted, and defaults to "action".
@@ -146,7 +142,7 @@
     {
         if (input == null) return _emptyContext;
 
-        String[] values = SLASH_PATTERN.split(input);
+        String[] values = TapestryInternalUtils.splitPath(input);
 
         for (int i = 0; i < values.length; i++)
         {

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/PageRenderDispatcher.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/PageRenderDispatcher.java?rev=633583&r1=633582&r2=633583&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/PageRenderDispatcher.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/PageRenderDispatcher.java Tue Mar  4 10:52:30 2008
@@ -44,41 +44,53 @@
 
     public boolean dispatch(Request request, final Response response) throws IOException
     {
-        // Rememeber that the path starts with a leading slash that is not part of the logical page
-        // name.
+
+        // The extended name may include a page activation context. The trick is
+        // to figure out where the logical page name stops and where the
+        // activation context begins. Further, strip out the leading slash.
 
         String path = request.getPath();
 
-        // TAPESTRY-1343: This can happen in Tomcat (but not in Jetty) for URL such as
-        // http://.../context (with no trailing slash).
-        if (path.equals("")) return false;
+        // TAPESTRY-1343: Sometimes path is the empty string (it should always be at least a slash,
+        // but Tomcat may return the empty string for a root context request).
+
+        String extendedName = path.length() == 0 ? path : path.substring(1);
 
-        int nextslashx = path.length();
-        String pageName;
+        // Ignore trailing slashes in the path.
+        while (extendedName.endsWith("/"))
+            extendedName = extendedName.substring(0, extendedName.length() - 1);
+
+        int slashx = extendedName.length();
         boolean atEnd = true;
 
-        while (true)
+        while (slashx > 0)
         {
-            // TAPESTRY-2150: Look for the longest match, for situations where
-            // you have some overlap between a class name and a package name.
 
-            pageName = path.substring(1, nextslashx);
+            String pageName = extendedName.substring(0, slashx);
+            String pageActivationContext = atEnd ? "" :
+                                           extendedName.substring(slashx + 1);
 
-            if (!pageName.endsWith("/") && _componentClassResolver.isPageName(pageName)) break;
+            if (process(pageName, pageActivationContext)) return true;
 
-            nextslashx = path.lastIndexOf('/', nextslashx - 1);
+            // Work backwards, splitting at the next slash.
+            slashx = extendedName.lastIndexOf('/', slashx - 1);
 
             atEnd = false;
-
-            if (nextslashx <= 1) return false;
         }
 
+        // OK, maybe its all page activation context for the root Index page.
+
+        return process("", extendedName);
+    }
+
+    private boolean process(String pageName, String pageActivationContext) throws IOException
+    {
+        if (!_componentClassResolver.isPageName(pageName)) return false;
 
-        String[] context = atEnd ? new String[0] : convertActivationContext(path
-                .substring(nextslashx + 1));
+        String[] values = convertActivationContext(pageActivationContext);
 
         EventContext activationContext
-                = new URLEventContext(_contextValueEncoder, context);
+                = new URLEventContext(_contextValueEncoder, values);
 
         PageRenderRequestParameters parameters = new PageRenderRequestParameters(pageName, activationContext);
 
@@ -92,14 +104,12 @@
      * activation context) into an array of strings. LinkFactory and friends URL encode each value, so we URL decode the
      * value (we assume that page names are "URL safe").
      *
-     * @param extraPath
-     * @return
      */
     private String[] convertActivationContext(String extraPath)
     {
         if (extraPath.length() == 0) return new String[0];
 
-        String[] context = extraPath.split("/");
+        String[] context = TapestryInternalUtils.splitPath(extraPath);
 
         for (int i = 0; i < context.length; i++)
         {

Copied: tapestry/tapestry5/trunk/tapestry-core/src/test/app3/Index.tml (from r633150, tapestry/tapestry5/trunk/tapestry-core/src/test/app3/Start.tml)
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/app3/Index.tml?p2=tapestry/tapestry5/trunk/tapestry-core/src/test/app3/Index.tml&p1=tapestry/tapestry5/trunk/tapestry-core/src/test/app3/Start.tml&r1=633150&r2=633583&rev=633583&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/app3/Start.tml (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/app3/Index.tml Tue Mar  4 10:52:30 2008
@@ -1,12 +1,13 @@
 <html>
     <head>
-        <title>Start</title>
+        <title>Index</title>
     </head>
     <body>
-        <h1>Start page</h1>
+        <h1>Index</h1>
 
         <p>
-            The Start page should not be visible, because of the onActivate() event handler method.
+            Message:
+            <span id="message">${message}</span>
         </p>
     </body>
 </html>

Copied: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/integration/AdditionalIntegrationTests.java (from r633150, tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/integration/RootPathRedirectTest.java)
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/integration/AdditionalIntegrationTests.java?p2=tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/integration/AdditionalIntegrationTests.java&p1=tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/integration/RootPathRedirectTest.java&r1=633150&r2=633583&rev=633583&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/integration/RootPathRedirectTest.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/integration/AdditionalIntegrationTests.java Tue Mar  4 10:52:30 2008
@@ -17,11 +17,14 @@
 import org.apache.tapestry.test.AbstractIntegrationTestSuite;
 import org.testng.annotations.Test;
 
+/**
+ * Additional integration tests that do not fit with the main group due to the need for special configuration.
+ */
 @Test(timeOut = 50000, sequential = true, groups = { "integration" })
-public class RootPathRedirectTest extends AbstractIntegrationTestSuite
+public class AdditionalIntegrationTests extends AbstractIntegrationTestSuite
 {
 
-    public RootPathRedirectTest()
+    public AdditionalIntegrationTests()
     {
         super("src/test/app3");
     }
@@ -48,4 +51,18 @@
         assertText("//div[@class='t-beandisplay-value no']", "Nay");
         assertText("//div[@class='t-beandisplay-value yes']", "Yea");
     }
+
+    /**
+     * TAPESTRY-2226
+     */
+    @Test
+    public void activation_context_for_root_index_page()
+    {
+        open(BASE_URL + "it worked");
+
+        assertText("//h1", "Index");
+
+        assertText("message", "it worked");
+    }
+
 }

Modified: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/integration/app3/pages/Index.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/integration/app3/pages/Index.java?rev=633583&r1=633582&r2=633583&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/integration/app3/pages/Index.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/integration/app3/pages/Index.java Tue Mar  4 10:52:30 2008
@@ -14,15 +14,31 @@
 
 package org.apache.tapestry.integration.app3.pages;
 
+import org.apache.tapestry.annotations.GenerateAccessors;
 import org.apache.tapestry.annotations.InjectPage;
+import org.apache.tapestry.annotations.Persist;
 
 public class Index
 {
     @InjectPage
     private Login _login;
 
+    @Persist
+    @GenerateAccessors
+    private String _message;
+
+    boolean onActivate(String message)
+    {
+        _message = message;
+
+        // Terminate the event before it gets to the no-args onActivate().
+
+        return true;
+    }
+
     Object onActivate()
     {
+
         // Perform a redirect to the login page.
         return _login;
     }

Modified: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/services/PageRenderDispatcherTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/services/PageRenderDispatcherTest.java?rev=633583&r1=633582&r2=633583&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/services/PageRenderDispatcherTest.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/services/PageRenderDispatcherTest.java Tue Mar  4 10:52:30 2008
@@ -71,6 +71,8 @@
 
         train_getPath(request, "");
 
+        train_isPageName(resolver, "", false);
+
         replay();
 
         Dispatcher d = new PageRenderDispatcher(resolver, handler, null);
@@ -79,6 +81,47 @@
 
         verify();
     }
+
+    /**
+     * TAPESTRY-2226
+     */
+    @Test
+    public void page_activation_context_for_root_index_page() throws Exception
+    {
+        ComponentClassResolver resolver = mockComponentClassResolver();
+        Request request = mockRequest();
+        Response response = mockResponse();
+        Page page = mockPage();
+        ComponentPageElement rootElement = mockComponentPageElement();
+        PageResponseRenderer renderer = mockPageResponseRenderer();
+        RequestPageCache cache = mockRequestPageCache();
+        ComponentEventResultProcessor processor = newComponentEventResultProcessor();
+
+        train_getPath(request, "/foo/bar");
+
+        train_isPageName(resolver, "foo/bar", false);
+        train_isPageName(resolver, "foo", false);
+        train_isPageName(resolver, "", true);
+
+        train_get(cache, "", page);
+
+        train_getRootElement(page, rootElement);
+
+        train_triggerContextEvent(rootElement, TapestryConstants.ACTIVATE_EVENT, new Object[] { "foo", "bar" }, false);
+
+        renderer.renderPageResponse(page);
+
+        replay();
+
+        PageRenderRequestHandler handler = new PageRenderRequestHandlerImpl(cache, processor, renderer);
+
+        Dispatcher d = new PageRenderDispatcher(resolver, handler, _contextValueEncoder);
+
+        assertTrue(d.dispatch(request, response));
+
+        verify();
+    }
+
 
     @Test
     public void no_extra_context_without_final_slash() throws Exception