tapestry-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From hls...@apache.org
Subject svn commit: r935563 - in /tapestry/tapestry5/trunk/tapestry-core/src: main/java/org/apache/tapestry5/internal/services/ main/java/org/apache/tapestry5/internal/services/assets/ main/java/org/apache/tapestry5/services/ main/java/org/apache/tapestry5/ser...
Date Mon, 19 Apr 2010 13:41:58 GMT
Author: hlship
Date: Mon Apr 19 13:41:57 2010
New Revision: 935563

URL: http://svn.apache.org/viewvc?rev=935563&view=rev
Log:
Strip out AssetAuthorizer and related implementations, build up new approach to accessing assets via AssetDispatcher and AssetRequestHandler

Added:
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/assets/
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/assets/AssetPathConstructorImpl.java   (with props)
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/assets/ClasspathAssetRequestHandler.java   (with props)
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/assets/ContextAssetRequestHandler.java   (with props)
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/assets/
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/assets/AssetPathConstructor.java   (with props)
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/assets/AssetRequestHandler.java   (with props)
Removed:
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/AssetProtectionDispatcher.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/RegexAuthorizer.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/WhitelistAuthorizer.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/AssetPathAuthorizer.java
    tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/AssetProtectionDispatcherTest.java
    tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/RegexAuthorizerTest.java
    tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/WhitelistAuthorizerTest.java
Modified:
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/AssetDispatcher.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/AssetResourceLocator.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/AssetResourceLocatorImpl.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ClasspathAssetAliasManagerImpl.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ContextAssetFactory.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/RequestConstants.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ResourceStreamer.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ResourceStreamerImpl.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/ClasspathAssetAliasManager.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TapestryModule.java
    tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/services/AppModule.java
    tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/AssetDispatcherTest.java
    tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/ClasspathAssetAliasManagerImplTest.java
    tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/ContextAssetFactoryTest.java

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/AssetDispatcher.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/AssetDispatcher.java?rev=935563&r1=935562&r2=935563&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/AssetDispatcher.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/AssetDispatcher.java Mon Apr 19 13:41:57 2010
@@ -4,7 +4,7 @@
 // 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
+// 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,
@@ -14,43 +14,46 @@
 
 package org.apache.tapestry5.internal.services;
 
-import org.apache.tapestry5.ioc.Resource;
+import java.io.IOException;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.tapestry5.SymbolConstants;
+import org.apache.tapestry5.ioc.annotations.Inject;
+import org.apache.tapestry5.ioc.annotations.Symbol;
+import org.apache.tapestry5.ioc.annotations.UsesMappedConfiguration;
 import org.apache.tapestry5.services.ClasspathAssetAliasManager;
 import org.apache.tapestry5.services.Dispatcher;
 import org.apache.tapestry5.services.Request;
 import org.apache.tapestry5.services.Response;
-
-import javax.servlet.http.HttpServletResponse;
-import java.io.IOException;
+import org.apache.tapestry5.services.assets.AssetRequestHandler;
 
 /**
  * Recognizes requests where the path begins with "/asset/" and delivers the content therein as a bytestream. Also
  * handles requests that are simply polling for a change to the file.
- *
+ * 
  * @see ResourceStreamer
  * @see ClasspathAssetAliasManager
  * @see ResourceCache
+ * @see AssetRequestHandler
  */
+@UsesMappedConfiguration(AssetRequestHandler.class)
 public class AssetDispatcher implements Dispatcher
 {
-    private final ResourceStreamer streamer;
-
-    private final ResourceCache resourceCache;
-
-    private final AssetResourceLocator assetResourceLocator;
+    private final Map<String, AssetRequestHandler> configuration;
 
-    static final String IF_MODIFIED_SINCE_HEADER = "If-Modified-Since";
+    private final String pathPrefix;
 
-    public AssetDispatcher(ResourceStreamer streamer,
+    public AssetDispatcher(Map<String, AssetRequestHandler> configuration,
 
-                           ResourceCache resourceCache,
-
-                           AssetResourceLocator assetResourceLocator)
+    @Inject
+    @Symbol(SymbolConstants.APPLICATION_VERSION)
+    String applicationVersion)
     {
-        this.streamer = streamer;
-        this.resourceCache = resourceCache;
-        this.assetResourceLocator = assetResourceLocator;
+        this.configuration = configuration;
 
+        this.pathPrefix = RequestConstants.ASSET_PATH_PREFIX + applicationVersion + "/";
     }
 
     public boolean dispatch(Request request, Response response) throws IOException
@@ -60,46 +63,29 @@ public class AssetDispatcher implements 
         // Remember that the request path does not include the context path, so we can simply start
         // looking for the asset path prefix right off the bat.
 
-        if (!path.startsWith(RequestConstants.ASSET_PATH_PREFIX)) return false;
-
-        // ClassLoaders like their paths to start with a leading slash.
+        if (!path.startsWith(pathPrefix))
+            return false;
 
-        Resource resource = assetResourceLocator.findResourceForPath(path);
+        String virtualPath = path.substring(pathPrefix.length());
 
-        if (resource == null) return true;
+        int slashx = virtualPath.indexOf('/');
 
-        if (!resource.exists())
-        {
-            response.sendError(HttpServletResponse.SC_NOT_FOUND, ServicesMessages
-                    .assetDoesNotExist(resource));
-            return true;
-        }
+        String virtualFolder = virtualPath.substring(0, slashx);
 
-        long ifModifiedSince = 0;
+        AssetRequestHandler handler = configuration.get(virtualFolder);
 
-        try
+        if (handler != null)
         {
-            ifModifiedSince = request.getDateHeader(IF_MODIFIED_SINCE_HEADER);
-        }
-        catch (IllegalArgumentException ex)
-        {
-            // Simulate the header being missing if it is poorly formatted.
 
-            ifModifiedSince = -1;
-        }
+            String extraPath = virtualPath.substring(slashx + 1);
 
-        if (ifModifiedSince > 0)
-        {
-            long modified = resourceCache.getTimeModified(resource);
+            boolean handled = handler.handleAssetRequest(request, response, extraPath);
 
-            if (ifModifiedSince >= modified)
-            {
-                response.sendError(HttpServletResponse.SC_NOT_MODIFIED, "");
+            if (handled)
                 return true;
-            }
         }
 
-        streamer.streamResource(resource);
+        response.sendError(HttpServletResponse.SC_NOT_FOUND, path);
 
         return true;
     }

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/AssetResourceLocator.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/AssetResourceLocator.java?rev=935563&r1=935562&r2=935563&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/AssetResourceLocator.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/AssetResourceLocator.java Mon Apr 19 13:41:57 2010
@@ -1,10 +1,10 @@
-// Copyright 2009 The Apache Software Foundation
+// Copyright 2009, 2010 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
+// 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,
@@ -19,10 +19,11 @@ import org.apache.tapestry5.ioc.Resource
 import java.io.IOException;
 
 /**
- * Responsible for converting a path (from {@link org.apache.tapestry5.internal.services.AssetDispatcher} into a {@link
- * org.apache.tapestry5.ioc.Resource} that can be {@linkplain org.apache.tapestry5.internal.services.ResourceStreamer
- * streamed to the client}.
- *
+ * Responsible for converting a path into a {@link org.apache.tapestry5.ioc.Resource} that can be
+ * {@linkplain org.apache.tapestry5.internal.services.ResourceStreamer
+ * streamed to the client}. The path is on the classpath, but may have been changed to include a checksum (in
+ * certain cases).
+ * 
  * @since 5.1.0.2
  */
 public interface AssetResourceLocator
@@ -30,8 +31,9 @@ public interface AssetResourceLocator
     /**
      * Analyzes the path and identifies the underying Asset Resource for that path. Handles context resources and
      * checking for a digest.
-     *
-     * @param path to translate
+     * 
+     * @param path
+     *            classpath path, possibly including a checksum in the file name
      * @return resource corresponding to path (may be for a non-existent resource), or null if path is invalid (i.e.,
      *         incorrect digest)
      */

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/AssetResourceLocatorImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/AssetResourceLocatorImpl.java?rev=935563&r1=935562&r2=935563&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/AssetResourceLocatorImpl.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/AssetResourceLocatorImpl.java Mon Apr 19 13:41:57 2010
@@ -4,7 +4,7 @@
 // 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
+// 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,
@@ -14,63 +14,34 @@
 
 package org.apache.tapestry5.internal.services;
 
-import org.apache.tapestry5.SymbolConstants;
+import java.io.IOException;
+
+import javax.servlet.http.HttpServletResponse;
+
 import org.apache.tapestry5.ioc.Resource;
