You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tapestry.apache.org by hl...@apache.org on 2012/07/05 18:55:32 UTC

[1/2] git commit: TAP5-1965: Replace use of Request.getContextPath() with a symbol define at application startup

Updated Branches:
  refs/heads/5.4-js-rewrite 95bc7c6b4 -> 4cd5be6b3


TAP5-1965: Replace use of Request.getContextPath() with a symbol define at application startup


Project: http://git-wip-us.apache.org/repos/asf/tapestry-5/repo
Commit: http://git-wip-us.apache.org/repos/asf/tapestry-5/commit/4cd5be6b
Tree: http://git-wip-us.apache.org/repos/asf/tapestry-5/tree/4cd5be6b
Diff: http://git-wip-us.apache.org/repos/asf/tapestry-5/diff/4cd5be6b

Branch: refs/heads/5.4-js-rewrite
Commit: 4cd5be6b38f34f579bb71ed09b127651ad8a4e20
Parents: 8876a2a
Author: Howard M. Lewis Ship <hl...@apache.org>
Authored: Thu Jul 5 09:55:18 2012 -0700
Committer: Howard M. Lewis Ship <hl...@apache.org>
Committed: Thu Jul 5 09:55:18 2012 -0700

----------------------------------------------------------------------
 54_RELEASE_NOTES.txt                               |   10 ++
 .../java/org/apache/tapestry5/SymbolConstants.java |   12 ++-
 .../java/org/apache/tapestry5/TapestryFilter.java  |   27 ++---
 .../tapestry5/internal/TapestryAppInitializer.java |   67 ++++++------
 .../internal/renderers/RequestRenderer.java        |   68 +++++++++---
 .../internal/services/AssetDispatcher.java         |   10 ++-
 .../services/ComponentEventLinkEncoderImpl.java    |   22 +++--
 .../tapestry5/internal/services/CookiesImpl.java   |   19 +++-
 .../services/assets/AssetPathConstructorImpl.java  |   19 +++-
 .../internal/test/TestableRequestImpl.java         |    9 +-
 .../internal/util/DelegatingSymbolProvider.java    |   46 ++++++++
 .../org/apache/tapestry5/services/Request.java     |   20 +++-
 .../apache/tapestry5/services/TapestryModule.java  |    3 +-
 .../java/org/apache/tapestry5/test/PageTester.java |   81 +++++++++------
 .../app1/TapestryJavaScriptTests.groovy            |   20 ----
 .../assets/AssetPathConstructorImplTest.groovy     |   23 ++---
 .../ClasspathAssetAliasManagerImplTest.java        |    6 +-
 .../services/ComponentEventDispatcherTest.java     |   22 ++--
 .../ComponentEventLinkEncoderImplTest.java         |   36 +++----
 .../internal/services/ContextAssetFactoryTest.java |   45 ++++-----
 .../internal/services/CookiesImplTest.java         |    6 +-
 .../internal/test/InternalBaseTestCase.java        |    7 +-
 22 files changed, 339 insertions(+), 239 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4cd5be6b/54_RELEASE_NOTES.txt
----------------------------------------------------------------------
diff --git a/54_RELEASE_NOTES.txt b/54_RELEASE_NOTES.txt
new file mode 100644
index 0000000..ce9a8ad
--- /dev/null
+++ b/54_RELEASE_NOTES.txt
@@ -0,0 +1,10 @@
+Scratch pad for changes destined for the 5.4 release notes page.
+
+Breaking Features:
+
+The definition of the symbol 'tapestry.asset-path-prefix' has changed; it no longer includes the leading and
+trailing slashes. The default in 5.3 was "/assets/", in 5.4 it is simply "assets".
+
+Bugs fixed (in 5.4-js-rewrite branch):
+
+TAP5-1965: Replace use of Request.getContextPath() with a symbol define at application startup

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4cd5be6b/tapestry-core/src/main/java/org/apache/tapestry5/SymbolConstants.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/SymbolConstants.java b/tapestry-core/src/main/java/org/apache/tapestry5/SymbolConstants.java
index cd1d552..d6517b4 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/SymbolConstants.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/SymbolConstants.java
@@ -353,7 +353,10 @@ public class SymbolConstants
     public static final String ASSET_URL_FULL_QUALIFIED = "tapestry.asset-url-fully-qualified";
 
     /**
-     * Prefix to be used for all asset paths
+     * Prefix to be used for all asset paths, used to recognize which requests are for assets. This value
+     * is appended to the context path and the (optional {@linkplain #APPLICATION_FOLDER application folder}.
+     * Its default is "assets".  It may contain slashes, but should not begin or end with one.
+     *
      */
     public static final String ASSET_PATH_PREFIX = "tapestry.asset-path-prefix";
 
@@ -364,4 +367,11 @@ public class SymbolConstants
      * @since 5.4
      */
     public static final String REQUIRE_JS = "tapestry.requirejs";
+
+    /**
+     * Identifies the context path of the application, as determined from {@link javax.servlet.ServletContext#getContextPath()}.
+     *
+     * @since 5.4
+     */
+    public static final String CONTEXT_PATH = "tapestry.context-path";
 }

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4cd5be6b/tapestry-core/src/main/java/org/apache/tapestry5/TapestryFilter.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/TapestryFilter.java b/tapestry-core/src/main/java/org/apache/tapestry5/TapestryFilter.java
index ec42565..eab839d 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/TapestryFilter.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/TapestryFilter.java
@@ -1,4 +1,4 @@
-// Copyright 2006, 2007, 2008, 2009, 2010, 2011 The Apache Software Foundation
+// Copyright 2006, 2007, 2008, 2009, 2010, 2011, 2012 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.
@@ -15,10 +15,11 @@
 package org.apache.tapestry5;
 
 import org.apache.tapestry5.internal.ServletContextSymbolProvider;
+import org.apache.tapestry5.internal.SingleKeySymbolProvider;
 import org.apache.tapestry5.internal.TapestryAppInitializer;
+import org.apache.tapestry5.internal.util.DelegatingSymbolProvider;
 import org.apache.tapestry5.ioc.Registry;
 import org.apache.tapestry5.ioc.def.ModuleDef;
-import org.apache.tapestry5.ioc.internal.services.SystemPropertiesSymbolProvider;
 import org.apache.tapestry5.ioc.services.SymbolProvider;
 import org.apache.tapestry5.services.HttpServletRequestHandler;
 import org.apache.tapestry5.services.ServletApplicationInitializer;
@@ -84,23 +85,14 @@ public class TapestryFilter implements Filter
 
         String filterName = config.getFilterName();
 
-        SymbolProvider provider = new SymbolProvider()
-        {
-            SymbolProvider contextProvider = new ServletContextSymbolProvider(context);
-            SymbolProvider systemProvider = new SystemPropertiesSymbolProvider();
-
-            public String valueForSymbol(String symbolName)
-            {
-                String contextValue = contextProvider.valueForSymbol(symbolName);
-                if (contextValue != null) return contextValue;
+        SymbolProvider contextProvider = new ServletContextSymbolProvider(context);
+        SymbolProvider contextPathProvider = new SingleKeySymbolProvider(SymbolConstants.CONTEXT_PATH, context.getContextPath());
 
-                return systemProvider.valueForSymbol(symbolName);
-            }
-        };
+        SymbolProvider combinedProvider = new DelegatingSymbolProvider(contextPathProvider, contextProvider);
 
         String executionMode = System.getProperty(SymbolConstants.EXECUTION_MODE, "production");
 