-import org.apache.tapestry5.ioc.annotations.Inject;
-import org.apache.tapestry5.ioc.annotations.Symbol;
 import org.apache.tapestry5.ioc.internal.util.ClasspathResource;
-import org.apache.tapestry5.services.AssetFactory;
-import org.apache.tapestry5.services.ClasspathAssetAliasManager;
-import org.apache.tapestry5.services.ContextProvider;
 import org.apache.tapestry5.services.Response;
 
-import javax.servlet.http.HttpServletResponse;
-import java.io.IOException;
-
 public class AssetResourceLocatorImpl implements AssetResourceLocator
 {
-
-    private final ClasspathAssetAliasManager aliasManager;
-
     private final ResourceCache resourceCache;
 
-    private final AssetFactory contextAssetFactory;
-
     private final Response response;
 
-    private final String applicationAssetPrefix;
-
-    public AssetResourceLocatorImpl(ClasspathAssetAliasManager aliasManager,
-
-                                    ResourceCache resourceCache,
-
-                                    @Inject @Symbol(SymbolConstants.APPLICATION_VERSION)
-                                    String applicationVersion,
-
-                                    @ContextProvider
-                                    AssetFactory contextAssetFactory,
-
-                                    Response response)
+    public AssetResourceLocatorImpl(ResourceCache resourceCache,
 
+    Response response)
     {
-        this.aliasManager = aliasManager;
         this.resourceCache = resourceCache;
-        this.contextAssetFactory = contextAssetFactory;
         this.response = response;
-
-        applicationAssetPrefix = RequestConstants.ASSET_PATH_PREFIX + RequestConstants.CONTEXT_FOLDER + applicationVersion + "/";
     }
 
     public Resource findResourceForPath(String path) throws IOException
     {
-        if (path.startsWith(applicationAssetPrefix))
-            return findContextResource(path.substring(applicationAssetPrefix.length()));
-
-        String resourcePath = aliasManager.toResourcePath(path);
+        Resource resource = new ClasspathResource(path);
 
-        Resource resource = new ClasspathResource(resourcePath);
-
-        if (!resourceCache.requiresDigest(resource)) return resource;
+        if (!resourceCache.requiresDigest(resource))
+            return resource;
 
         String file = resource.getFile();
 
@@ -103,19 +74,14 @@ public class AssetResourceLocatorImpl im
             }
         }
 
-        if (valid) return result;
+        if (valid)
+            return result;
 
         // TODO: Perhaps we should send an exception here, so that the caller can decide
         // to send the error. I'm not happy with this.
-        
-        response.sendError(HttpServletResponse.SC_FORBIDDEN,
-                           ServicesMessages.wrongAssetDigest(result));
 
-        return null;
-    }
+        response.sendError(HttpServletResponse.SC_FORBIDDEN, ServicesMessages.wrongAssetDigest(result));
 
-    private Resource findContextResource(String contextPath)
-    {
-        return contextAssetFactory.getRootResource().forFile(contextPath);
+        return null;
     }
 }

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ClasspathAssetAliasManagerImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ClasspathAssetAliasManagerImpl.java?rev=935563&r1=935562&r2=935563&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ClasspathAssetAliasManagerImpl.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ClasspathAssetAliasManagerImpl.java Mon Apr 19 13:41:57 2010
@@ -14,25 +14,20 @@
 
 package org.apache.tapestry5.internal.services;
 
-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.util.AvailableValues;
-import org.apache.tapestry5.ioc.util.UnknownValueException;
-import org.apache.tapestry5.services.ClasspathAssetAliasManager;
-import org.apache.tapestry5.services.Request;
-
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.List;
 import java.util.Map;
 