-        TapestryAppInitializer appInitializer = new TapestryAppInitializer(logger, provider,
+        TapestryAppInitializer appInitializer = new TapestryAppInitializer(logger, combinedProvider,
                 filterName, executionMode);
 
         appInitializer.addModules(provideExtraModuleDefs(context));
@@ -113,7 +105,7 @@ public class TapestryFilter implements Filter
         ServletApplicationInitializer ai = registry.getService("ServletApplicationInitializer",
                 ServletApplicationInitializer.class);
 
-        ai.initializeApplication(filterConfig.getServletContext());
+        ai.initializeApplication(context);
 
         registry.performRegistryStartup();
 
@@ -134,7 +126,8 @@ public class TapestryFilter implements Filter
      * additional
      * initialization to occur. This implementation does nothing, and my be overriden in subclasses.
      *
-     * @param registry from which services may be extracted
+     * @param registry
+     *         from which services may be extracted
      * @throws ServletException
      */
     protected void init(Registry registry) throws ServletException

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4cd5be6b/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryAppInitializer.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryAppInitializer.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryAppInitializer.java
index 47504ef..c721754 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryAppInitializer.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryAppInitializer.java
@@ -1,4 +1,4 @@
-// Copyright 2006, 2007, 2008, 2009, 2010, 2011 The Apache Software Foundation
+// Copyright 2006, 2007, 2008, 2009, 2010, 2011, 2012 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.
@@ -56,22 +56,12 @@ public class TapestryAppInitializer
     private Registry registry;
 
     /**
-     * @param logger     logger for output confirmation
-     * @param appPackage root package name to search for pages and components
-     * @param appName    the name of the application (i.e., the name of the application servlet)
-     * @param aliasMode  ignored (was used in 5.2)
-     * @deprecated Use {@link #TapestryAppInitializer(Logger, String, String)} instead. To be removed
-     *             in 5.4.
-     */
-    public TapestryAppInitializer(Logger logger, String appPackage, String appName, String aliasMode)
-    {
-        this(logger, appPackage, appName);
-    }
-
-    /**
-     * @param logger     logger for output confirmation
-     * @param appPackage root package name to search for pages and components
-     * @param appName    the name of the application (i.e., the name of the application servlet)
+     * @param logger
+     *         logger for output confirmation
+     * @param appPackage
+     *         root package name to search for pages and components
+     * @param appName
+     *         the name of the application (i.e., the name of the application servlet)
      */
     public TapestryAppInitializer(Logger logger, String appPackage, String appName)
     {
@@ -80,15 +70,20 @@ public class TapestryAppInitializer
     }
 
     /**
-     * @param logger         logger for output confirmation
-     * @param appProvider    provides symbols for the application (normally, from the ServletContext init
-     *                       parameters)
-     * @param appName        the name of the application (i.e., the name of the application servlet)
-     * @param aliasMode      ignored (was used in 5.2 and earlier)
-     * @param executionModes an optional, comma-separated list of execution modes, each of which is used
-     *                       to find a list of additional module classes to load (key
-     *                       <code>tapestry.<em>name</em>-modules</code> in appProvider, i.e., the servlet
-     *                       context)
+     * @param logger
+     *         logger for output confirmation
+     * @param appProvider
+     *         provides symbols for the application (normally, from the ServletContext init
+     *         parameters)
+     * @param appName
+     *         the name of the application (i.e., the name of the application servlet)
+     * @param aliasMode
+     *         ignored (was used in 5.2 and earlier)
+     * @param executionModes
+     *         an optional, comma-separated list of execution modes, each of which is used
+     *         to find a list of additional module classes to load (key
+     *         <code>tapestry.<em>name</em>-modules</code> in appProvider, i.e., the servlet
+     *         context)
      * @deprecated Use {@link #TapestryAppInitializer(Logger, SymbolProvider, String, String)} instead.
      *             To be removed in 5.4.
      */
@@ -99,14 +94,18 @@ public class TapestryAppInitializer
     }
 
     /**
-     * @param logger         logger for output confirmation
-     * @param appProvider    provides symbols for the application (normally, from the ServletContext init
-     *                       parameters)
-     * @param appName        the name of the application (i.e., the name of the application servlet)
-     * @param executionModes an optional, comma-separated list of execution modes, each of which is used
-     *                       to find a list of additional module classes to load (key
-     *                       <code>tapestry.<em>name</em>-modules</code> in appProvider, i.e., the servlet
-     *                       context)
+     * @param logger
+     *         logger for output confirmation
+     * @param appProvider
+     *         provides symbols for the application (normally, from the ServletContext init
+     *         parameters), plus (as of 5.4) the value for symbol {@link SymbolConstants#CONTEXT_PATH}
+     * @param appName
+     *         the name of the application (i.e., the name of the application servlet)
+     * @param executionModes
+     *         an optional, comma-separated list of execution modes, each of which is used
+     *         to find a list of additional module classes to load (key
+     *         <code>tapestry.<em>name</em>-modules</code> in appProvider, i.e., the servlet
+     *         context)
      */
     public TapestryAppInitializer(Logger logger, SymbolProvider appProvider, String appName, String executionModes)
     {

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4cd5be6b/tapestry-core/src/main/java/org/apache/tapestry5/internal/renderers/RequestRenderer.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/renderers/RequestRenderer.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/renderers/RequestRenderer.java
index e4022a0..a50920b 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/renderers/RequestRenderer.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/renderers/RequestRenderer.java
@@ -1,4 +1,4 @@
-// Copyright 2007, 2008 The Apache Software Foundation
+// Copyright 2007, 2008, 2012 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.
@@ -15,8 +15,12 @@
 package org.apache.tapestry5.internal.renderers;
 
 import org.apache.tapestry5.MarkupWriter;
+import org.apache.tapestry5.SymbolConstants;
 import org.apache.tapestry5.internal.InternalConstants;
 import org.apache.tapestry5.ioc.annotations.Primary;
+import org.apache.tapestry5.ioc.annotations.Symbol;
+import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
+import org.apache.tapestry5.ioc.internal.util.InternalUtils;
 import org.apache.tapestry5.services.Context;
 import org.apache.tapestry5.services.ObjectRenderer;
 import org.apache.tapestry5.services.Request;
@@ -27,12 +31,15 @@ public class RequestRenderer implements ObjectRenderer<Request>
 {
     private final Context context;
 
+    private final String contextPath;
+
     private final ObjectRenderer masterObjectRenderer;
 
-    public RequestRenderer(@Primary ObjectRenderer masterObjectRenderer, Context context)
+    public RequestRenderer(@Primary ObjectRenderer masterObjectRenderer, Context context, @Symbol(SymbolConstants.CONTEXT_PATH) String contextPath)
     {
         this.masterObjectRenderer = masterObjectRenderer;
         this.context = context;
+        this.contextPath = contextPath;
     }
 
     public void render(Request request, MarkupWriter writer)
@@ -43,31 +50,55 @@ public class RequestRenderer implements ObjectRenderer<Request>
 
         writer.element("dd");
 
-        String contextPath = request.getContextPath();
-
         if (contextPath.equals(""))
         {
             writer.element("em");
             writer.write("none (deployed as root)");
             writer.end();
-        }
-        else
+        } else
         {
             writer.write(contextPath);
         }
+
         writer.end(); // dd
 
-        dt(writer, "Request Path");
-        dd(writer, request.getPath());
+        dt(writer, "Path", request.getPath());
 
-        dt(writer, "Locale");
-        dd(writer, request.getLocale().toString());
+        dt(writer, "Locale", request.getLocale().toString());
 
-        dt(writer, "Secure");
-        dd(writer, Boolean.toString(request.isSecure()));
+        dt(writer, "Server Name", request.getServerName());
 
-        dt(writer, "Server Name");
-        dd(writer, request.getServerName());
+
+        List<String> flags = CollectionFactory.newList();
+        if (request.isSecure())
+        {
+            flags.add("secure");
+        }
+
+        if (request.isXHR())
+        {
+            flags.add("xhr");
+        }
+
+        if (request.isRequestedSessionIdValid())
+        {
+            flags.add("requested session id valid");
+        }
+
+        if (request.isSessionInvalidated())
+        {
+            flags.add("session invalidated");
+        }
+
+        if (!flags.isEmpty())
+        {
+            dt(writer, "flags", InternalUtils.join(flags));
+        }
+
+        dt(writer, "Ports (local/server)",
+                String.format("%d / %d", request.getLocalPort(), request.getServerPort()));
+
+        dt(writer, "Method", request.getMethod());
 
         writer.end();
 
@@ -131,8 +162,7 @@ public class RequestRenderer implements ObjectRenderer<Request>
                 }
 
                 writer.end(); // ul