+import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
+import org.apache.tapestry5.ioc.util.AvailableValues;
+import org.apache.tapestry5.ioc.util.UnknownValueException;
+import org.apache.tapestry5.services.ClasspathAssetAliasManager;
+import org.apache.tapestry5.services.assets.AssetPathConstructor;
+
 public class ClasspathAssetAliasManagerImpl implements ClasspathAssetAliasManager
 {
-    private final Request request;
-
-    private final String assetPathPrefix;
+    private final AssetPathConstructor assetPathConstructor;
 
     /**
      * Map from alias to path.
@@ -52,20 +47,14 @@ public class ClasspathAssetAliasManagerI
      * Configuration is a map of aliases (short names) to complete names. Keys and values should end with a slash, but
      * one will be provided as necessary, so don't both.
      * 
-     * @param applicationVersion
+     * @param assetPathConstructor
      *            TODO
      */
-    public ClasspathAssetAliasManagerImpl(Request request,
-
-    @Inject
-    @Symbol(SymbolConstants.APPLICATION_VERSION)
-    String applicationVersion,
+    public ClasspathAssetAliasManagerImpl(AssetPathConstructor assetPathConstructor,
 
     Map<String, String> configuration)
     {
-        this.request = request;
-
-        this.assetPathPrefix = RequestConstants.ASSET_PATH_PREFIX + applicationVersion + "/";
+        this.assetPathConstructor = assetPathConstructor;
 
         for (Map.Entry<String, String> e : configuration.entrySet())
         {
@@ -102,19 +91,15 @@ public class ClasspathAssetAliasManagerI
 
     public String toClientURL(String resourcePath)
     {
-        StringBuilder builder = new StringBuilder(request.getContextPath());
-        builder.append(assetPathPrefix);
-
         for (String pathPrefix : sortedPathPrefixes)
         {
             if (resourcePath.startsWith(pathPrefix))
             {
-                String alias = pathPrefixToAlias.get(pathPrefix);
-                builder.append(alias);
-                builder.append("/");
-                builder.append(resourcePath.substring(pathPrefix.length() + 1));
+                String virtualFolder = pathPrefixToAlias.get(pathPrefix);
+
+                String virtualPath = resourcePath.substring(pathPrefix.length() + 1);
 
-                return builder.toString();
+                return assetPathConstructor.constructAssetPath(virtualFolder, virtualPath);
             }
         }
 

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ContextAssetFactory.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ContextAssetFactory.java?rev=935563&r1=935562&r2=935563&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ContextAssetFactory.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ContextAssetFactory.java Mon Apr 19 13:41:57 2010
@@ -1,10 +1,10 @@
-// Copyright 2006, 2007, 2008, 2009 The Apache Software Foundation
+// Copyright 2006, 2007, 2008, 2009, 2010 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
+// 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,
@@ -19,18 +19,16 @@ import org.apache.tapestry5.ioc.Resource
 import org.apache.tapestry5.services.AssetFactory;
 import org.apache.tapestry5.services.AssetPathConverter;
 import org.apache.tapestry5.services.Context;
-import org.apache.tapestry5.services.Request;
+import org.apache.tapestry5.services.assets.AssetPathConstructor;
 
 /**
  * Implementation of {@link AssetFactory} for assets that are part of the web application context.
- *
+ * 
  * @see org.apache.tapestry5.internal.services.ContextResource
  */
 public class ContextAssetFactory implements AssetFactory
 {
-    private final Request request;
-
-    private final String pathPrefix;
+    private final AssetPathConstructor assetPathConstructor;
 
     private final Resource rootResource;
 
@@ -38,25 +36,21 @@ public class ContextAssetFactory impleme
 
     private final boolean invariant;
 
-    public ContextAssetFactory(Request request, Context context,
-
-                               String applicationVersion,
+    public ContextAssetFactory(AssetPathConstructor assetPathConstructor, Context context,
 
-                               AssetPathConverter converter)
+    AssetPathConverter converter)
     {
-        this.request = request;
+        this.assetPathConstructor = assetPathConstructor;
         this.converter = converter;
 
-        pathPrefix = RequestConstants.ASSET_PATH_PREFIX + RequestConstants.CONTEXT_FOLDER
-                + applicationVersion + "/";
-
         rootResource = new ContextResource(context, "/");
         invariant = this.converter.isInvariant();
     }
 
     public Asset createAsset(final Resource resource)
     {
-        final String defaultPath = request.getContextPath() + pathPrefix + resource.getPath();
+        final String defaultPath = assetPathConstructor.constructAssetPath(RequestConstants.CONTEXT_FOLDER, resource
+                .getPath());
 
         return new AbstractAsset(invariant)
         {

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/RequestConstants.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/RequestConstants.java?rev=935563&r1=935562&r2=935563&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/RequestConstants.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/RequestConstants.java Mon Apr 19 13:41:57 2010
@@ -1,4 +1,4 @@
-// Copyright 2006, 2007, 2008, 2009 The Apache Software Foundation
+// Copyright 2006, 2007, 2008, 2009, 2010 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.
@@ -30,15 +30,14 @@ public final class RequestConstants
 
     /**
      * Virtual folder name for assets that are actually stored in the context, but are exposed (much like classpath
-     * assets) to gain far-future expires headers and automatic content compression. The application version number
-     * comes after this prefix and before the true path.
+     * assets) to gain far-future expires headers and automatic content compression.
      * 
      * @since 5.1.0.0
      */
-    public static final String CONTEXT_FOLDER = "ctx/";
+    public static final String CONTEXT_FOLDER = "ctx";
 
     /**
-     * Folder for virtual assets: combined JavaScript files. The file name is actualy a compressed bytestream
+     * Folder for virtual assets: combined JavaScript files. The file name is actually a compressed bytestream
      * of the names of each file.
      * 
      * @since 5.1.0.2

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ResourceStreamer.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ResourceStreamer.java?rev=935563&r1=935562&r2=935563&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ResourceStreamer.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ResourceStreamer.java Mon Apr 19 13:41:57 2010
@@ -4,7 +4,7 @@
 // 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
+// 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,
@@ -19,27 +19,31 @@ import org.apache.tapestry5.ioc.annotati
 
 import java.io.IOException;
 
+import javax.servlet.http.HttpServletResponse;
+
 /**
  * Responsible for streaming the contents of a resource to the client. The {@link org.apache.tapestry5.ioc.Resource} to
  * stream is almost always a {@link org.apache.tapestry5.ioc.internal.util.ClasspathResource}.
  * <p/>
  * The service's configuration is used to map file extensions to content types. Note: this only works for simple
  * extensions (i.e., "jpg") not for complex extensions (i.e., "tar.gz").
- *
+ * 
  * @since 5.1.0.0
  */
 @UsesMappedConfiguration(String.class)
 public interface ResourceStreamer
 {
     /**
-     * Streams the content of the resource to the client.
+     * Streams the content of the resource to the client (or sends
+     * an alternative response such as {@link HttpServletResponse#SC_NOT_MODIFIED}).
      */
     void streamResource(Resource resource) throws IOException;
 
     /**
      * Analyzes the resource to determine what its content type is, possibly using the service's configuration.
-     *
-     * @param resource to analyze
+     * 
+     * @param resource
+     *            to analyze
      * @return content type
      * @throws IOException
      */

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ResourceStreamerImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ResourceStreamerImpl.java?rev=935563&r1=935562&r2=935563&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ResourceStreamerImpl.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ResourceStreamerImpl.java Mon Apr 19 13:41:57 2010
@@ -30,8 +30,12 @@ import java.io.InputStream;
 import java.io.OutputStream;
 import java.util.Map;
 
+import javax.servlet.http.HttpServletResponse;
+
 public class ResourceStreamerImpl implements ResourceStreamer
 {
+    static final String IF_MODIFIED_SINCE_HEADER = "If-Modified-Since";
+
     private final ResourceCache resourceCache;
 
     private final Request request;
@@ -78,6 +82,36 @@ public class ResourceStreamerImpl implem
 
     public void streamResource(Resource resource) throws IOException
     {
+        if (!resource.exists())
+        {
+            response.sendError(HttpServletResponse.SC_NOT_FOUND, ServicesMessages.assetDoesNotExist(resource));
+            return;
+        }
+
+        long ifModifiedSince = 0;
+
+        try
+        {
+            ifModifiedSince = request.getDateHeader(IF_MODIFIED_SINCE_HEADER);
+        }
+        catch (IllegalArgumentException ex)
+        {
+            // Simulate the header being missing if it is poorly formatted.
+
+            ifModifiedSince = -1;
+        }
+
+        if (ifModifiedSince > 0)
+        {
+            long modified = resourceCache.getTimeModified(resource);
+
+            if (ifModifiedSince >= modified)
+            {
+                response.sendError(HttpServletResponse.SC_NOT_MODIFIED, "");
+                return;
+            }
+        }
+
         // Prevent the upstream code from compressing when we don't want to.
 
         request.setAttribute(InternalConstants.SUPPRESS_COMPRESSION, true);
@@ -93,8 +127,7 @@ public class ResourceStreamerImpl implem
 
         String contentType = identifyContentType(resource, streamble);
 
-        boolean compress = analyzer.isGZipSupported()
-                && streamble.getSize(false) >= compressionCutoff
+        boolean compress = analyzer.isGZipSupported() && streamble.getSize(false) >= compressionCutoff
                 && analyzer.isCompressable(contentType);
 
         int contentLength = streamble.getSize(compress);
@@ -103,8 +136,7 @@ public class ResourceStreamerImpl implem
             response.setContentLength(contentLength);
 
         if (compress)
-            response.setHeader(InternalConstants.CONTENT_ENCODING_HEADER,
-                    InternalConstants.GZIP_CONTENT_ENCODING);
+            response.setHeader(InternalConstants.CONTENT_ENCODING_HEADER, InternalConstants.GZIP_CONTENT_ENCODING);
 
         InputStream is = null;
 
@@ -132,8 +164,7 @@ public class ResourceStreamerImpl implem
         return identifyContentType(resource, resourceCache.getStreamableResource(resource));
     }
 
-    private String identifyContentType(Resource resource, StreamableResource streamble)
-            throws IOException
+    private String identifyContentType(Resource resource, StreamableResource streamble) throws IOException
     {
         String contentType = streamble.getContentType();
 

Added: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/assets/AssetPathConstructorImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/assets/AssetPathConstructorImpl.java?rev=935563&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/assets/AssetPathConstructorImpl.java (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/assets/AssetPathConstructorImpl.java Mon Apr 19 13:41:57 2010
@@ -0,0 +1,50 @@
+// Copyright 2010 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.services.assets;
+
+import org.apache.tapestry5.SymbolConstants;
+import org.apache.tapestry5.internal.services.RequestConstants;
+import org.apache.tapestry5.ioc.annotations.Inject;
+import org.apache.tapestry5.ioc.annotations.Symbol;
+import org.apache.tapestry5.services.Request;
+import org.apache.tapestry5.services.assets.AssetPathConstructor;
+
+public class AssetPathConstructorImpl implements AssetPathConstructor
+{
+    private final Request request;
+
+    private final String prefix;
+
+    public AssetPathConstructorImpl(Request request,
+
+    @Inject
+    @Symbol(SymbolConstants.APPLICATION_VERSION)
+    String applicationVersion)
+    {
+        this.request = request;
+        this.prefix = RequestConstants.ASSET_PATH_PREFIX + applicationVersion + "/";
+    }
+
+    public String constructAssetPath(String virtualFolder, String path)
+    {
+        StringBuilder builder = new StringBuilder(request.getContextPath());
+        builder.append(prefix);
+        builder.append(virtualFolder);
+        builder.append('/');
+        builder.append(path);
+
+        return builder.toString();
+    }
+}

Propchange: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/assets/AssetPathConstructorImpl.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/assets/ClasspathAssetRequestHandler.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/assets/ClasspathAssetRequestHandler.java?rev=935563&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/assets/ClasspathAssetRequestHandler.java (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/assets/ClasspathAssetRequestHandler.java Mon Apr 19 13:41:57 2010
@@ -0,0 +1,62 @@
+// Copyright 2010 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.services.assets;
+
+import java.io.IOException;
+
+import org.apache.tapestry5.internal.services.AssetResourceLocator;
+import org.apache.tapestry5.internal.services.ResourceStreamer;
+import org.apache.tapestry5.ioc.Resource;
+import org.apache.tapestry5.services.ClasspathAssetAliasManager;
+import org.apache.tapestry5.services.Request;
+import org.apache.tapestry5.services.Response;
+import org.apache.tapestry5.services.assets.AssetRequestHandler;
+
+/**
+ * A handler for asset requests for classpath assets (within a specific folder).
+ * Each mapping of the {@link ClasspathAssetAliasManager} gets one of these.
+ * 
+ * @since 5.2.0
+ */
+public class ClasspathAssetRequestHandler implements AssetRequestHandler
+{
+    private final ResourceStreamer streamer;
+
+    private final AssetResourceLocator assetResourceLocator;
+
+    private final String baseFolder;
+
+    public ClasspathAssetRequestHandler(ResourceStreamer streamer, AssetResourceLocator assetResourceLocator,
+            String baseFolder)
+    {
+        this.streamer = streamer;
+        this.assetResourceLocator = assetResourceLocator;
+        this.baseFolder = baseFolder;
+    }
+
+    public boolean handleAssetRequest(Request request, Response response, String extraPath) throws IOException
+    {
+        String path = baseFolder + "/" + extraPath;
+
+        Resource resource = assetResourceLocator.findResourceForPath(path);
+
+        if (resource == null)
+            return false;
+
+        streamer.streamResource(resource);
+
+        return true;
+    }
+}

Propchange: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/assets/ClasspathAssetRequestHandler.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/assets/ContextAssetRequestHandler.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/assets/ContextAssetRequestHandler.java?rev=935563&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/assets/ContextAssetRequestHandler.java (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/assets/ContextAssetRequestHandler.java Mon Apr 19 13:41:57 2010
@@ -0,0 +1,58 @@
+// Copyright 2010 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.services.assets;
+
+import java.io.IOException;
+import java.util.regex.Pattern;
+
+import org.apache.tapestry5.internal.services.ResourceStreamer;
+import org.apache.tapestry5.ioc.Resource;
+import org.apache.tapestry5.services.Request;
+import org.apache.tapestry5.services.Response;
+import org.apache.tapestry5.services.assets.AssetRequestHandler;
+
+/**
+ * Handles requests for context assets, screening out attempt to
+ * access anything under WEB-INF or META-INF.
+ * 
+ * @since 5.2.0
+ */
+public class ContextAssetRequestHandler implements AssetRequestHandler
+{
+    private final ResourceStreamer resourceStreamer;
+
+    private final Resource rootContextResource;
+
+    private final Pattern illegal = Pattern.compile("^(web|meta)-inf/.*", Pattern.CASE_INSENSITIVE);
+
+    public ContextAssetRequestHandler(ResourceStreamer resourceStreamer, Resource rootContextResource)
+    {
+        this.resourceStreamer = resourceStreamer;
+        this.rootContextResource = rootContextResource;
+    }
+
+    public boolean handleAssetRequest(Request request, Response response, String extraPath) throws IOException
+    {
+        if (illegal.matcher(extraPath).matches())
+            return false;
+
+        Resource resource = rootContextResource.forFile(extraPath);
+
+        resourceStreamer.streamResource(resource);
+
+        return true;
+    }
+
+}

Propchange: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/assets/ContextAssetRequestHandler.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/ClasspathAssetAliasManager.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/ClasspathAssetAliasManager.java?rev=935563&r1=935562&r2=935563&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/ClasspathAssetAliasManager.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/ClasspathAssetAliasManager.java Mon Apr 19 13:41:57 2010
@@ -22,7 +22,8 @@ import org.apache.tapestry5.ioc.annotati
 /**
  * Used as part of the support for classpath {@link org.apache.tapestry5.Asset}s, to convert the Asset's
  * {@link org.apache.tapestry5.ioc.Resource} to a URL that can be accessed by the client. The asset path, within the
- * classpath, is converted into a shorter virtual path.
+ * classpath, is converted into a shorter virtual path. The term "alias" here is generally referred to as
+ * "virtual folder" elsewhere.
  * <p/>
  * Service configuration is a map from folder aliases (short names) to complete paths. Names should not start or end end
  * with a slash. Generally, an alias should be a single name (not contain a slash). Paths should also not start or end

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TapestryModule.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TapestryModule.java?rev=935563&r1=935562&r2=935563&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TapestryModule.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TapestryModule.java Mon Apr 19 13:41:57 2010
@@ -76,6 +76,9 @@ import org.apache.tapestry5.internal.ren
 import org.apache.tapestry5.internal.services.*;
 import org.apache.tapestry5.internal.services.ajax.AjaxFormUpdateFilter;
 import org.apache.tapestry5.internal.services.ajax.JavascriptSupportImpl;
+import org.apache.tapestry5.internal.services.assets.AssetPathConstructorImpl;
+import org.apache.tapestry5.internal.services.assets.ClasspathAssetRequestHandler;
+import org.apache.tapestry5.internal.services.assets.ContextAssetRequestHandler;
 import org.apache.tapestry5.internal.services.messages.PropertiesFileParserImpl;
 import org.apache.tapestry5.internal.transform.*;
 import org.apache.tapestry5.internal.translator.NumericTranslator;
@@ -100,6 +103,8 @@ import org.apache.tapestry5.runtime.Comp
 import org.apache.tapestry5.runtime.RenderCommand;
 import org.apache.tapestry5.runtime.RenderQueue;
 import org.apache.tapestry5.services.ajax.MultiZoneUpdateEventResultProcessor;
+import org.apache.tapestry5.services.assets.AssetPathConstructor;
+import org.apache.tapestry5.services.assets.AssetRequestHandler;
 import org.apache.tapestry5.services.javascript.JavascriptSupport;
 import org.apache.tapestry5.services.messages.PropertiesFileParser;
 import org.apache.tapestry5.util.StringToEnumCoercion;
@@ -352,12 +357,11 @@ public final class TapestryModule
         binder.bind(PageRenderLinkSource.class, PageRenderLinkSourceImpl.class);
         binder.bind(ClientInfrastructure.class, ClientInfrastructureImpl.class);
         binder.bind(URLRewriter.class, URLRewriterImpl.class);
-        binder.bind(Dispatcher.class, AssetProtectionDispatcher.class).withId("AssetProtectionDispatcher");
-        binder.bind(AssetPathAuthorizer.class, WhitelistAuthorizer.class).withId("WhitelistAuthorizer");
-        binder.bind(AssetPathAuthorizer.class, RegexAuthorizer.class).withId("RegexAuthorizer");
         binder.bind(ValidatorMacro.class, ValidatorMacroImpl.class);
         binder.bind(PropertiesFileParser.class, PropertiesFileParserImpl.class);
         binder.bind(PageActivator.class, PageActivatorImpl.class);
+        binder.bind(Dispatcher.class, AssetDispatcher.class).withId("AssetDispatcher");
+        binder.bind(AssetPathConstructor.class, AssetPathConstructorImpl.class);
     }
 
     // ========================================================================
@@ -456,6 +460,30 @@ public final class TapestryModule
 
     }
 
+    /**
+     * Contributes an handler for each mapped classpath alias, as well as one for context assets.
+     */
+    public static void contributeAssetDispatcher(MappedConfiguration<String, AssetRequestHandler> configuration,
+
+    @ContextProvider
+    AssetFactory contextAssetFactory,
+
+    ClasspathAssetAliasManager classpathAssetAliasManager, ResourceStreamer streamer,
+            AssetResourceLocator assetResourceLocator)
+    {
+        Map<String, String> mappings = classpathAssetAliasManager.getMappings();
+
+        for (String folder : mappings.keySet())
+        {
+            String path = mappings.get(folder);
+
+            configuration.add(folder, new ClasspathAssetRequestHandler(streamer, assetResourceLocator, path));
+        }
+
+        configuration.add(RequestConstants.CONTEXT_FOLDER, new ContextAssetRequestHandler(streamer, contextAssetFactory
+                .getRootResource()));
+    }
+
     private static String toPackagePath(String packageName)
     {
         return packageName.replace('.', '/');
@@ -1223,13 +1251,11 @@ public final class TapestryModule
     @Marker(ContextProvider.class)
     public AssetFactory buildContextAssetFactory(ApplicationGlobals globals,
 
-    @Inject
-    @Symbol(SymbolConstants.APPLICATION_VERSION)
-    String applicationVersion,
+    AssetPathConstructor assetPathConstructor,
 
     AssetPathConverter converter)
     {
-        return new ContextAssetFactory(request, globals.getContext(), applicationVersion, converter);
+        return new ContextAssetFactory(assetPathConstructor, globals.getContext(), converter);
     }
 
     /**
@@ -1761,9 +1787,9 @@ public final class TapestryModule
      * kind of incoming request.
      * <dl>
      * <dt>RootPath</dt>
-     * <dd>Renders the start page for the "/" request</dd>
+     * <dd>Renders the start page for the "/" request (outdated)</dd>
      * <dt>Asset</dt>
-     * <dd>Provides access to classpath assets</dd>
+     * <dd>Provides access to assets</dd>
      * <dt>VirtualAsset</dt>
      * <dd>Provides access to combined scripts</dd>
      * <dt>PageRender</dt>
@@ -1775,8 +1801,9 @@ public final class TapestryModule
      * </dl>
      */
     public static void contributeMasterDispatcher(OrderedConfiguration<Dispatcher> configuration,
-            @InjectService("AssetProtectionDispatcher")
-            Dispatcher assetProt)
+
+    @InjectService("AssetDispatcher")
+    Dispatcher assetDispatcher)
     {
         // Looks for the root path and renders the start page. This is
         // maintained for compatibility
@@ -1785,15 +1812,11 @@ public final class TapestryModule
 
         configuration.addInstance("RootPath", RootPathDispatcher.class, "before:Asset");
 
-        // this goes before asset to make sure that only allowed assets are
-        // streamed to the client.
-        configuration.add("AssetProtection", assetProt, "before:Asset");
-
         // This goes first because an asset to be streamed may have an file
         // extension, such as
         // ".html", that will confuse the later dispatchers.
 
-        configuration.addInstance("Asset", AssetDispatcher.class, "before:ComponentEvent");
+        configuration.add("Asset", assetDispatcher, "before:ComponentEvent");
 
         configuration.addInstance("VirtualAsset", VirtualAssetDispatcher.class, "before:Asset");
 
@@ -2799,79 +2822,6 @@ public final class TapestryModule
     }
 
     /**
-     * Contributes the default set of AssetPathAuthorizers into the
-     * AssetProtectionDispatcher.
-     * 
-     * @param whitelist
-     *            authorization based on explicit whitelisting.
-     * @param regex
-     *            authorization based on pattern matching.
-     * @param conf
-     */
-    public static void contributeAssetProtectionDispatcher(@InjectService("WhitelistAuthorizer")
-    AssetPathAuthorizer whitelist, @InjectService("RegexAuthorizer")
-    AssetPathAuthorizer regex, OrderedConfiguration<AssetPathAuthorizer> conf)
-    {
-        // putting whitelist after everything ensures that, in fact, nothing
-        // falls through.
-        // also ensures that whitelist gives other authorizers the chance to
-        // act...
-        conf.add("regex", regex, "before:whitelist");
-        conf.add("whitelist", whitelist, "after:*");
-    }
-
-    public void contributeRegexAuthorizer(Configuration<String> regex,
-
-    @Symbol("tapestry.scriptaculous.path")
-    String scriptPath,
-
-    @Symbol("tapestry.blackbird.path")
-    String blackbirdPath,
-
-    @Symbol("tapestry.datepicker.path")
-    String datepickerPath,
-
-    @Symbol(SymbolConstants.CONTEXT_ASSETS_AVAILABLE)
-    boolean contextAvailable,
-
-    @Symbol(SymbolConstants.APPLICATION_VERSION)
-    String appVersion,
-
-    @Symbol(InternalConstants.TAPESTRY_APP_PACKAGE_PARAM)
-    String appPackageName)
-    {
-        // allow any js, jpg, jpeg, png, or css under org/apache/tapestry5,
-        // along with
-        // resources for blackbird, scriptaculous, and the date picker.
-        // The funky bit of ([^/.]+/)* is what allows
-        // multiple paths, while not allowing any of those paths to contains ./
-        // or ../ thereby preventing paths like:
-        // org/apache/tapestry5/../../../foo.js
-        String pathPattern = "([^/.]+/)*[^/.]+\\.((css)|(js)|(jpg)|(jpeg)|(png)|(gif))$";
-
-        regex.add("^org/apache/tapestry5/" + pathPattern);
-
-        regex.add(blackbirdPath + "/" + pathPattern);
-        regex.add(datepickerPath + "/" + pathPattern);
-        regex.add(scriptPath + "/" + pathPattern);
-        // allow access to virtual assets. Critical for tapestry-combined js
-        // files.
-        regex.add("virtual/" + pathPattern);
-
-        regex.add("^" + appPackageName.replace(".", "/") + "/" + pathPattern);
-
-        if (contextAvailable)
-        {
-            // we allow everything underneath the context folder, as long as it's not
-            // at or below WEB-INF.
-            // necessary since context assets are now handled via AssetDispatcher so that
-            // they can be compressed, combined, etc.
-            String contextPathPattern = "/(?!(WEB-INF)|(META-INF))([^/.]+/)*[^/]+(?<!\\.tml)$";
-            regex.add(RequestConstants.CONTEXT_FOLDER + appVersion + contextPathPattern);
-        }
-    }
-
-    /**
      * Exposes the Environmental {@link Heartbeat} as an injective service.
      * 
      * @since 5.2.0

Added: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/assets/AssetPathConstructor.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/assets/AssetPathConstructor.java?rev=935563&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/assets/AssetPathConstructor.java (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/assets/AssetPathConstructor.java Mon Apr 19 13:41:57 2010
@@ -0,0 +1,35 @@
+// Copyright 2010 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.services.assets;
+
+/**
+ * Encapslates the logic or creating the path portion of an asset URL, including
+ * the application version.
+ * 
+ * @since 5.2.0
+ */
+public interface AssetPathConstructor
+{
+    /**
+     * Constructs an asset URL path from the virtual folder and path (within the virtual folder).
+     * 
+     * @param virtualFolder
+     *            corresponds to a {@link AssetRequestHandler} contributed to the AssetDispatcher service
+     * @param path
+     *            within the virtual folder (should <em>not</em> start with a slash)
+     * @return path portion of asset URL
+     */
+    String constructAssetPath(String virtualFolder, String path);
+}

Propchange: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/assets/AssetPathConstructor.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/assets/AssetRequestHandler.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/assets/AssetRequestHandler.java?rev=935563&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/assets/AssetRequestHandler.java (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/assets/AssetRequestHandler.java Mon Apr 19 13:41:57 2010
@@ -0,0 +1,69 @@
+// Copyright 2010 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.services.assets;
+
+import java.io.IOException;
+
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.tapestry5.Asset;
+import org.apache.tapestry5.SymbolConstants;
+import org.apache.tapestry5.internal.services.AssetDispatcher;
+import org.apache.tapestry5.services.Request;
+import org.apache.tapestry5.services.Response;
+
+/**
+ * Handler for asset requests, which expose some kind of {@link Asset} to
+ * the user agent (i.e., the client web browser). Starting in Tapestry 5.2,
+ * asset paths are more structured, consisting of four parts:
+ * <ul>
+ * <li><code>/assets/</code> -- the root path for all assets
+ * <li>
+ * <em>application version</em> -- the application version, as defined by the
+ * {@link SymbolConstants#APPLICATION_VERSION} symbol
+ * <li><em>handler id</em> -- a handler for this part of the asset path (defined by contributions to the
+ * <code>AssetDispatcher</code> service)
+ * <li><em>extra path</em> -- additional path beyond the handler id, used to identify the specific resource
+ * </ul>
+ * <p>
+ * So, an example path might be <code>/assets/1.0.1/corelib/components/select.png</code>. The handler id would be
+ * <code>corelib</code>, and the extra path would be <code>components/select.png</code>.
+ * 
+ * @since 5.2.0
+ * @see AssetDispatcher
+ */
+public interface AssetRequestHandler
+{
+    /**
+     * Given a request targeted (via the handler id) to the specific handler, process the request.
+     * The handler is responsible for processing the request, sending back either a bytestream
+     * (via {@link Response#getOutputStream(String)}) or an error response
+     * (via {@link Response#sendError(int, String)}). It is the handler's responsibility to allow
+     * for client-side caching (possibly sending an {@link HttpServletResponse#SC_NOT_MODIFIED} response).
+     * <p>
+     * The handler should return true if it provided a response. If the handler returns false, this indicates that the
+     * extra path did not identify a known asset (virtual or otherwise) and the AssetDispatcher service should send a
+     * {@link HttpServletResponse#SC_NOT_FOUND} response.
+     * 
+     * @param request
+     *            incoming asset request
+     * @param response
+     *            used to send a response to client
+     * @param extraPath
+     *            additional path to identify the specific asset
+     * @return true if request handler, false if asset not found
+     */
+    boolean handleAssetRequest(Request request, Response response, String extraPath) throws IOException;
+}

Propchange: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/assets/AssetRequestHandler.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/services/AppModule.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/services/AppModule.java?rev=935563&r1=935562&r2=935563&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/services/AppModule.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/services/AppModule.java Mon Apr 19 13:41:57 2010
@@ -271,9 +271,4 @@ public class AppModule
     {
         configuration.add("ReverseStringsWorker", new ReverseStringsWorker());
     }
-
-    public static void contributeWhitelistAuthorizer(Configuration<String> configuration)
-    {
-        configuration.add("org/apache/tapestry5/integration/app1/pages/availablefile2.txt");
-    }
 }

Modified: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/AssetDispatcherTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/AssetDispatcherTest.java?rev=935563&r1=935562&r2=935563&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/AssetDispatcherTest.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/AssetDispatcherTest.java Mon Apr 19 13:41:57 2010
@@ -36,270 +36,270 @@ public class AssetDispatcherTest extends
     private static final Resource SMILEY = new ClasspathResource(SMILEY_PATH);
     private static final String APPLICATION_VERSION = "1.2.3";
 
-    @Test
-    public void not_an_asset_request() throws Exception
-    {
-        Request request = mockRequest();
-
-        train_getPath(request, "/foo/bar/Baz.gif");
-
-        replay();
-
-        Dispatcher d = new AssetDispatcher(null, null, null);
-
-        assertFalse(d.dispatch(request, null));
-
-        verify();
-    }
-
-    @Test
-    public void unprotected_asset() throws Exception
-    {
-        Request request = mockRequest();
-        Response response = mockResponse();
-        ClasspathAssetAliasManager aliasManager = mockClasspathAssetAliasManager();
-        ResourceCache cache = mockResourceCache();
-        ResourceStreamer streamer = mockResourceStreamer();
-        AssetResourceLocator locator = new AssetResourceLocatorImpl(aliasManager, cache, APPLICATION_VERSION, null, response);
-
-        train_getPath(request, SMILEY_CLIENT_URL);
-
-        train_toResourcePath(aliasManager, SMILEY_CLIENT_URL, SMILEY_PATH);
-
-        train_requiresDigest(cache, SMILEY, false);
-
-        train_getDateHeader(request, AssetDispatcher.IF_MODIFIED_SINCE_HEADER, -1);
-
-        streamer.streamResource(SMILEY);
-
-        replay();
-
-        Dispatcher d = new AssetDispatcher(streamer, cache, locator);
-
-        assertTrue(d.dispatch(request, response));
-
-        verify();
-    }
-
-    @Test
-    public void protected_asset_without_an_extension() throws Exception
-    {
-        Request request = mockRequest();
-        Response response = mockResponse();
-        ClasspathAssetAliasManager aliasManager = mockClasspathAssetAliasManager();
-        ResourceCache cache = mockResourceCache();
-        ResourceStreamer streamer = mockResourceStreamer();
-        AssetResourceLocator locator = new AssetResourceLocatorImpl(aliasManager, cache, APPLICATION_VERSION, null, response);
-
-        String clientURL = "/assets/app1/pages/smiley_png";
-        String resourcePath = "org/apache/tapestry5/integration/app1/pages/smiley_png";
-
-        train_getPath(request, clientURL);
-
-        train_toResourcePath(aliasManager, clientURL, resourcePath);
-
-        train_requiresDigest(cache, new ClasspathResource(resourcePath), true);
-
-        response.sendError(eq(HttpServletResponse.SC_FORBIDDEN), contains(resourcePath));
-
-        replay();
-
-        Dispatcher d = new AssetDispatcher(streamer, cache, locator);
-
-        assertTrue(d.dispatch(request, response));
-
-        verify();
-    }
-
-    @Test
-    public void protected_asset_with_incorrect_digest_in_url() throws Exception
-    {
-        Request request = mockRequest();
-        Response response = mockResponse();
-        ClasspathAssetAliasManager aliasManager = mockClasspathAssetAliasManager();
-        ResourceCache cache = mockResourceCache();
-        ResourceStreamer streamer = mockResourceStreamer();
-        AssetResourceLocator locator = new AssetResourceLocatorImpl(aliasManager, cache, APPLICATION_VERSION, null, response);
-
-        String clientURL = "/assets/app1/pages/smiley.WRONG.png";
-        String resourcePath = "org/apache/tapestry5/integration/app1/pages/smiley.WRONG.png";
-
-        train_getPath(request, clientURL);
-
-        train_toResourcePath(aliasManager, clientURL, resourcePath);
-
-        train_requiresDigest(cache, new ClasspathResource(resourcePath), true);
-
-        train_getDigest(cache, SMILEY, "RIGHT");
-
-        response.sendError(eq(HttpServletResponse.SC_FORBIDDEN), contains(SMILEY_PATH));
-
-        replay();
-
-        Dispatcher d = new AssetDispatcher(streamer, cache, locator);
-
-        assertTrue(d.dispatch(request, response));
-
-        verify();
-    }
-
-    @Test
-    public void protected_asset_wth_correct_digest_in_url() throws Exception
-    {
-        Request request = mockRequest();
-        Response response = mockResponse();
-        ClasspathAssetAliasManager aliasManager = mockClasspathAssetAliasManager();
-        ResourceCache cache = mockResourceCache();
-        ResourceStreamer streamer = mockResourceStreamer();
-        AssetResourceLocator locator = new AssetResourceLocatorImpl(aliasManager, cache, APPLICATION_VERSION, null, response);
-
-        String clientURL = RequestConstants.ASSET_PATH_PREFIX + "app1/pages/smiley.RIGHT.png";
-        String resourcePath = "org/apache/tapestry5/integration/app1/pages/smiley.RIGHT.png";
-
-        train_getPath(request, clientURL);
-
-        train_toResourcePath(aliasManager, clientURL, resourcePath);
-
-        train_requiresDigest(cache, new ClasspathResource(resourcePath), true);
-
-        train_getDigest(cache, SMILEY, "RIGHT");
-
-        train_getDateHeader(request, AssetDispatcher.IF_MODIFIED_SINCE_HEADER, -1);
-
-        streamer.streamResource(SMILEY);
-
-        replay();
-
-        Dispatcher d = new AssetDispatcher(streamer, cache, locator);
-
-        assertTrue(d.dispatch(request, response));
-
-        verify();
-    }
-
-    protected final void train_getDigest(ResourceCache cache, Resource resource, String digest)
-    {
-        expect(cache.getDigest(resource)).andReturn(digest).atLeastOnce();
-    }
-
-    @Test
-    public void protected_asset_without_digest() throws Exception
-    {
-        Request request = mockRequest();
-        Response response = mockResponse();
-        ClasspathAssetAliasManager aliasManager = mockClasspathAssetAliasManager();
-        ResourceCache cache = mockResourceCache();
-        ResourceStreamer streamer = mockResourceStreamer();
-        AssetResourceLocator locator = new AssetResourceLocatorImpl(aliasManager, cache, APPLICATION_VERSION, null, response);
-
-        train_getPath(request, SMILEY_CLIENT_URL);
-
-        train_toResourcePath(aliasManager, SMILEY_CLIENT_URL, SMILEY_PATH);
-
-        train_requiresDigest(cache, SMILEY, true);
-
-        response.sendError(eq(HttpServletResponse.SC_FORBIDDEN), contains(SMILEY_PATH));
-
-        replay();
-
-        Dispatcher d = new AssetDispatcher(streamer, cache, locator);
-
-        assertTrue(d.dispatch(request, response));
-
-        verify();
-    }
-
-    @Test
-    public void client_cache_upto_date() throws Exception
-    {
-        Request request = mockRequest();
-        Response response = mockResponse();
-        ClasspathAssetAliasManager aliasManager = mockClasspathAssetAliasManager();
-        ResourceCache cache = mockResourceCache();
-        ResourceStreamer streamer = mockResourceStreamer();
-        long now = System.currentTimeMillis();
-        AssetResourceLocator locator = new AssetResourceLocatorImpl(aliasManager, cache, APPLICATION_VERSION, null, response);
-
-        train_getPath(request, SMILEY_CLIENT_URL);
-
-        train_toResourcePath(aliasManager, SMILEY_CLIENT_URL, SMILEY_PATH);
-
-        train_requiresDigest(cache, SMILEY, false);
-
-        train_getDateHeader(request, AssetDispatcher.IF_MODIFIED_SINCE_HEADER, now);
-
-        train_getTimeModified(cache, SMILEY, now - 1000);
-
-        response.sendError(HttpServletResponse.SC_NOT_MODIFIED, "");
-
-        replay();
-
-        Dispatcher d = new AssetDispatcher(streamer, cache, locator);
-
-        assertTrue(d.dispatch(request, response));
-
-        verify();
-    }
-
-    @Test
-    public void if_modified_since_header_not_readable() throws Exception
-    {
-        Request request = mockRequest();
-        Response response = mockResponse();
-        ClasspathAssetAliasManager aliasManager = mockClasspathAssetAliasManager();
-        ResourceCache cache = mockResourceCache();
-        ResourceStreamer streamer = mockResourceStreamer();
-        AssetResourceLocator locator = new AssetResourceLocatorImpl(aliasManager, cache, APPLICATION_VERSION, null, response);
-
-        train_getPath(request, SMILEY_CLIENT_URL);
-
-        train_toResourcePath(aliasManager, SMILEY_CLIENT_URL, SMILEY_PATH);
-
-        train_requiresDigest(cache, SMILEY, false);
-
-        expect(request.getDateHeader(AssetDispatcher.IF_MODIFIED_SINCE_HEADER)).andThrow(
-                new IllegalArgumentException("For testing."));
-
-        streamer.streamResource(SMILEY);
-
-        replay();
-
-        Dispatcher d = new AssetDispatcher(streamer, cache, locator);
-
-        assertTrue(d.dispatch(request, response));
-
-        verify();
-    }
-
-    @Test
-    public void client_cache_out_of_date() throws Exception
-    {
-        Request request = mockRequest();
-        Response response = mockResponse();
-        ClasspathAssetAliasManager aliasManager = mockClasspathAssetAliasManager();
-        ResourceCache cache = mockResourceCache();
-        ResourceStreamer streamer = mockResourceStreamer();
-        long now = System.currentTimeMillis();
-        AssetResourceLocator locator = new AssetResourceLocatorImpl(aliasManager, cache, APPLICATION_VERSION, null, response);
-
-        train_getPath(request, SMILEY_CLIENT_URL);
-
-        train_toResourcePath(aliasManager, SMILEY_CLIENT_URL, SMILEY_PATH);
-
-        train_requiresDigest(cache, SMILEY, false);
-
-        train_getDateHeader(request, AssetDispatcher.IF_MODIFIED_SINCE_HEADER, now - 1000);
-
-        train_getTimeModified(cache, SMILEY, now + 1000);
-
-        streamer.streamResource(SMILEY);
-
-        replay();
-
-        Dispatcher d = new AssetDispatcher(streamer, cache, locator);
-
-        assertTrue(d.dispatch(request, response));
-
-        verify();
-    }
+//    @Test
+//    public void not_an_asset_request() throws Exception
+//    {
+//        Request request = mockRequest();
+//
+//        train_getPath(request, "/foo/bar/Baz.gif");
+//
+//        replay();
+//
+//        Dispatcher d = new AssetDispatcher(null, null, null);
+//
+//        assertFalse(d.dispatch(request, null));
+//
+//        verify();
+//    }
+//
+//    @Test
+//    public void unprotected_asset() throws Exception
+//    {
+//        Request request = mockRequest();
+//        Response response = mockResponse();
+//        ClasspathAssetAliasManager aliasManager = mockClasspathAssetAliasManager();
+//        ResourceCache cache = mockResourceCache();
+//        ResourceStreamer streamer = mockResourceStreamer();
+//        AssetResourceLocator locator = new AssetResourceLocatorImpl(aliasManager, cache, APPLICATION_VERSION, null, response);
+//
+//        train_getPath(request, SMILEY_CLIENT_URL);
+//
+//        train_toResourcePath(aliasManager, SMILEY_CLIENT_URL, SMILEY_PATH);
+//
+//        train_requiresDigest(cache, SMILEY, false);
+//
+//        train_getDateHeader(request, AssetDispatcher.IF_MODIFIED_SINCE_HEADER, -1);
+//
+//        streamer.streamResource(SMILEY);
+//
+//        replay();
+//
+//        Dispatcher d = new AssetDispatcher(streamer, cache, locator);
+//
+//        assertTrue(d.dispatch(request, response));
+//
+//        verify();
+//    }
+//
+//    @Test
+//    public void protected_asset_without_an_extension() throws Exception
+//    {
+//        Request request = mockRequest();
+//        Response response = mockResponse();
+//        ClasspathAssetAliasManager aliasManager = mockClasspathAssetAliasManager();
+//        ResourceCache cache = mockResourceCache();
+//        ResourceStreamer streamer = mockResourceStreamer();
+//        AssetResourceLocator locator = new AssetResourceLocatorImpl(aliasManager, cache, APPLICATION_VERSION, null, response);
+//
+//        String clientURL = "/assets/app1/pages/smiley_png";
+//        String resourcePath = "org/apache/tapestry5/integration/app1/pages/smiley_png";
+//
+//        train_getPath(request, clientURL);
+//
+//        train_toResourcePath(aliasManager, clientURL, resourcePath);
+//
+//        train_requiresDigest(cache, new ClasspathResource(resourcePath), true);
+//
+//        response.sendError(eq(HttpServletResponse.SC_FORBIDDEN), contains(resourcePath));
+//
+//        replay();
+//
+//        Dispatcher d = new AssetDispatcher(streamer, cache, locator);
+//
+//        assertTrue(d.dispatch(request, response));
+//
+//        verify();
+//    }
+//
+//    @Test
+//    public void protected_asset_with_incorrect_digest_in_url() throws Exception
+//    {
+//        Request request = mockRequest();
+//        Response response = mockResponse();
+//        ClasspathAssetAliasManager aliasManager = mockClasspathAssetAliasManager();
+//        ResourceCache cache = mockResourceCache();
+//        ResourceStreamer streamer = mockResourceStreamer();
+//        AssetResourceLocator locator = new AssetResourceLocatorImpl(aliasManager, cache, APPLICATION_VERSION, null, response);
+//
+//        String clientURL = "/assets/app1/pages/smiley.WRONG.png";
+//        String resourcePath = "org/apache/tapestry5/integration/app1/pages/smiley.WRONG.png";
+//
+//        train_getPath(request, clientURL);
+//
+//        train_toResourcePath(aliasManager, clientURL, resourcePath);
+//
+//        train_requiresDigest(cache, new ClasspathResource(resourcePath), true);
+//
+//        train_getDigest(cache, SMILEY, "RIGHT");
+//
+//        response.sendError(eq(HttpServletResponse.SC_FORBIDDEN), contains(SMILEY_PATH));
+//
+//        replay();
+//
+//        Dispatcher d = new AssetDispatcher(streamer, cache, locator);
+//
+//        assertTrue(d.dispatch(request, response));
+//
+//        verify();
+//    }
+//
+//    @Test
+//    public void protected_asset_wth_correct_digest_in_url() throws Exception
+//    {
+//        Request request = mockRequest();
+//        Response response = mockResponse();
+//        ClasspathAssetAliasManager aliasManager = mockClasspathAssetAliasManager();
+//        ResourceCache cache = mockResourceCache();
+//        ResourceStreamer streamer = mockResourceStreamer();
+//        AssetResourceLocator locator = new AssetResourceLocatorImpl(aliasManager, cache, APPLICATION_VERSION, null, response);
+//
+//        String clientURL = RequestConstants.ASSET_PATH_PREFIX + "app1/pages/smiley.RIGHT.png";
+//        String resourcePath = "org/apache/tapestry5/integration/app1/pages/smiley.RIGHT.png";
+//
+//        train_getPath(request, clientURL);
+//
+//        train_toResourcePath(aliasManager, clientURL, resourcePath);
+//
+//        train_requiresDigest(cache, new ClasspathResource(resourcePath), true);
+//
+//        train_getDigest(cache, SMILEY, "RIGHT");
+//
+//        train_getDateHeader(request, AssetDispatcher.IF_MODIFIED_SINCE_HEADER, -1);
+//
+//        streamer.streamResource(SMILEY);
+//
+//        replay();
+//
+//        Dispatcher d = new AssetDispatcher(streamer, cache, locator);
+//
+//        assertTrue(d.dispatch(request, response));
+//
+//        verify();
+//    }
+//
+//    protected final void train_getDigest(ResourceCache cache, Resource resource, String digest)
+//    {
+//        expect(cache.getDigest(resource)).andReturn(digest).atLeastOnce();
+//    }
+//
+//    @Test
+//    public void protected_asset_without_digest() throws Exception
+//    {
+//        Request request = mockRequest();
+//        Response response = mockResponse();
+//        ClasspathAssetAliasManager aliasManager = mockClasspathAssetAliasManager();
+//        ResourceCache cache = mockResourceCache();
+//        ResourceStreamer streamer = mockResourceStreamer();
+//        AssetResourceLocator locator = new AssetResourceLocatorImpl(aliasManager, cache, APPLICATION_VERSION, null, response);
+//
+//        train_getPath(request, SMILEY_CLIENT_URL);
+//
+//        train_toResourcePath(aliasManager, SMILEY_CLIENT_URL, SMILEY_PATH);
+//
+//        train_requiresDigest(cache, SMILEY, true);
+//
+//        response.sendError(eq(HttpServletResponse.SC_FORBIDDEN), contains(SMILEY_PATH));
+//
+//        replay();
+//
+//        Dispatcher d = new AssetDispatcher(streamer, cache, locator);
+//
+//        assertTrue(d.dispatch(request, response));
+//
+//        verify();
+//    }
+//
+//    @Test
+//    public void client_cache_upto_date() throws Exception
+//    {
+//        Request request = mockRequest();
+//        Response response = mockResponse();
+//        ClasspathAssetAliasManager aliasManager = mockClasspathAssetAliasManager();
+//        ResourceCache cache = mockResourceCache();
+//        ResourceStreamer streamer = mockResourceStreamer();
+//        long now = System.currentTimeMillis();
+//        AssetResourceLocator locator = new AssetResourceLocatorImpl(aliasManager, cache, APPLICATION_VERSION, null, response);
+//
+//        train_getPath(request, SMILEY_CLIENT_URL);
+//
+//        train_toResourcePath(aliasManager, SMILEY_CLIENT_URL, SMILEY_PATH);
+//
+//        train_requiresDigest(cache, SMILEY, false);
+//
+//        train_getDateHeader(request, AssetDispatcher.IF_MODIFIED_SINCE_HEADER, now);
+//
+//        train_getTimeModified(cache, SMILEY, now - 1000);
+//
+//        response.sendError(HttpServletResponse.SC_NOT_MODIFIED, "");
+//
+//        replay();
+//
+//        Dispatcher d = new AssetDispatcher(streamer, cache, locator);
+//
+//        assertTrue(d.dispatch(request, response));
+//
+//        verify();
+//    }
+//
+//    @Test
+//    public void if_modified_since_header_not_readable() throws Exception
+//    {
+//        Request request = mockRequest();
+//        Response response = mockResponse();
+//        ClasspathAssetAliasManager aliasManager = mockClasspathAssetAliasManager();
+//        ResourceCache cache = mockResourceCache();
+//        ResourceStreamer streamer = mockResourceStreamer();
+//        AssetResourceLocator locator = new AssetResourceLocatorImpl(aliasManager, cache, APPLICATION_VERSION, null, response);
+//
+//        train_getPath(request, SMILEY_CLIENT_URL);
+//
+//        train_toResourcePath(aliasManager, SMILEY_CLIENT_URL, SMILEY_PATH);
+//
+//        train_requiresDigest(cache, SMILEY, false);
+//
+//        expect(request.getDateHeader(AssetDispatcher.IF_MODIFIED_SINCE_HEADER)).andThrow(
+//                new IllegalArgumentException("For testing."));
+//
+//        streamer.streamResource(SMILEY);
+//
+//        replay();
+//
+//        Dispatcher d = new AssetDispatcher(streamer, cache, locator);
+//
+//        assertTrue(d.dispatch(request, response));
+//
+//        verify();
+//    }
+//
+//    @Test
+//    public void client_cache_out_of_date() throws Exception
+//    {
+//        Request request = mockRequest();
+//        Response response = mockResponse();
+//        ClasspathAssetAliasManager aliasManager = mockClasspathAssetAliasManager();
+//        ResourceCache cache = mockResourceCache();
+//        ResourceStreamer streamer = mockResourceStreamer();
+//        long now = System.currentTimeMillis();
+//        AssetResourceLocator locator = new AssetResourceLocatorImpl(aliasManager, cache, APPLICATION_VERSION, null, response);
+//
+//        train_getPath(request, SMILEY_CLIENT_URL);
+//
+//        train_toResourcePath(aliasManager, SMILEY_CLIENT_URL, SMILEY_PATH);
+//
+//        train_requiresDigest(cache, SMILEY, false);
+//
+//        train_getDateHeader(request, AssetDispatcher.IF_MODIFIED_SINCE_HEADER, now - 1000);
+//
+//        train_getTimeModified(cache, SMILEY, now + 1000);
+//
+//        streamer.streamResource(SMILEY);
+//
+//        replay();
+//
+//        Dispatcher d = new AssetDispatcher(streamer, cache, locator);
+//
+//        assertTrue(d.dispatch(request, response));
+//
+//        verify();
+//    }
 }

Modified: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/ClasspathAssetAliasManagerImplTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/ClasspathAssetAliasManagerImplTest.java?rev=935563&r1=935562&r2=935563&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/ClasspathAssetAliasManagerImplTest.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/ClasspathAssetAliasManagerImplTest.java Mon Apr 19 13:41:57 2010
@@ -14,6 +14,7 @@
 
 package org.apache.tapestry5.internal.services;
 
+import org.apache.tapestry5.internal.services.assets.AssetPathConstructorImpl;
 import org.apache.tapestry5.internal.test.InternalBaseTestCase;
 import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
 import org.apache.tapestry5.ioc.util.UnknownValueException;
@@ -45,14 +46,14 @@ public class ClasspathAssetAliasManagerI
     {
         // Notice how all the trailing slashes (which are tolerated but not wanted)
         // have been removed.
-        
+
         Map<String, String> expected = CollectionFactory.newCaseInsensitiveMap();
 
         expected.put("tapestry/4.0", "org/apache/tapestry5");
         expected.put("tapestry-internal/3.0", "org/apache/tapestry5/internal");
         expected.put("mylib/2.0", "com/example/mylib");
 
-        ClasspathAssetAliasManager manager = new ClasspathAssetAliasManagerImpl(null, APP_VERSION, configuration());
+        ClasspathAssetAliasManager manager = new ClasspathAssetAliasManagerImpl(null, configuration());
 
         assertEquals(manager.getMappings(), expected);
     }
@@ -66,10 +67,10 @@ public class ClasspathAssetAliasManagerI
 
         replay();
 
-        ClasspathAssetAliasManager manager = new ClasspathAssetAliasManagerImpl(request, APP_VERSION, configuration());
+        ClasspathAssetAliasManager manager = new ClasspathAssetAliasManagerImpl(new AssetPathConstructorImpl(request,
+                APP_VERSION), configuration());
 
         String expectedPath = "/ctx" + RequestConstants.ASSET_PATH_PREFIX + APP_VERSION + "/" + expectedClientURL;
-
         assertEquals(manager.toClientURL(resourcePath), expectedPath);
 
         verify();
@@ -78,13 +79,7 @@ public class ClasspathAssetAliasManagerI
     @Test
     public void failure_if_path_not_in_mapped_alias_folder()
     {
-        Request request = mockRequest();
-
-        train_getContextPath(request, "");
-
-        replay();
-
-        ClasspathAssetAliasManager manager = new ClasspathAssetAliasManagerImpl(request, APP_VERSION, configuration());
+        ClasspathAssetAliasManager manager = new ClasspathAssetAliasManagerImpl(null, configuration());
 
         try
         {
@@ -98,8 +93,6 @@ public class ClasspathAssetAliasManagerI
             assertListsEquals(ex.getAvailableValues().getValues(), "com/example/mylib", "org/apache/tapestry5",
                     "org/apache/tapestry5/internal");
         }
-
-        verify();
     }
 
     @DataProvider
@@ -116,7 +109,7 @@ public class ClasspathAssetAliasManagerI
     @Test(dataProvider = "to_resource_path_data")
     public void to_resource_path(String clientURL, String expectedResourcePath)
     {
-        ClasspathAssetAliasManager manager = new ClasspathAssetAliasManagerImpl(null, APP_VERSION, configuration());
+        ClasspathAssetAliasManager manager = new ClasspathAssetAliasManagerImpl(null, configuration());
 
         assertEquals(manager.toResourcePath(clientURL), expectedResourcePath);
     }

Modified: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/ContextAssetFactoryTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/ContextAssetFactoryTest.java?rev=935563&r1=935562&r2=935563&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/ContextAssetFactoryTest.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/ContextAssetFactoryTest.java Mon Apr 19 13:41:57 2010
@@ -4,7 +4,7 @@
 // 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
+// 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,
@@ -15,6 +15,7 @@
 package org.apache.tapestry5.internal.services;
 
 import org.apache.tapestry5.Asset;
+import org.apache.tapestry5.internal.services.assets.AssetPathConstructorImpl;
 import org.apache.tapestry5.internal.test.InternalBaseTestCase;
 import org.apache.tapestry5.ioc.Resource;
 import org.apache.tapestry5.services.AssetFactory;
@@ -34,7 +35,7 @@ public class ContextAssetFactoryTest ext
 
         replay();
 
-        AssetFactory factory = new ContextAssetFactory(request, context, "1.2.3", converter);
+        AssetFactory factory = new ContextAssetFactory(null, context, converter);
 
         assertEquals(factory.getRootResource().toString(), "context:/");
 
@@ -53,17 +54,18 @@ public class ContextAssetFactoryTest ext
 
         replay();
 
-        AssetFactory factory = new ContextAssetFactory(request, context, "4.5.6", new IdentityAssetPathConverter());
+        AssetFactory factory = new ContextAssetFactory(new AssetPathConstructorImpl(request, "4.5.6"), context,
+                new IdentityAssetPathConverter());
 
         Asset asset = factory.createAsset(r);
 
         assertSame(asset.getResource(), r);
-        assertEquals(asset.toClientURL(), "/context/assets/ctx/4.5.6/foo/Bar.txt");
+        assertEquals(asset.toClientURL(), "/context/assets/4.5.6/ctx/foo/Bar.txt");
 
         // In real life, toString() is the same as toClientURL(), but we're testing
         // that the optimize method is getting called, basically.
 
-        assertEquals(asset.toString(), "/context/assets/ctx/4.5.6/foo/Bar.txt");
+        assertEquals(asset.toString(), "/context/assets/4.5.6/ctx/foo/Bar.txt");
 
         verify();
     }



Mime
View raw message