-            }
-            else
+            } else
             {
                 writer.write(values[0]);
             }
@@ -143,6 +173,12 @@ public class RequestRenderer implements ObjectRenderer<Request>
         writer.end(); // dl
     }
 
+    private void dt(MarkupWriter writer, String name, String value)
+    {
+        dt(writer, name);
+        dd(writer, value);
+    }
+
     private void dt(MarkupWriter writer, String name)
     {
         writer.element("dt");

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4cd5be6b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/AssetDispatcher.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/AssetDispatcher.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/AssetDispatcher.java
index 2d2f00c..fe33e2b 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/AssetDispatcher.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/AssetDispatcher.java
@@ -68,9 +68,15 @@ public class AssetDispatcher implements Dispatcher
                            @Symbol(SymbolConstants.ASSET_PATH_PREFIX)
                            String assetPathPrefix)
     {
-        String folder = applicationFolder.equals("") ? "" : "/" + applicationFolder;
+        StringBuilder pathPrefix = new StringBuilder("/");
 
-        this.pathPrefix = folder + assetPathPrefix + applicationVersion + "/";
+        if (! applicationFolder.equals("")) {
+            pathPrefix.append(applicationFolder).append("/");
+        }
+
+        pathPrefix.append(assetPathPrefix).append("/").append(applicationVersion).append("/");
+
+        this.pathPrefix = pathPrefix.toString();
 
         for (String path : configuration.keySet())
         {

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4cd5be6b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ComponentEventLinkEncoderImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ComponentEventLinkEncoderImpl.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ComponentEventLinkEncoderImpl.java
index c3c853b..53f3769 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ComponentEventLinkEncoderImpl.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ComponentEventLinkEncoderImpl.java
@@ -34,8 +34,6 @@ public class ComponentEventLinkEncoderImpl implements ComponentEventLinkEncoder
 
     private final LocalizationSetter localizationSetter;
 
-    private final Request request;
-
     private final Response response;
 
     private final RequestSecurityManager requestSecurityManager;
@@ -50,6 +48,8 @@ public class ComponentEventLinkEncoderImpl implements ComponentEventLinkEncoder
 
     private final ClientWhitelist clientWhitelist;
 
+    private final String contextPath;
+
     private final String applicationFolder;
 
     private final String applicationFolderPrefix;
@@ -59,20 +59,26 @@ public class ComponentEventLinkEncoderImpl implements ComponentEventLinkEncoder
     private static final char SLASH = '/';
 
     public ComponentEventLinkEncoderImpl(ComponentClassResolver componentClassResolver,
-                                         ContextPathEncoder contextPathEncoder, LocalizationSetter localizationSetter, Request request,
+                                         ContextPathEncoder contextPathEncoder, LocalizationSetter localizationSetter,
                                          Response response, RequestSecurityManager requestSecurityManager, BaseURLSource baseURLSource,
-                                         PersistentLocale persistentLocale, @Symbol(SymbolConstants.ENCODE_LOCALE_INTO_PATH)
-    boolean encodeLocaleIntoPath, @Symbol(SymbolConstants.APPLICATION_FOLDER) String applicationFolder, MetaDataLocator metaDataLocator, ClientWhitelist clientWhitelist)
+                                         PersistentLocale persistentLocale,
+                                         @Symbol(SymbolConstants.ENCODE_LOCALE_INTO_PATH)
+                                         boolean encodeLocaleIntoPath,
+                                         @Symbol(SymbolConstants.CONTEXT_PATH)
+                                         String contextPath,
+                                         @Symbol(SymbolConstants.APPLICATION_FOLDER) String applicationFolder,
+                                         MetaDataLocator metaDataLocator,
+                                         ClientWhitelist clientWhitelist)
     {
         this.componentClassResolver = componentClassResolver;
         this.contextPathEncoder = contextPathEncoder;
         this.localizationSetter = localizationSetter;
-        this.request = request;
         this.response = response;
         this.requestSecurityManager = requestSecurityManager;
         this.baseURLSource = baseURLSource;
         this.persistentLocale = persistentLocale;
         this.encodeLocaleIntoPath = encodeLocaleIntoPath;
+        this.contextPath = contextPath;
         this.applicationFolder = applicationFolder;
         this.metaDataLocator = metaDataLocator;
         this.clientWhitelist = clientWhitelist;
@@ -90,7 +96,7 @@ public class ComponentEventLinkEncoderImpl implements ComponentEventLinkEncoder
 
         String activePageName = parameters.getLogicalPageName();
 
-        builder.append(request.getContextPath());
+        builder.append(contextPath);
 
         encodeAppFolderAndLocale(builder);
 
@@ -158,7 +164,7 @@ public class ComponentEventLinkEncoderImpl implements ComponentEventLinkEncoder
         String nestedComponentId = parameters.getNestedComponentId();
         boolean hasComponentId = InternalUtils.isNonBlank(nestedComponentId);
 
-        builder.append(request.getContextPath());
+        builder.append(contextPath);
 
         encodeAppFolderAndLocale(builder);
 

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4cd5be6b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/CookiesImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/CookiesImpl.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/CookiesImpl.java
index 3c88006..ea31c45 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/CookiesImpl.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/CookiesImpl.java
@@ -1,4 +1,4 @@
-// Copyright 2007, 2008 The Apache Software Foundation
+// Copyright 2007, 2008, 2012 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.tapestry5.internal.services;
 
+import org.apache.tapestry5.SymbolConstants;
 import org.apache.tapestry5.ioc.annotations.IntermediateType;
 import org.apache.tapestry5.ioc.annotations.Symbol;
 import org.apache.tapestry5.ioc.util.TimeInterval;
@@ -33,13 +34,17 @@ public class CookiesImpl implements Cookies
 
     private final CookieSink cookieSink;
 
+    private final String defaultCookiePath;
+
     private final int defaultMaxAge;
 
     /**
      * @param request
      * @param cookieSource
      * @param cookieSink
-     * @param defaultMaxAge default cookie expiration time in milliseconds
+     * @param contextPath
+     * @param defaultMaxAge
+     *         default cookie expiration time in milliseconds
      */
     public CookiesImpl(Request request,
 
@@ -47,12 +52,16 @@ public class CookiesImpl implements Cookies
 
                        CookieSink cookieSink,
 
+                       @Symbol(SymbolConstants.CONTEXT_PATH)
+                       String contextPath,
+
                        @Symbol("tapestry.default-cookie-max-age") @IntermediateType(TimeInterval.class)
                        long defaultMaxAge)
     {
         this.request = request;
         this.cookieSource = cookieSource;
         this.cookieSink = cookieSink;
+        this.defaultCookiePath = contextPath + "/";
         this.defaultMaxAge = (int) (defaultMaxAge / 1000l);
     }
 
@@ -78,7 +87,7 @@ public class CookiesImpl implements Cookies
     public void writeCookieValue(String name, String value, int maxAge)
     {
         Cookie cookie = new Cookie(name, value);
-        cookie.setPath(request.getContextPath() + "/");
+        cookie.setPath(defaultCookiePath);
         cookie.setMaxAge(maxAge);
         cookie.setSecure(request.isSecure());
 
@@ -103,7 +112,7 @@ public class CookiesImpl implements Cookies
     public void writeDomainCookieValue(String name, String value, String domain, int maxAge)
     {
         Cookie cookie = new Cookie(name, value);
-        cookie.setPath(request.getContextPath() + "/");
+        cookie.setPath(defaultCookiePath);
         cookie.setDomain(domain);
         cookie.setMaxAge(maxAge);
         cookie.setSecure(request.isSecure());
@@ -125,7 +134,7 @@ public class CookiesImpl implements Cookies
     public void removeCookieValue(String name)
     {
         Cookie cookie = new Cookie(name, null);
-        cookie.setPath(request.getContextPath() + "/");
+        cookie.setPath(defaultCookiePath);
         cookie.setMaxAge(0);
         cookie.setSecure(request.isSecure());
 

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4cd5be6b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/assets/AssetPathConstructorImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/assets/AssetPathConstructorImpl.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/assets/AssetPathConstructorImpl.java
index 66f34a3..3d81b8f 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/assets/AssetPathConstructorImpl.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/assets/AssetPathConstructorImpl.java
@@ -1,4 +1,4 @@
-// Copyright 2010, 2011 The Apache Software Foundation
+// Copyright 2010, 2011, 2012 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.
@@ -34,6 +34,9 @@ public class AssetPathConstructorImpl implements AssetPathConstructor
     public AssetPathConstructorImpl(Request request,
                                     BaseURLSource baseURLSource,
 
+                                    @Symbol(SymbolConstants.CONTEXT_PATH)
+                                    String contextPath,
+
                                     @Symbol(SymbolConstants.APPLICATION_VERSION)
                                     String applicationVersion,
 
@@ -51,9 +54,18 @@ public class AssetPathConstructorImpl implements AssetPathConstructor
 
         this.fullyQualified = fullyQualified;
 
-        String folder = applicationFolder.equals("") ? "" : "/" + applicationFolder;
+        StringBuilder prefix = new StringBuilder("/");
+
+        // Either blank, or ending in a slash:
+        prefix.append(contextPath);
+
+        if (!applicationFolder.equals("")) {
+            prefix.append(applicationFolder).append("/");
+        }
+
+        prefix.append(assetPathPrefix).append("/").append(applicationVersion).append("/");
 
-        this.prefix = folder + assetPathPrefix + applicationVersion + "/";
+        this.prefix = prefix.toString();
     }
 
     public String constructAssetPath(String virtualFolder, String path)
@@ -68,7 +80,6 @@ public class AssetPathConstructorImpl implements AssetPathConstructor
             builder.append(baseURLSource.getBaseURL(request.isSecure()));
         }
 
-        builder.append(request.getContextPath());
         builder.append(prefix);
         builder.append(virtualFolder);
 

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4cd5be6b/tapestry-core/src/main/java/org/apache/tapestry5/internal/test/TestableRequestImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/test/TestableRequestImpl.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/test/TestableRequestImpl.java
index dde44c8..1561bd3 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/test/TestableRequestImpl.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/test/TestableRequestImpl.java
@@ -14,7 +14,9 @@
 
 package org.apache.tapestry5.internal.test;
 
+import org.apache.tapestry5.SymbolConstants;
 import org.apache.tapestry5.ioc.annotations.Inject;
+import org.apache.tapestry5.ioc.annotations.Symbol;
 import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
 import org.apache.tapestry5.ioc.internal.util.InternalUtils;
 import org.apache.tapestry5.services.Session;
@@ -36,12 +38,7 @@ public class TestableRequestImpl implements TestableRequest
     private Locale locale = Locale.getDefault();
 
     @Inject
-    public TestableRequestImpl()
-    {
-        this("/foo");
-    }
-
-    public TestableRequestImpl(String contextPath)
+    public TestableRequestImpl(@Symbol(SymbolConstants.CONTEXT_PATH) String contextPath)
     {
         this.contextPath = contextPath;
     }

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4cd5be6b/tapestry-core/src/main/java/org/apache/tapestry5/internal/util/DelegatingSymbolProvider.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/util/DelegatingSymbolProvider.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/util/DelegatingSymbolProvider.java
new file mode 100644
index 0000000..bca339c
--- /dev/null
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/util/DelegatingSymbolProvider.java
@@ -0,0 +1,46 @@
+// Copyright 2012 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.tapestry5.internal.util;
+
+import org.apache.tapestry5.ioc.services.SymbolProvider;
+
+/**
+ * Combines two symbol providers.
+ *
+ * @since 5.4
+ */
+public class DelegatingSymbolProvider implements SymbolProvider
+{
+    private final SymbolProvider primary, secondary;
+
+    public DelegatingSymbolProvider(SymbolProvider primary, SymbolProvider secondary)
+    {
+        this.primary = primary;
+        this.secondary = secondary;
+    }
+
+    @Override
+    public String valueForSymbol(String symbolName)
+    {
+        String value = primary.valueForSymbol(symbolName);
+
+        if (value == null)
+        {
+            value = secondary.valueForSymbol(symbolName);
+        }
+
+        return value;
+    }
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4cd5be6b/tapestry-core/src/main/java/org/apache/tapestry5/services/Request.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/services/Request.java b/tapestry-core/src/main/java/org/apache/tapestry5/services/Request.java
index 65c419d..5a23a58 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/services/Request.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/services/Request.java
@@ -31,7 +31,8 @@ public interface Request
      * if the session is invalidated and create is false, returns null. Invoking this method with true, when the session exists but has
      * been invalidated, will force the creation of a new session.
      *
-     * @param create true to force the creation of the session
+     * @param create
+     *         true to force the creation of the session
      * @return the session (or null if create is false the session has not been previously created)
      */
     Session getSession(boolean create);
@@ -39,6 +40,8 @@ public interface Request
     /**
      * 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.
+     *
+     * @deprecated in 5.4, inject the value for symbol {@link org.apache.tapestry5.SymbolConstants#CONTEXT_PATH} instead
      */
     String getContextPath();
 
@@ -85,10 +88,12 @@ public interface Request
      * If the request did not have a header of the specified name, this method returns -1. If the header can't be
      * converted to a date, the method throws an <code>IllegalArgumentException</code>.
      *
-     * @param name a <code>String</code> specifying the name of the header
+     * @param name
+     *         a <code>String</code> specifying the name of the header
      * @return a <code>long</code> value representing the date specified in the header expressed as the number of
      *         milliseconds since January 1, 1970 GMT, or -1 if the named header was not included with the reqest
-     * @throws IllegalArgumentException If the header value can't be converted to a date
+     * @throws IllegalArgumentException
+     *         If the header value can't be converted to a date
      */
     long getDateHeader(String name);
 
@@ -136,7 +141,8 @@ public interface Request
      * {@link javax.servlet.ServletRequest#getAttribute(String)},
      * it is case <em>sensitive</em> (unlike most of Tapestry).
      *
-     * @param name a <code>String</code> specifying the name of the attribute
+     * @param name
+     *         a <code>String</code> specifying the name of the attribute
      * @return an <code>Object</code> containing the value of the attribute, or <code>null</code> if the attribute does
      *         not exist
      */
@@ -146,8 +152,10 @@ public interface Request
      * Stores an attribute in this request. Attributes are reset between requests (and remember that in Tapestry, there
      * is usually two requests per operation: the action request that redirects to a render request).
      *
-     * @param name  a <code>String</code> specifying the name of the attribute
-     * @param value the <code>Object</code> to be stored, or null to remove the attribute
+     * @param name
+     *         a <code>String</code> specifying the name of the attribute
+     * @param value
+     *         the <code>Object</code> to be stored, or null to remove the attribute
      */
     void setAttribute(String name, Object value);
 

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4cd5be6b/tapestry-core/src/main/java/org/apache/tapestry5/services/TapestryModule.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/services/TapestryModule.java b/tapestry-core/src/main/java/org/apache/tapestry5/services/TapestryModule.java
index 6744cee..b811e34 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/services/TapestryModule.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/services/TapestryModule.java
@@ -2123,7 +2123,7 @@ public final class TapestryModule
 
         configuration.add(SymbolConstants.CLUSTERED_SESSIONS, true);
 
-        configuration.add(SymbolConstants.ASSET_PATH_PREFIX, "/assets/");
+        configuration.add(SymbolConstants.ASSET_PATH_PREFIX, "assets");
 
         configuration.add(SymbolConstants.COMPRESS_WHITESPACE, true);
 
@@ -2212,6 +2212,7 @@ public final class TapestryModule
         configuration.add(MetaDataConstants.WHITELIST_ONLY_PAGE, false);
 
         configuration.add(SymbolConstants.REQUIRE_JS, "classpath:org/apache/tapestry5/require_2.0.2.js");
+        configuration.add(SymbolConstants.CONTEXT_PATH, "");
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4cd5be6b/tapestry-core/src/main/java/org/apache/tapestry5/test/PageTester.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/test/PageTester.java b/tapestry-core/src/main/java/org/apache/tapestry5/test/PageTester.java
index 72536ab..5771a7f 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/test/PageTester.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/test/PageTester.java
@@ -1,4 +1,4 @@
-// Copyright 2006, 2007, 2008, 2009, 2010, 2011 The Apache Software Foundation
+// Copyright 2006=-2012 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.
@@ -31,7 +31,6 @@ import org.apache.tapestry5.ioc.internal.util.InternalUtils;
 import org.apache.tapestry5.ioc.services.SymbolProvider;
 import org.apache.tapestry5.services.ApplicationGlobals;
 import org.apache.tapestry5.services.RequestHandler;
-import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import java.io.IOException;
@@ -40,17 +39,13 @@ import java.util.Map;
 
 /**
  * This class is used to run a Tapestry app in a single-threaded, in-process testing environment.
- * You can ask it to
- * render a certain page and check the DOM object created. You can also ask it to click on a link
- * element in the DOM
- * object to get the next page. Because no servlet container is required, it is very fast and you
- * can directly debug
- * into your code in your IDE.
+ * You can ask it to render a certain page and check the DOM object created. You can also ask it to click on a link
+ * element in the DOM object to get the next page. Because no servlet container is required, it is very fast and you
+ * can directly debug into your code in your IDE.
  */
 @SuppressWarnings("all")
 public class PageTester
 {
-    private final Logger logger = LoggerFactory.getLogger(PageTester.class);
 
     private final Registry registry;
 
@@ -80,16 +75,20 @@ public class PageTester
      * Initializes a PageTester that acts as a browser and a servlet container to test drive your
      * Tapestry pages.
      *
-     * @param appPackage    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
-     *                      of the
-     *                      module class for your app. If you don't have one, pass an empty string.
-     * @param contextPath   The path to the context root so that Tapestry can find the templates (if they're
-     *                      put
-     *                      there).
-     * @param moduleClasses Classes of additional modules to load
+     * @param appPackage
+     *         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
+     *         of the
+     *         module class for your app. If you don't have one, pass an empty string.
+     * @param contextPath
+     *         The path to the context root so that Tapestry can find the templates (if they're
+     *         put
+     *         there).
+     * @param moduleClasses
+     *         Classes of additional modules to load
      */
     public PageTester(String appPackage, String appName, String contextPath, Class... moduleClasses)
     {
@@ -99,7 +98,7 @@ public class PageTester
 
         SymbolProvider provider = new SingleKeySymbolProvider(InternalConstants.TAPESTRY_APP_PACKAGE_PARAM, appPackage);
 
-        TapestryAppInitializer initializer = new TapestryAppInitializer(logger, provider, appName,
+        TapestryAppInitializer initializer = new TapestryAppInitializer(LoggerFactory.getLogger(PageTester.class), provider, appName,
                 null);
 
         initializer.addModules(PageTesterModule.class);
@@ -157,7 +156,8 @@ public class PageTester
      * more complicated
      * queries.
      *
-     * @param serviceInterface used to select the service
+     * @param serviceInterface
+     *         used to select the service
      */
     public <T> T getService(Class<T> serviceInterface)
     {
@@ -167,7 +167,8 @@ public class PageTester
     /**
      * Renders a page specified by its name.
      *
-     * @param pageName The name of the page to be rendered.
+     * @param pageName
+     *         The name of the page to be rendered.
      * @return The DOM created. Typically you will assert against it.
      */
     public Document renderPage(String pageName)
@@ -188,7 +189,8 @@ public class PageTester
     /**
      * Renders a page specified by its name and returns the response.
      *
-     * @param pageName The name of the page to be rendered.
+     * @param pageName
+     *         The name of the page to be rendered.
      * @return The response object to assert against
      * @since 5.2.3
      */
@@ -234,7 +236,8 @@ public class PageTester
     /**
      * Simulates a click on a link.
      *
-     * @param linkElement The Link object to be "clicked" on.
+     * @param linkElement
+     *         The Link object to be "clicked" on.
      * @return The DOM created. Typically you will assert against it.
      */
     public Document clickLink(Element linkElement)
@@ -247,7 +250,8 @@ public class PageTester
     /**
      * Simulates a click on a link.
      *
-     * @param linkElement The Link object to be "clicked" on.
+     * @param linkElement
+     *         The Link object to be "clicked" on.
      * @return The response object to assert against
      * @since 5.2.3
      */
@@ -380,8 +384,10 @@ public class PageTester
      * fields, which act as
      * overrides on the values stored inside the elements.
      *
-     * @param form       the form to be submitted.
-     * @param parameters the query parameter name/value pairs
+     * @param form
+     *         the form to be submitted.
+     * @param parameters
+     *         the query parameter name/value pairs
      * @return The DOM created. Typically you will assert against it.
      */
     public Document submitForm(Element form, Map<String, String> parameters)
@@ -396,8 +402,10 @@ public class PageTester
      * fields, which act as
      * overrides on the values stored inside the elements.
      *
-     * @param form       the form to be submitted.
-     * @param parameters the query parameter name/value pairs
+     * @param form
+     *         the form to be submitted.
+     * @param parameters
+     *         the query parameter name/value pairs
      * @return The response object to assert against.
      * @since 5.2.3
      */
@@ -501,8 +509,10 @@ public class PageTester
      * specify values for the
      * form fields.
      *
-     * @param submitButton the submit button to be clicked.
-     * @param fieldValues  the field values keyed on field names.
+     * @param submitButton
+     *         the submit button to be clicked.
+     * @param fieldValues
+     *         the field values keyed on field names.
      * @return The DOM created. Typically you will assert against it.
      */
     public Document clickSubmit(Element submitButton, Map<String, String> fieldValues)
@@ -517,8 +527,10 @@ public class PageTester
      * specify values for the
      * form fields.
      *
-     * @param submitButton the submit button to be clicked.
-     * @param fieldValues  the field values keyed on field names.
+     * @param submitButton
+     *         the submit button to be clicked.
+     * @param fieldValues
+     *         the field values keyed on field names.
      * @return The response object to assert against.
      * @since 5.2.3
      */
@@ -584,7 +596,8 @@ public class PageTester
      * Sets the simulated browser's preferred language, i.e., the value returned from
      * {@link org.apache.tapestry5.services.Request#getLocale()}.
      *
-     * @param preferedLanguage preferred language setting
+     * @param preferedLanguage
+     *         preferred language setting
      */
     public void setPreferedLanguage(Locale preferedLanguage)
     {

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4cd5be6b/tapestry-core/src/test/groovy/org/apache/tapestry5/integration/app1/TapestryJavaScriptTests.groovy
----------------------------------------------------------------------
diff --git a/tapestry-core/src/test/groovy/org/apache/tapestry5/integration/app1/TapestryJavaScriptTests.groovy b/tapestry-core/src/test/groovy/org/apache/tapestry5/integration/app1/TapestryJavaScriptTests.groovy
deleted file mode 100644
index e5920b6..0000000
--- a/tapestry-core/src/test/groovy/org/apache/tapestry5/integration/app1/TapestryJavaScriptTests.groovy
+++ /dev/null
@@ -1,20 +0,0 @@
-package org.apache.tapestry5.integration.app1
-
-import org.apache.tapestry5.integration.TapestryCoreTestCase
-import org.testng.annotations.Test
-
-class TapestryJavaScriptTests extends TapestryCoreTestCase {
-
-    @Test
-    void basic_javascript_tests() {
-        openLinks "JavaScript Unit Tests"
-
-        def caption = getText("//div[@class='js-results']/p[contains(@class,'caption')]")
-
-        def matches = caption =~ /(\d+) failed/
-
-        if (matches[0][1] != "0"){
-            fail "Some JavaScript unit tests failed"
-        }
-    }
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4cd5be6b/tapestry-core/src/test/groovy/org/apache/tapestry5/internal/services/assets/AssetPathConstructorImplTest.groovy
----------------------------------------------------------------------
diff --git a/tapestry-core/src/test/groovy/org/apache/tapestry5/internal/services/assets/AssetPathConstructorImplTest.groovy b/tapestry-core/src/test/groovy/org/apache/tapestry5/internal/services/assets/AssetPathConstructorImplTest.groovy
index 166dbd8..5dae34a 100644
--- a/tapestry-core/src/test/groovy/org/apache/tapestry5/internal/services/assets/AssetPathConstructorImplTest.groovy
+++ b/tapestry-core/src/test/groovy/org/apache/tapestry5/internal/services/assets/AssetPathConstructorImplTest.groovy
@@ -12,9 +12,7 @@ class AssetPathConstructorImplTest extends TestBase {
 
     def request = newMock(Request)
 
-    def apc = new AssetPathConstructorImpl(request, null, "123", "", false, "/assets/")
-
-    expect(request.contextPath).andReturn("").atLeastOnce()
+    def apc = new AssetPathConstructorImpl(request, null, "", "123", "", false, "assets")
 
     replay()
 
@@ -25,14 +23,12 @@ class AssetPathConstructorImplTest extends TestBase {
     verify()
   }
 
-  @Test
+@Test
   void "construct an asset path with no extra path"() {
 
     def request = newMock(Request)
 
-    def apc = new AssetPathConstructorImpl(request, null, "123", "", false, "/assets/")
-
-    expect(request.contextPath).andReturn("")
+    def apc = new AssetPathConstructorImpl(request, null, "", "123", "", false, "assets")
 
     replay()
 
@@ -44,9 +40,7 @@ class AssetPathConstructorImplTest extends TestBase {
   void "construct asset path with an application folder"() {
     def request = newMock(Request)
 
-    def apc = new AssetPathConstructorImpl(request, null, "123", "myapp", false, "/assets/")
-
-    expect(request.contextPath).andReturn("").atLeastOnce()
+    def apc = new AssetPathConstructorImpl(request, null, "", "123", "myapp", false, "assets")
 
     replay()
 
@@ -59,9 +53,7 @@ class AssetPathConstructorImplTest extends TestBase {
   void "construct asset path with a context path"() {
     def request = newMock(Request)
 
-    def apc = new AssetPathConstructorImpl(request, null, "123", "myapp", false, "/assets/")
-
-    expect(request.contextPath).andReturn("/ctx").atLeastOnce()
+    def apc = new AssetPathConstructorImpl(request, null, "ctx/", "123", "myapp", false, "assets")
 
     replay()
 
@@ -75,15 +67,14 @@ class AssetPathConstructorImplTest extends TestBase {
     def request = newMock(Request)
     def baseURLSource = newMock(BaseURLSource)
 
-    def apc = new AssetPathConstructorImpl(request, baseURLSource, "123", "myapp", true, "/assets/")
+    def apc = new AssetPathConstructorImpl(request, baseURLSource, "mycontext/", "123", "myapp", true, "assets")
 
     expect(request.secure).andReturn(false)
-    expect(request.contextPath).andReturn("")
     expect(baseURLSource.getBaseURL(false)).andReturn("http://localhost:8080")
 
     replay()
 
-    assert apc.constructAssetPath("virt", "extra") == "http://localhost:8080/myapp/assets/123/virt/extra"
+    assert apc.constructAssetPath("virt", "extra") == "http://localhost:8080/mycontext/myapp/assets/123/virt/extra"
 
     verify()
 

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4cd5be6b/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/ClasspathAssetAliasManagerImplTest.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/ClasspathAssetAliasManagerImplTest.java b/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/ClasspathAssetAliasManagerImplTest.java
index db2ac2d..8a8ab7a 100644
--- a/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/ClasspathAssetAliasManagerImplTest.java
+++ b/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/ClasspathAssetAliasManagerImplTest.java
@@ -1,4 +1,4 @@
-// Copyright 2006, 2007, 2009, 2010, 2011 The Apache Software Foundation
+// Copyright 2006, 2007, 2009, 2010, 2011, 2012 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.
@@ -82,13 +82,11 @@ public class ClasspathAssetAliasManagerImplTest extends InternalBaseTestCase
 
         BaseURLSource baseURLSource = newMock(BaseURLSource.class);
 
-        train_getContextPath(request, "/ctx");
-
         replay();
 
         ClasspathAssetAliasManager manager = new ClasspathAssetAliasManagerImpl(
                 new AssetPathConstructorImpl(request,
-                baseURLSource, APP_VERSION, "", false, "/assets/"), configuration());
+                baseURLSource, "ctx/", APP_VERSION, "", false, "assets"), configuration());
 
         String expectedPath = "/ctx/assets/" + APP_VERSION + "/" + expectedClientURL;
         assertEquals(manager.toClientURL(resourcePath), expectedPath);

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4cd5be6b/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/ComponentEventDispatcherTest.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/ComponentEventDispatcherTest.java b/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/ComponentEventDispatcherTest.java
index 888c098..c1642d8 100644
--- a/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/ComponentEventDispatcherTest.java
+++ b/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/ComponentEventDispatcherTest.java
@@ -55,8 +55,8 @@ public class ComponentEventDispatcherTest extends InternalBaseTestCase
         replay();
 
         Dispatcher dispatcher = new ComponentEventDispatcher(null,
-                new ComponentEventLinkEncoderImpl(null, contextPathEncoder, ls, request,
-                        response, null, null, null, true, "", null, null));
+                new ComponentEventLinkEncoderImpl(null, contextPathEncoder, ls,
+                        response, null, null, null, true, null, "", null, null));
 
         assertFalse(dispatcher.dispatch(request, response));
 
@@ -169,8 +169,8 @@ public class ComponentEventDispatcherTest extends InternalBaseTestCase
         replay();
 
         Dispatcher dispatcher = new ComponentEventDispatcher(handler,
-                new ComponentEventLinkEncoderImpl(resolver, contextPathEncoder, ls, request,
-                        response, null, null, null, true, "", metaDataLocator, null));
+                new ComponentEventLinkEncoderImpl(resolver, contextPathEncoder, ls,
+                        response, null, null, null, true, null, "", metaDataLocator, null));
 
         assertTrue(dispatcher.dispatch(request, response));
 
@@ -212,8 +212,8 @@ public class ComponentEventDispatcherTest extends InternalBaseTestCase
         replay();
 
         Dispatcher dispatcher = new ComponentEventDispatcher(handler,
-                new ComponentEventLinkEncoderImpl(resolver, contextPathEncoder, ls, request,
-                        response, null, null, null, true, "", metaDataLocator, null));
+                new ComponentEventLinkEncoderImpl(resolver, contextPathEncoder, ls,
+                        response, null, null, null, true, null, "", metaDataLocator, null));
 
         assertTrue(dispatcher.dispatch(request, response));
 
@@ -237,8 +237,8 @@ public class ComponentEventDispatcherTest extends InternalBaseTestCase
         replay();
 
         Dispatcher dispatcher = new ComponentEventDispatcher(null,
-                new ComponentEventLinkEncoderImpl(resolver, contextPathEncoder, ls, request,
-                        response, null, null, null, true, "", null, null));
+                new ComponentEventLinkEncoderImpl(resolver, contextPathEncoder, ls,
+                        response, null, null, null, true, null, "", null, null));
 
         assertFalse(dispatcher.dispatch(request, response));
 
@@ -279,7 +279,7 @@ public class ComponentEventDispatcherTest extends InternalBaseTestCase
 
         Dispatcher dispatcher = new ComponentEventDispatcher(handler,
                 new ComponentEventLinkEncoderImpl(resolver, contextPathEncoder, localizationSetter,
-                        request, response, null, null, null, true, "", metaDataLocator, null));
+                        response, null, null, null, true, null, "", metaDataLocator, null));
 
         assertTrue(dispatcher.dispatch(request, response));
 
@@ -334,7 +334,7 @@ public class ComponentEventDispatcherTest extends InternalBaseTestCase
 
         Dispatcher dispatcher = new ComponentEventDispatcher(handler,
                 new ComponentEventLinkEncoderImpl(resolver, contextPathEncoder, localizationSetter,
-                        request, response, null, null, null, true, "", metaDataLocator, whitelist));
+                        response, null, null, null, true, null, "", metaDataLocator, whitelist));
 
         assertTrue(dispatcher.dispatch(request, response));
 
@@ -371,7 +371,7 @@ public class ComponentEventDispatcherTest extends InternalBaseTestCase
 
         Dispatcher dispatcher = new ComponentEventDispatcher(handler,
                 new ComponentEventLinkEncoderImpl(resolver, contextPathEncoder, localizationSetter,
-                        request, response, null, null, null, true, "", metaDataLocator, whitelist));
+                        response, null, null, null, true, null, "", metaDataLocator, whitelist));
 
         assertFalse(dispatcher.dispatch(request, response));
 

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4cd5be6b/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/ComponentEventLinkEncoderImplTest.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/ComponentEventLinkEncoderImplTest.java b/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/ComponentEventLinkEncoderImplTest.java
index 638be59..bb01930 100644
--- a/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/ComponentEventLinkEncoderImplTest.java
+++ b/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/ComponentEventLinkEncoderImplTest.java
@@ -50,19 +50,17 @@ public class ComponentEventLinkEncoderImplTest extends InternalBaseTestCase
     public void locale_not_encoded()
     {
         RequestSecurityManager manager = mockRequestSecurityManager();
-        Request request = mockRequest();
         Response response = mockResponse();
         ContextPathEncoder contextPathEncoder = getService(ContextPathEncoder.class);
 
         expect(manager.checkPageSecurity("MyPage")).andReturn(LinkSecurity.INSECURE);
-        train_getContextPath(request, "/myapp");
 
         train_encodeURL(response, "/myapp/mypage", "MAGIC");
 
         replay();
 
-        ComponentEventLinkEncoder encoder = new ComponentEventLinkEncoderImpl(null, contextPathEncoder, null, request,
-                response, manager, null, null, false, "", null, null);
+        ComponentEventLinkEncoder encoder = new ComponentEventLinkEncoderImpl(null, contextPathEncoder, null,
+                response, manager, null, null, false, "/myapp", "", null, null);
 
         PageRenderRequestParameters parameters = new PageRenderRequestParameters("MyPage", new EmptyEventContext());
 
@@ -77,19 +75,17 @@ public class ComponentEventLinkEncoderImplTest extends InternalBaseTestCase
     public void index_stripped_off()
     {
         RequestSecurityManager manager = mockRequestSecurityManager();
-        Request request = mockRequest();
         Response response = mockResponse();
         ContextPathEncoder contextPathEncoder = getService(ContextPathEncoder.class);
 
         expect(manager.checkPageSecurity("admin/Index")).andReturn(LinkSecurity.INSECURE);
-        train_getContextPath(request, "");
 
         train_encodeURL(response, "/admin/abc", "MAGIC");
 
         replay();
 
-        ComponentEventLinkEncoder encoder = new ComponentEventLinkEncoderImpl(null, contextPathEncoder, null, request,
-                response, manager, null, null, false, "", null, null);
+        ComponentEventLinkEncoder encoder = new ComponentEventLinkEncoderImpl(null, contextPathEncoder, null,
+                response, manager, null, null, false, "", "", null, null);
 
         PageRenderRequestParameters parameters = new PageRenderRequestParameters("admin/Index", new ArrayEventContext(
                 typeCoercer, "abc"));
@@ -105,19 +101,17 @@ public class ComponentEventLinkEncoderImplTest extends InternalBaseTestCase
     public void root_index_page_gone()
     {
         RequestSecurityManager manager = mockRequestSecurityManager();
-        Request request = mockRequest();
         Response response = mockResponse();
         ContextPathEncoder contextPathEncoder = getService(ContextPathEncoder.class);
 
         expect(manager.checkPageSecurity("Index")).andReturn(LinkSecurity.INSECURE);
-        train_getContextPath(request, "");
 
         train_encodeURL(response, "/", "MAGIC");
 
         replay();
 
-        ComponentEventLinkEncoder encoder = new ComponentEventLinkEncoderImpl(null, contextPathEncoder, null, request,
-                response, manager, null, null, false, "", null, null);
+        ComponentEventLinkEncoder encoder = new ComponentEventLinkEncoderImpl(null, contextPathEncoder, null,
+                response, manager, null, null, false, "", "", null, null);
 
         PageRenderRequestParameters parameters = new PageRenderRequestParameters("Index", new EmptyEventContext());
 
@@ -145,7 +139,7 @@ public class ComponentEventLinkEncoderImplTest extends InternalBaseTestCase
         replay();
 
         ComponentEventLinkEncoderImpl linkEncoder = new ComponentEventLinkEncoderImpl(resolver, contextPathEncoder, ls,
-                request, response, null, null, null, true, "", null, null);
+                response, null, null, null, true, null, "", null, null);
 
         PageRenderRequestParameters parameters = linkEncoder.decodePageRenderRequest(request);
 
@@ -170,7 +164,7 @@ public class ComponentEventLinkEncoderImplTest extends InternalBaseTestCase
         replay();
 
         ComponentEventLinkEncoderImpl linkEncoder = new ComponentEventLinkEncoderImpl(resolver, contextPathEncoder, ls,
-                request, response, null, null, null, true, "", null, null);
+                response, null, null, null, true, null, "", null, null);
 
         PageRenderRequestParameters parameters = linkEncoder.decodePageRenderRequest(request);
 
@@ -196,7 +190,7 @@ public class ComponentEventLinkEncoderImplTest extends InternalBaseTestCase
         replay();
 
         ComponentEventLinkEncoderImpl linkEncoder = new ComponentEventLinkEncoderImpl(resolver, contextPathEncoder, ls,
-                request, response, null, null, null, true, "", null, null);
+                response, null, null, null, true, null, "", null, null);
 
         PageRenderRequestParameters parameters = linkEncoder.decodePageRenderRequest(request);
 
@@ -241,7 +235,7 @@ public class ComponentEventLinkEncoderImplTest extends InternalBaseTestCase
         replay();
 
         ComponentEventLinkEncoderImpl linkEncoder = new ComponentEventLinkEncoderImpl(resolver, contextPathEncoder, ls,
-                request, null, null, null, null, true, "", metaDataLocator, null);
+                null, null, null, null, true, null, "", metaDataLocator, null);
 
         PageRenderRequestParameters parameters = linkEncoder.decodePageRenderRequest(request);
 
@@ -283,7 +277,7 @@ public class ComponentEventLinkEncoderImplTest extends InternalBaseTestCase
         replay();
 
         ComponentEventLinkEncoderImpl linkEncoder = new ComponentEventLinkEncoderImpl(resolver, contextPathEncoder, ls,
-                request, null, null, null, null, true, "", metaDataLocator, null);
+                null, null, null, null, true, null, "", metaDataLocator, null);
 
         PageRenderRequestParameters parameters = linkEncoder.decodePageRenderRequest(request);
 
@@ -319,7 +313,7 @@ public class ComponentEventLinkEncoderImplTest extends InternalBaseTestCase
         replay();
 
         ComponentEventLinkEncoderImpl linkEncoder = new ComponentEventLinkEncoderImpl(resolver, contextPathEncoder, ls,
-                request, null, null, null, null, true, "", metaDataLocator, whitelist);
+                null, null, null, null, true, null, "", metaDataLocator, whitelist);
 
         PageRenderRequestParameters parameters = linkEncoder.decodePageRenderRequest(request);
 
@@ -358,7 +352,7 @@ public class ComponentEventLinkEncoderImplTest extends InternalBaseTestCase
         replay();
 
         ComponentEventLinkEncoderImpl linkEncoder = new ComponentEventLinkEncoderImpl(resolver, contextPathEncoder, ls,
-                request, null, null, null, null, true, "", metaDataLocator, whitelist);
+                null, null, null, null, true, null, "", metaDataLocator, whitelist);
 
         assertNull(linkEncoder.decodePageRenderRequest(request));
 
@@ -401,7 +395,7 @@ public class ComponentEventLinkEncoderImplTest extends InternalBaseTestCase
         replay();
 
         ComponentEventLinkEncoderImpl linkEncoder = new ComponentEventLinkEncoderImpl(resolver, contextPathEncoder, ls,
-                request, null, null, null, null, true, "", metaDataLocator, null);
+                null, null, null, null, true, null, "", metaDataLocator, null);
 
         PageRenderRequestParameters parameters = linkEncoder.decodePageRenderRequest(request);
 
@@ -438,7 +432,7 @@ public class ComponentEventLinkEncoderImplTest extends InternalBaseTestCase
         replay();
 
         ComponentEventLinkEncoderImpl linkEncoder = new ComponentEventLinkEncoderImpl(resolver, contextPathEncoder, ls,
-                request, null, null, null, null, true, "", metaDataLocator, null);
+                null, null, null, null, true, null, "", metaDataLocator, null);
 
         ComponentEventRequestParameters parameters = linkEncoder.decodeComponentEventRequest(request);
 

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4cd5be6b/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/ContextAssetFactoryTest.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/ContextAssetFactoryTest.java b/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/ContextAssetFactoryTest.java
index 29cbf69..1183cea 100644
--- a/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/ContextAssetFactoryTest.java
+++ b/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/ContextAssetFactoryTest.java
@@ -1,4 +1,4 @@
-// Copyright 2006, 2007, 2009 The Apache Software Foundation
+// Copyright 2006, 2007, 2009, 2012 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.
@@ -53,21 +53,19 @@ public class ContextAssetFactoryTest extends InternalBaseTestCase
 
         Resource r = new ContextResource(context, "foo/Bar.txt");
 
-        train_getContextPath(request, "/context");
-
         replay();
 
         AssetFactory factory = new ContextAssetFactory(
-                                    new AssetPathConstructorImpl(request,
-                                                                baseURLSource,
-                                                                "4.5.6",
-                                                                "",
-                                                                false,
-                                                                "/assets/"
-                                                            ),
-                                    context,
-                                    new IdentityAssetPathConverter()
-                                );
+                new AssetPathConstructorImpl(request,
+                        baseURLSource,
+                        "context/", "4.5.6",
+                        "",
+                        false,
+                        "assets"
+                ),
+                context,
+                new IdentityAssetPathConverter()
+        );
 
         Asset asset = factory.createAsset(r);
 
@@ -92,22 +90,21 @@ public class ContextAssetFactoryTest extends InternalBaseTestCase
 
         Resource r = new ContextResource(context, "foo/Bar.txt");
 
-        train_getContextPath(request, "/context");
         train_getBaseSource(baseURLSource, request);
 
         replay();
 
         AssetFactory factory = new ContextAssetFactory(
-                                    new AssetPathConstructorImpl(request,
-                                                                baseURLSource,
-                                                                "4.5.6",
-                                                                "",
-                                                                true,
-                                                                "/assets/"
-                                                            ),
-                                    context,
-                                    new IdentityAssetPathConverter()
-                                );
+                new AssetPathConstructorImpl(request,
+                        baseURLSource,
+                        "context/", "4.5.6",
+                        "",
+                        true,
+                        "assets"
+                ),
+                context,
+                new IdentityAssetPathConverter()
+        );
 
         Asset asset = factory.createAsset(r);
 

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4cd5be6b/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/CookiesImplTest.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/CookiesImplTest.java b/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/CookiesImplTest.java
index 844119c..906f0b2 100644
--- a/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/CookiesImplTest.java
+++ b/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/CookiesImplTest.java
@@ -1,4 +1,4 @@
-// Copyright 2007, 2010 The Apache Software Foundation
+// Copyright 2007, 2010, 2012 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.
@@ -88,7 +88,7 @@ public class CookiesImplTest extends Assert
     {
         // In seconds
         final int ONE_WEEK = 7 * 24 * 60 * 60;
-        CookiesImpl cs = new CookiesImpl(null, newCookieSource(nameValues), null, ONE_WEEK);
+        CookiesImpl cs = new CookiesImpl(null, newCookieSource(nameValues), null, "", ONE_WEEK);
         String actual = cs.readCookieValue(name);
         assertEquals(actual, expected);
     }
@@ -129,7 +129,7 @@ public class CookiesImplTest extends Assert
             {
                 cookies.add(cookie);
             }
-        }, 1000l * 1000l);
+        }, contextPath, 1000l * 1000l);
     }
 
     public void test_Write_Cookie_With_Max_Age()

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4cd5be6b/tapestry-core/src/test/java/org/apache/tapestry5/internal/test/InternalBaseTestCase.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/test/java/org/apache/tapestry5/internal/test/InternalBaseTestCase.java b/tapestry-core/src/test/java/org/apache/tapestry5/internal/test/InternalBaseTestCase.java
index 7089c83..5882544 100644
--- a/tapestry-core/src/test/java/org/apache/tapestry5/internal/test/InternalBaseTestCase.java
+++ b/tapestry-core/src/test/java/org/apache/tapestry5/internal/test/InternalBaseTestCase.java
@@ -1,4 +1,4 @@
-// Copyright 2006, 2007, 2008, 2009, 2010, 2011 The Apache Software Foundation
+// Copyright 2006-2012 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.
@@ -172,11 +172,6 @@ public class InternalBaseTestCase extends TapestryTestCase implements Registry
         expect(resources.getNestedId()).andReturn(nestedId).atLeastOnce();
     }
 
-    protected final void train_getContextPath(Request request, String contextPath)
-    {
-        expect(request.getContextPath()).andReturn(contextPath).atLeastOnce();
-    }
-
     protected final void train_getBaseSource(BaseURLSource baseURLSource, Request request)
     {
         expect(request.isSecure()).andReturn(false);