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 2006/12/05 18:35:14 UTC

svn commit: r482719 [2/4] - in /tapestry/tapestry5/tapestry-core/trunk/src: main/java/org/apache/tapestry/ main/java/org/apache/tapestry/annotations/ main/java/org/apache/tapestry/corelib/base/ main/java/org/apache/tapestry/corelib/components/ main/jav...

Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ResourceCacheImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ResourceCacheImpl.java?view=auto&rev=482719
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ResourceCacheImpl.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ResourceCacheImpl.java Tue Dec  5 09:35:05 2006
@@ -0,0 +1,116 @@
+// Copyright 2006 The Apache Software Foundation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry.internal.services;
+
+import static org.apache.tapestry.ioc.internal.util.CollectionFactory.newThreadSafeMap;
+
+import java.net.URL;
+import java.util.Map;
+
+import org.apache.tapestry.events.UpdateListener;
+import org.apache.tapestry.internal.event.InvalidationEventHubImpl;
+import org.apache.tapestry.internal.util.URLChangeTracker;
+import org.apache.tapestry.ioc.Resource;
+import org.apache.tapestry.services.ResourceDigestGenerator;
+
+public class ResourceCacheImpl extends InvalidationEventHubImpl implements ResourceCache,
+        UpdateListener
+{
+    private final URLChangeTracker _tracker;
+
+    private final ResourceDigestGenerator _digestGenerator;
+
+    private final Map<Resource, Cached> _cache = newThreadSafeMap();
+
+    final static long MISSING_RESOURCE_TIME_MODIFIED = -1l;
+
+    private class Cached
+    {
+        final boolean _requiresDigest;
+
+        final String _digest;
+
+        final long _timeModified;
+
+        Cached(Resource resource)
+        {
+            _requiresDigest = _digestGenerator.requiresDigest(resource.getPath());
+
+            URL url = resource.toURL();
+
+            // The url may be null when a request for a protected asset arrives, because the
+            // Resource initially is for the file with the digest incorporated into the path, which
+            // means
+            // no underlying file exists. Subsequently, we'll strip out the digest and resolve
+            // to an actual resource.
+
+            _digest = (_requiresDigest && url != null) ? _digestGenerator.generateDigest(url)
+                    : null;
+
+            _timeModified = url != null ? _tracker.add(url) : MISSING_RESOURCE_TIME_MODIFIED;
+        }
+    }
+
+    public ResourceCacheImpl(final ResourceDigestGenerator digestGenerator)
+    {
+        this(digestGenerator, new URLChangeTracker());
+    }
+
+    ResourceCacheImpl(final ResourceDigestGenerator digestGenerator, URLChangeTracker tracker)
+    {
+        _digestGenerator = digestGenerator;
+        _tracker = tracker;
+    }
+
+    public void checkForUpdates()
+    {
+        if (_tracker.containsChanges())
+        {
+            _cache.clear();
+            _tracker.clear();
+
+            fireInvalidationEvent();
+        }
+    }
+
+    private Cached get(Resource resource)
+    {
+        Cached result = _cache.get(resource);
+
+        if (result == null)
+        {
+            result = new Cached(resource);
+            _cache.put(resource, result);
+        }
+
+        return result;
+    }
+
+    public String getDigest(Resource resource)
+    {
+        return get(resource)._digest;
+    }
+
+    public long getTimeModified(Resource resource)
+    {
+        return get(resource)._timeModified;
+    }
+
+    public boolean requiresDigest(Resource resource)
+    {
+        return get(resource)._requiresDigest;
+    }
+
+}

Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ResourceDigestGeneratorImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ResourceDigestGeneratorImpl.java?view=auto&rev=482719
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ResourceDigestGeneratorImpl.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ResourceDigestGeneratorImpl.java Tue Dec  5 09:35:05 2006
@@ -0,0 +1,87 @@
+// Copyright 2006 The Apache Software Foundation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry.internal.services;
+
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.security.MessageDigest;
+
+import org.apache.commons.codec.binary.Hex;
+import org.apache.tapestry.internal.TapestryUtils;
+import org.apache.tapestry.services.ResourceDigestGenerator;
+
+/**
+ * Implementation of {@link ResourceDigestGenerator} that generates MD5 digests.
+ * Available as service:tapestry.ResourceDigestGenerator or
+ * infrastructure:ResourceDigestGenerator.
+ */
+public class ResourceDigestGeneratorImpl implements ResourceDigestGenerator
+{
+    private static final int BUFFER_SIZE = 5000;
+
+    public String generateDigest(URL url)
+    {
+        InputStream stream = null;
+
+        try
+        {
+            MessageDigest digest = MessageDigest.getInstance("MD5");
+
+            stream = new BufferedInputStream(url.openStream());
+
+            digestStream(digest, stream);
+
+            stream.close();
+            stream = null;
+
+            byte[] bytes = digest.digest();
+            char[] encoded = Hex.encodeHex(bytes);
+
+            return new String(encoded);
+        }
+        catch (Exception ex)
+        {
+            throw new RuntimeException(ex);
+        }
+        finally
+        {
+            TapestryUtils.close(stream);
+        }
+    }
+
+    private void digestStream(MessageDigest digest, InputStream stream) throws IOException
+    {
+        byte[] buffer = new byte[BUFFER_SIZE];
+
+        while (true)
+        {
+            int length = stream.read(buffer);
+
+            if (length < 0)
+                return;
+
+            digest.update(buffer, 0, length);
+        }
+    }
+
+    /** Current implementation: any path that ends with ".class", but this will expand in the future. */
+    public boolean requiresDigest(String path)
+    {
+        return path.endsWith(".class");
+    }
+
+}

Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ResourceStreamer.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ResourceStreamer.java?view=auto&rev=482719
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ResourceStreamer.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ResourceStreamer.java Tue Dec  5 09:35:05 2006
@@ -0,0 +1,30 @@
+// Copyright 2006 The Apache Software Foundation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry.internal.services;
+
+import java.io.IOException;
+
+import org.apache.tapestry.ioc.Resource;
+import org.apache.tapestry.ioc.internal.util.ClasspathResource;
+
+/**
+ * Responsible for streaming the contents of a resource to the client. The {@link Resource} to
+ * stream is almost always a {@link ClasspathResource}.
+ */
+public interface ResourceStreamer
+{
+    /** Streams the content of the resource to the client. */
+    void streamResource(Resource resource) throws IOException;
+}

Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ResourceStreamerImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ResourceStreamerImpl.java?view=auto&rev=482719
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ResourceStreamerImpl.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ResourceStreamerImpl.java Tue Dec  5 09:35:05 2006
@@ -0,0 +1,97 @@
+// Copyright 2006 The Apache Software Foundation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry.internal.services;
+
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.URL;
+import java.net.URLConnection;
+
+import org.apache.tapestry.internal.TapestryUtils;
+import org.apache.tapestry.ioc.Resource;
+import org.apache.tapestry.services.Response;
+
+public class ResourceStreamerImpl implements ResourceStreamer
+{
+    private final Response _response;
+
+    private final int _bufferSize = 1000;
+
+    // One year, in milliseconds
+
+    final static long EXPIRE_DELTA = 31536000000l;
+
+    public ResourceStreamerImpl(final Response response)
+    {
+        _response = response;
+    }
+
+    public void streamResource(Resource resource) throws IOException
+    {
+        URL url = resource.toURL();
+
+        URLConnection connection = url.openConnection();
+
+        int contentLength = connection.getContentLength();
+
+        if (contentLength >= 0)
+            _response.setContentLength(contentLength);
+
+        // Could get this from the ResourceCache, but can't imagine
+        // it's very expensive.
+
+        long lastModified = connection.getLastModified();
+
+        _response.setDateHeader("Last-Modified", lastModified);
+        _response.setDateHeader("Expires", lastModified + EXPIRE_DELTA);
+
+        // TODO: content type
+
+        InputStream is = null;
+
+        try
+        {
+            connection.connect();
+
+            is = new BufferedInputStream(connection.getInputStream());
+
+            OutputStream os = _response.getOutputStream();
+
+            byte[] buffer = new byte[_bufferSize];
+
+            while (true)
+            {
+                int length = is.read(buffer);
+
+                if (length < 0)
+                    break;
+
+                os.write(buffer, 0, length);
+            }
+
+            is.close();
+            is = null;
+
+            os.flush();
+        }
+        finally
+        {
+            TapestryUtils.close(is);
+        }
+
+    }
+}

Copied: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ResponseImpl.java (from r480115, tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/WebResponseImpl.java)
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ResponseImpl.java?view=diff&rev=482719&p1=tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/WebResponseImpl.java&r1=480115&p2=tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ResponseImpl.java&r2=482719
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/WebResponseImpl.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ResponseImpl.java Tue Dec  5 09:35:05 2006
@@ -12,45 +12,71 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package org.apache.tapestry.internal.services;
-
-import java.io.IOException;
-import java.io.PrintWriter;
-
-import javax.servlet.http.HttpServletResponse;
-
-import org.apache.tapestry.services.WebResponse;
-
-/**
- * 
- */
-public class WebResponseImpl implements WebResponse
-{
-    private final HttpServletResponse _response;
-
-    public WebResponseImpl(HttpServletResponse response)
-    {
-        _response = response;
-    }
-
-    public PrintWriter getPrintWriter() throws IOException
-    {
-        return _response.getWriter();
-    }
-
-    public String encodeURL(String URL)
-    {
-        return _response.encodeURL(URL);
-    }
-
-    public String encodeRedirectURL(String URL)
-    {
-        return _response.encodeRedirectURL(URL);
-    }
-
-    public void sendRedirect(String URL) throws IOException
-    {
-        _response.sendRedirect(URL);
-    }
-
-}
+package org.apache.tapestry.internal.services;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.tapestry.ioc.internal.util.Defense;
+import org.apache.tapestry.services.Response;
+
+/**
+ * Implementation of {@link Response} that wraps around an underlying {@link HttpServletResponse}.
+ */
+public class ResponseImpl implements Response
+{
+    private final HttpServletResponse _response;
+
+    public ResponseImpl(HttpServletResponse response)
+    {
+        Defense.notNull(response, "response");
+
+        _response = response;
+    }
+
+    public PrintWriter getPrintWriter() throws IOException
+    {
+        return _response.getWriter();
+    }
+
+    public String encodeURL(String URL)
+    {
+        return _response.encodeURL(URL);
+    }
+
+    public String encodeRedirectURL(String URL)
+    {
+        return _response.encodeRedirectURL(URL);
+    }
+
+    public void sendRedirect(String URL) throws IOException
+    {
+        _response.sendRedirect(URL);
+    }
+
+    public OutputStream getOutputStream() throws IOException
+    {
+        // TODO: Set content type before getting the stream.
+
+        return _response.getOutputStream();
+    }
+
+    public void sendError(int sc, String message) throws IOException
+    {
+        _response.sendError(sc, message);
+    }
+
+    public void setContentLength(int length)
+    {
+        _response.setContentLength(length);
+    }
+
+    public void setDateHeader(String name, long date)
+    {
+        _response.setDateHeader(name, date);
+    }
+
+}

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ServicesMessages.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ServicesMessages.java?view=diff&rev=482719&r1=482718&r2=482719
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ServicesMessages.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ServicesMessages.java Tue Dec  5 09:35:05 2006
@@ -260,4 +260,9 @@
     {
         return MESSAGES.format("asset-does-not-exist", resource);
     }
+
+    static String wrongAssetDigest(Resource resource)
+    {
+        return MESSAGES.format("wrong-asset-digest", resource.getPath());
+    }
 }

Copied: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/SessionImpl.java (from r480115, tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/WebSessionImpl.java)
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/SessionImpl.java?view=diff&rev=482719&p1=tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/WebSessionImpl.java&r1=480115&p2=tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/SessionImpl.java&r2=482719
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/WebSessionImpl.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/SessionImpl.java Tue Dec  5 09:35:05 2006
@@ -12,62 +12,62 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package org.apache.tapestry.internal.services;
-
+package org.apache.tapestry.internal.services;
+
 import static org.apache.tapestry.ioc.internal.util.CollectionFactory.newList;
-
-import java.util.Collections;
-import java.util.Enumeration;
-import java.util.List;
-
-import javax.servlet.http.HttpSession;
-
+
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.List;
+
+import javax.servlet.http.HttpSession;
+
 import org.apache.tapestry.ioc.internal.util.InternalUtils;
-import org.apache.tapestry.services.WebSession;
-
-/**
- * A thin wrapper around {@link HttpSession}.
- */
-public class WebSessionImpl implements WebSession
-{
-    private final HttpSession _session;
-
-    public WebSessionImpl(final HttpSession session)
-    {
-        _session = session;
-    }
-
-    public Object getAttribute(String name)
-    {
-        return _session.getAttribute(name);
-    }
-
-    public List<String> getAttributeNames()
-    {
-        return InternalUtils.toList(_session.getAttributeNames());
-    }
-
-    public void setAttribute(String name, Object value)
-    {
-        _session.setAttribute(name, value);
-    }
-
-    public List<String> getAttributeNames(String prefix)
-    {
-        List<String> result = newList();
-
-        Enumeration e = _session.getAttributeNames();
-        while (e.hasMoreElements())
-        {
-            String name = (String) e.nextElement();
-
-            if (name.startsWith(prefix))
-                result.add(name);
-        }
-
-        Collections.sort(result);
-
-        return result;
-    }
-
-}
+import org.apache.tapestry.services.Session;
+
+/**
+ * A thin wrapper around {@link HttpSession}.
+ */
+public class SessionImpl implements Session
+{
+    private final HttpSession _session;
+
+    public SessionImpl(final HttpSession session)
+    {
+        _session = session;
+    }
+
+    public Object getAttribute(String name)
+    {
+        return _session.getAttribute(name);
+    }
+
+    public List<String> getAttributeNames()
+    {
+        return InternalUtils.toList(_session.getAttributeNames());
+    }
+
+    public void setAttribute(String name, Object value)
+    {
+        _session.setAttribute(name, value);
+    }
+
+    public List<String> getAttributeNames(String prefix)
+    {
+        List<String> result = newList();
+
+        Enumeration e = _session.getAttributeNames();
+        while (e.hasMoreElements())
+        {
+            String name = (String) e.nextElement();
+
+            if (name.startsWith(prefix))
+                result.add(name);
+        }
+
+        Collections.sort(result);
+
+        return result;
+    }
+
+}

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/SessionPersistentFieldStrategy.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/SessionPersistentFieldStrategy.java?view=diff&rev=482719&r1=482718&r2=482719
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/SessionPersistentFieldStrategy.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/SessionPersistentFieldStrategy.java Tue Dec  5 09:35:05 2006
@@ -23,11 +23,11 @@
 
 import org.apache.tapestry.services.PersistentFieldChange;
 import org.apache.tapestry.services.PersistentFieldStrategy;
-import org.apache.tapestry.services.WebRequest;
-import org.apache.tapestry.services.WebSession;
+import org.apache.tapestry.services.Request;
+import org.apache.tapestry.services.Session;
 
 /**
- * A strategy for storing persistent page properties into the {@link WebSession session}.
+ * A strategy for storing persistent page properties into the {@link Session session}.
  * <p>
  * Builds attribute names as:
  * <code>state:<em>page-name</em>:<em>component-id</em>:<em>field-name</em></code>
@@ -41,16 +41,16 @@
      */
     public static final String PREFIX = "state:";
 
-    private final WebRequest _request;
+    private final Request _request;
 
-    public SessionPersistentFieldStrategy(final WebRequest request)
+    public SessionPersistentFieldStrategy(final Request request)
     {
         _request = request;
     }
 
     public Collection<PersistentFieldChange> gatherFieldChanges(String pageName)
     {
-        WebSession session = _request.getSession(false);
+        Session session = _request.getSession(false);
 
         if (session == null)
             return Collections.emptyList();
@@ -96,7 +96,7 @@
         builder.append(':');
         builder.append(fieldName);
 
-        WebSession session = _request.getSession(true);
+        Session session = _request.getSession(true);
 
         session.setAttribute(builder.toString(), newValue);
     }

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/StaticFilesFilter.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/StaticFilesFilter.java?view=diff&rev=482719&r1=482718&r2=482719
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/StaticFilesFilter.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/StaticFilesFilter.java Tue Dec  5 09:35:05 2006
@@ -17,11 +17,11 @@
 import java.io.IOException;
 import java.net.URL;
 
-import org.apache.tapestry.services.WebContext;
-import org.apache.tapestry.services.WebRequest;
-import org.apache.tapestry.services.WebRequestFilter;
-import org.apache.tapestry.services.WebRequestHandler;
-import org.apache.tapestry.services.WebResponse;
+import org.apache.tapestry.services.Context;
+import org.apache.tapestry.services.Request;
+import org.apache.tapestry.services.RequestFilter;
+import org.apache.tapestry.services.RequestHandler;
+import org.apache.tapestry.services.Response;
 
 /**
  * Identifies requests that are for actual resource files in the context. For those, Tapestry allows
@@ -29,16 +29,16 @@
  * 
  * 
  */
-public class StaticFilesFilter implements WebRequestFilter
+public class StaticFilesFilter implements RequestFilter
 {
-    private final WebContext _context;
+    private final Context _context;
 
-    public StaticFilesFilter(WebContext context)
+    public StaticFilesFilter(Context context)
     {
         _context = context;
     }
 
-    public boolean service(WebRequest request, WebResponse response, WebRequestHandler handler)
+    public boolean service(Request request, Response response, RequestHandler handler)
             throws IOException
     {
         String path = request.getPath();

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/test/InternalBaseTestCase.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/test/InternalBaseTestCase.java?view=diff&rev=482719&r1=482718&r2=482719
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/test/InternalBaseTestCase.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/test/InternalBaseTestCase.java Tue Dec  5 09:35:05 2006
@@ -23,6 +23,7 @@
 
 import org.apache.commons.logging.Log;
 import org.apache.tapestry.ComponentResources;
+import org.apache.tapestry.events.InvalidationListener;
 import org.apache.tapestry.internal.InternalComponentResources;
 import org.apache.tapestry.internal.parser.ComponentTemplate;
 import org.apache.tapestry.internal.parser.TemplateToken;
@@ -33,6 +34,8 @@
 import org.apache.tapestry.internal.services.PageLoader;
 import org.apache.tapestry.internal.services.PagePool;
 import org.apache.tapestry.internal.services.RequestPageCache;
+import org.apache.tapestry.internal.services.ResourceCache;
+import org.apache.tapestry.internal.services.ResourceStreamer;
 import org.apache.tapestry.internal.services.TemplateParser;
 import org.apache.tapestry.internal.structure.ComponentPageElement;
 import org.apache.tapestry.internal.structure.Page;
@@ -51,7 +54,7 @@
 import org.apache.tapestry.services.ComponentClassResolver;
 import org.apache.tapestry.services.Infrastructure;
 import org.apache.tapestry.services.TapestryModule;
-import org.apache.tapestry.services.WebRequest;
+import org.apache.tapestry.services.Request;
 import org.apache.tapestry.test.TapestryTestCase;
 import org.easymock.EasyMock;
 import org.testng.annotations.AfterMethod;
@@ -199,7 +202,7 @@
         expect(element.getNestedId()).andReturn(nestedId).atLeastOnce();
     }
 
-    protected final void train_getContextPath(WebRequest request, String contextPath)
+    protected final void train_getContextPath(Request request, String contextPath)
     {
         expect(request.getContextPath()).andReturn(contextPath).atLeastOnce();
     }
@@ -307,10 +310,10 @@
         expect(model.getEmbeddedComponentIds()).andReturn(Arrays.asList(ids));
     }
 
-    protected void train_getTemplate(ComponentTemplateSource templateSource, String className,
+    protected void train_getTemplate(ComponentTemplateSource templateSource, ComponentModel model,
             Locale locale, ComponentTemplate template)
     {
-        expect(templateSource.getTemplate(className, locale)).andReturn(template);
+        expect(templateSource.getTemplate(model, locale)).andReturn(template);
     }
 
     protected final void train_getComponentModel(ComponentResources component, ComponentModel model)
@@ -375,5 +378,31 @@
     protected final void train_getRootComponent(Page page, Component component)
     {
         expect(page.getRootComponent()).andReturn(component).atLeastOnce();
+    }
+
+    protected final ResourceCache newResourceCache()
+    {
+        return newMock(ResourceCache.class);
+    }
+
+    protected final void train_requiresDigest(ResourceCache cache, Resource resource,
+            boolean requiresChecksum)
+    {
+        expect(cache.requiresDigest(resource)).andReturn(requiresChecksum);
+    }
+
+    protected InvalidationListener newInvalidationListener()
+    {
+        return newMock(InvalidationListener.class);
+    }
+
+    protected void train_getTimeModified(ResourceCache cache, Resource resource, long timeModified)
+    {
+        expect(cache.getTimeModified(resource)).andReturn(timeModified).atLeastOnce();
+    }
+
+    protected final ResourceStreamer newResourceStreamer()
+    {
+        return newMock(ResourceStreamer.class);
     }
 }

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/util/URLChangeTracker.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/util/URLChangeTracker.java?view=diff&rev=482719&r1=482718&r2=482719
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/util/URLChangeTracker.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/util/URLChangeTracker.java Tue Dec  5 09:35:05 2006
@@ -14,7 +14,7 @@
 
 package org.apache.tapestry.internal.util;
 
-import static org.apache.tapestry.ioc.internal.util.CollectionFactory.newMap;
+import static org.apache.tapestry.ioc.internal.util.CollectionFactory.newThreadSafeMap;
 
 import java.io.IOException;
 import java.net.URL;
@@ -27,27 +27,32 @@
  */
 public class URLChangeTracker
 {
-    private final Map<URL, Long> _urlToTimestamp = newMap();
+    private final Map<URL, Long> _urlToTimestamp = newThreadSafeMap();
 
     /**
-     * Stores a new URL into the tracker. The last modified timestamp for the URL is accessed and
-     * stored for later checking. May replacing an existing URL and timestamp.
+     * Stores a new URL into the tracker, or returns the previous time stamp for a previously added
+     * URL.
      * 
      * @param url
      *            of the resource to add
+     * @return the current timestamp for the URL
      */
-
-    public synchronized void add(URL url)
+    public long add(URL url)
     {
+        if (_urlToTimestamp.containsKey(url))
+            return _urlToTimestamp.get(url);
+
         long timestamp = readTimestamp(url);
 
         _urlToTimestamp.put(url, timestamp);
+
+        return timestamp;
     }
 
     /**
      * Clears all URL and timestamp data stored in the tracker.
      */
-    public synchronized void clear()
+    public void clear()
     {
         _urlToTimestamp.clear();
     }
@@ -56,10 +61,14 @@
      * Re-acquires the last updated timestamp for each URL and returns true if any timestamp has
      * changed.
      */
-    public synchronized boolean containsChanges()
+    public boolean containsChanges()
     {
         boolean result = false;
 
+        // This code would be highly suspect if this method was expected to be invoked
+        // concurrently, but CheckForUpdatesFilter ensures that it will be invoked
+        // synchronously.
+        
         for (Map.Entry<URL, Long> entry : _urlToTimestamp.entrySet())
         {
             long newTimestamp = readTimestamp(entry.getKey());

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/ApplicationGlobals.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/ApplicationGlobals.java?view=diff&rev=482719&r1=482718&r2=482719
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/ApplicationGlobals.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/ApplicationGlobals.java Tue Dec  5 09:35:05 2006
@@ -27,7 +27,7 @@
 
     ServletContext getServletContext();
 
-    void store(WebContext context);
+    void store(Context context);
 
-    WebContext getWebContext();
+    Context getContext();
 }

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/ApplicationInitializer.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/ApplicationInitializer.java?view=diff&rev=482719&r1=482718&r2=482719
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/ApplicationInitializer.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/ApplicationInitializer.java Tue Dec  5 09:35:05 2006
@@ -22,5 +22,5 @@
  */
 public interface ApplicationInitializer
 {
-    void initializeApplication(WebContext context);
+    void initializeApplication(Context context);
 }

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/ApplicationInitializerFilter.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/ApplicationInitializerFilter.java?view=diff&rev=482719&r1=482718&r2=482719
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/ApplicationInitializerFilter.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/ApplicationInitializerFilter.java Tue Dec  5 09:35:05 2006
@@ -21,5 +21,5 @@
  */
 public interface ApplicationInitializerFilter
 {
-    void initializeApplication(WebContext context, ApplicationInitializer initializer);
+    void initializeApplication(Context context, ApplicationInitializer initializer);
 }

Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/ClasspathAssetAliasManager.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/ClasspathAssetAliasManager.java?view=auto&rev=482719
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/ClasspathAssetAliasManager.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/ClasspathAssetAliasManager.java Tue Dec  5 09:35:05 2006
@@ -0,0 +1,34 @@
+// Copyright 2006 The Apache Software Foundation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry.services;
+
+public interface ClasspathAssetAliasManager
+{
+    /**
+     * Takes a resource path to a classpath resource and adds the asset path prefix to the path. May
+     * also convert part of the path to an alias (based on the manager's configuration).
+     * 
+     * @param resourcePath
+     *            resource path on the classpath (with no leading slash)
+     * @return URL ready to send to the client
+     */
+    String toClientURL(String resourcePath);
+
+    /**
+     * Reverses {@link #toClientURL(String)}, stripping off the asset prefix, and re-expanding any
+     * aliased folders back to complete folders.
+     */
+    String toResourcePath(String clientURL);
+}

Copied: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/Context.java (from r480115, tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/WebContext.java)
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/Context.java?view=diff&rev=482719&p1=tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/WebContext.java&r1=480115&p2=tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/Context.java&r2=482719
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/WebContext.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/Context.java Tue Dec  5 09:35:05 2006
@@ -12,26 +12,25 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package org.apache.tapestry.services;
-
-import java.net.URL;
-
-/**
- * An API agnostic version of {@link javax.servlet.ServletContext}.
- * 
- * 
- */
-public interface WebContext
-{
-    /**
-     * Returns a URL to a resource stored within the context. The path should start with a leading
-     * slash.
-     * 
-     * @param path
-     * @return the URL for the path, or null if the path does not correspond to a file.
-     */
-    URL getResource(String path);
-
-    /** Returns an initial parameter value defined by servlet. */
-    String getInitParameter(String name);
-}
+package org.apache.tapestry.services;
+
+import java.net.URL;
+
+/**
+ * An API agnostic version of {@link javax.servlet.ServletContext}, used to bridge the gaps between
+ * the Servlet API and the Portlet API.
+ */
+public interface Context
+{
+    /**
+     * Returns a URL to a resource stored within the context. The path should start with a leading
+     * slash.
+     * 
+     * @param path
+     * @return the URL for the path, or null if the path does not correspond to a file.
+     */
+    URL getResource(String path);
+
+    /** Returns an initial parameter value defined by servlet. */
+    String getInitParameter(String name);
+}

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/Dispatcher.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/Dispatcher.java?view=diff&rev=482719&r1=482718&r2=482719
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/Dispatcher.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/Dispatcher.java Tue Dec  5 09:35:05 2006
@@ -12,21 +12,19 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package org.apache.tapestry.services;
-
-import java.io.IOException;
-
-/**
- * A dispatcher is responsible for recognizing an incoming request
- * 
- * 
- */
-public interface Dispatcher
-{
-    /**
-     * Analyzes the incoming request and performs an appropriate operation for each.
-     * 
-     * @return true if a response was delivered
-     */
-    boolean dispatch(WebRequest request, WebResponse response) throws IOException;
-}
+package org.apache.tapestry.services;
+
+import java.io.IOException;
+
+/**
+ * A dispatcher is responsible for recognizing an incoming request.  Dispatchers form a chain of command.
+ */
+public interface Dispatcher
+{
+    /**
+     * Analyzes the incoming request and performs an appropriate operation for each.
+     * 
+     * @return true if a response was delivered
+     */
+    boolean dispatch(Request request, Response response) throws IOException;
+}

Copied: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/Request.java (from r480168, tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/WebRequest.java)
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/Request.java?view=diff&rev=482719&p1=tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/WebRequest.java&r1=480168&p2=tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/Request.java&r2=482719
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/WebRequest.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/Request.java Tue Dec  5 09:35:05 2006
@@ -18,9 +18,10 @@
 import java.util.Locale;
 
 /**
- * Generic version of {@link javax.servlet.http.HttpServletRequest}.
+ * Generic version of {@link javax.servlet.http.HttpServletRequest}, used to encapsulate the
+ * Servlet API version, and to help bridge the differences between Servlet API and Porlet API.
  */
-public interface WebRequest
+public interface Request
 {
     /** Returns a list of query parameter names, in alphabetical order. */
     List<String> getParameterNames();
@@ -53,15 +54,37 @@
     String getContextPath();
 
     /**
-     * Gets the {@link WebSession}. If create is false and the session has not be created
+     * Gets the {@link Session}. If create is false and the session has not be created
      * previously, returns null.
      * 
      * @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)
      */
-    WebSession getSession(boolean create);
+    Session getSession(boolean create);
 
     /** Returns the locale of the client as determined from the request headers. */
     Locale getLocale();
+
+    /**
+     * Returns the value of the specified request header as a <code>long</code> value that
+     * represents a <code>Date</code> object. Use this method with headers that contain dates,
+     * such as <code>If-Modified-Since</code>.
+     * <p>
+     * The date is returned as the number of milliseconds since January 1, 1970 GMT. The header name
+     * is case insensitive.
+     * <p>
+     * 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
+     * @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
+     * @exception IllegalArgumentException
+     *                If the header value can't be converted to a date
+     */
+    long getDateHeader(String name);
 }

Copied: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/RequestFilter.java (from r480115, tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/WebRequestFilter.java)
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/RequestFilter.java?view=diff&rev=482719&p1=tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/WebRequestFilter.java&r1=480115&p2=tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/RequestFilter.java&r2=482719
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/WebRequestFilter.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/RequestFilter.java Tue Dec  5 09:35:05 2006
@@ -12,21 +12,18 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package org.apache.tapestry.services;
-
-import java.io.IOException;
-
-/**
- * Filter interface for {@link org.apache.tapestry.services.WebRequestHandler}.
- * 
- * 
- */
-public interface WebRequestFilter
-{
-    /**
-     * Returns true if the request has been handled, false otherwise.
-     */
-    boolean service(WebRequest request, WebResponse response, WebRequestHandler handler)
-            throws IOException;
-
-}
+package org.apache.tapestry.services;
+
+import java.io.IOException;
+
+/**
+ * Filter interface for {@link org.apache.tapestry.services.RequestHandler}.
+ */
+public interface RequestFilter
+{
+    /**
+     * Returns true if the request has been handled, false otherwise.
+     */
+    boolean service(Request request, Response response, RequestHandler handler) throws IOException;
+
+}

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/RequestGlobals.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/RequestGlobals.java?view=diff&rev=482719&r1=482718&r2=482719
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/RequestGlobals.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/RequestGlobals.java Tue Dec  5 09:35:05 2006
@@ -32,11 +32,11 @@
 
     HttpServletResponse getHTTPServletResponse();
 
-    void store(WebRequest request, WebResponse response);
+    void store(Request request, Response response);
 
-    /** Accessible as injected object "infrastructure:request". */
-    WebRequest getRequest();
+    /** Accessible as injected object "infrastructure:Request". */
+    Request getRequest();
 
-    /** Accessible as injected object "infrastructure:response". */
-    WebResponse getResponse();
+    /** Accessible as injected object "infrastructure:Response". */
+    Response getResponse();
 }

Copied: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/RequestHandler.java (from r480115, tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/WebRequestHandler.java)
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/RequestHandler.java?view=diff&rev=482719&p1=tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/WebRequestHandler.java&r1=480115&p2=tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/RequestHandler.java&r2=482719
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/WebRequestHandler.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/RequestHandler.java Tue Dec  5 09:35:05 2006
@@ -21,8 +21,8 @@
  * 
  * 
  */
-public interface WebRequestHandler
+public interface RequestHandler
 {
     /** Returns true if the request has been handled, false otherwise. */
-    boolean service(WebRequest request, WebResponse response) throws IOException;
+    boolean service(Request request, Response response) throws IOException;
 }

Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/ResourceDigestGenerator.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/ResourceDigestGenerator.java?view=auto&rev=482719
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/ResourceDigestGenerator.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/ResourceDigestGenerator.java Tue Dec  5 09:35:05 2006
@@ -0,0 +1,49 @@
+// Copyright 2006 The Apache Software Foundation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry.services;
+
+import java.net.URL;
+
+import org.apache.tapestry.internal.services.ClasspathAssetFactory;
+import org.apache.tapestry.ioc.Resource;
+import org.apache.tapestry.ioc.internal.util.ClasspathResource;
+
+/**
+ * Responsible for determining which classpath resources require checksums, and for generating
+ * checksums for such resources.
+ * 
+ * @see ClasspathResource
+ * @see ClasspathAssetFactory
+ */
+public interface ResourceDigestGenerator
+{
+    /**
+     * Examines the path (typically, the file name extension at the end of the path) to determine if
+     * a checksum is required for the path. The path is {@link Resource} style, without a leading
+     * slash.
+     */
+    boolean requiresDigest(String path);
+
+    /**
+     * Reads the content of a URL (presumably, for a resource on the classpath) and generates a
+     * digest of its content. This digest will be incorporated into the URL provided to the
+     * client, to verify that the client has been "granted" access to this resource. This is only
+     * used for resources where {@link #requiresDigest(String)} is true.
+     * 
+     * @param url
+     * @return the digest for the resource
+     */
+    String generateDigest(URL url);
+}

Copied: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/Response.java (from r480115, tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/WebResponse.java)
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/Response.java?view=diff&rev=482719&p1=tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/WebResponse.java&r1=480115&p2=tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/Response.java&r2=482719
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/WebResponse.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/Response.java Tue Dec  5 09:35:05 2006
@@ -12,46 +12,98 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package org.apache.tapestry.services;
-
-import java.io.IOException;
-import java.io.PrintWriter;
-
-/**
- * API agnostic wrapper for generating a response.
- */
-public interface WebResponse
-{
-    /**
-     * Returns a PrintWriter object to which output may be sent. Invoking flush() on the writer will
-     * commit the output.
-     */
-    PrintWriter getPrintWriter() throws IOException;
-
-    /**
-     * Encodes the URL, ensuring that a session id is included (if a session exists, and as
-     * necessary depending on the client browser's use of cookies).
-     * 
-     * @param URL
-     * @return the same URL or a different one with additional information to track the user session
-     */
-    String encodeURL(String URL);
-
-    /**
-     * Encodes the URL for use as a redirect, ensuring that a session id is included (if a session
-     * exists, and as necessary depending on the client browser's use of cookies).
-     * 
-     * @param URL
-     * @return the same URL or a different one with additional information to track the user session
-     */
-    String encodeRedirectURL(String URL);
-
-    /**
-     * Sends a redirect to the client.
-     * 
-     * @param URL
-     *            full or partial (relative) URL to send to the client
-     * @see #encodeRedirectURL(String)
-     */
-    void sendRedirect(String URL) throws IOException;
-}
+package org.apache.tapestry.services;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+
+/**
+ * API agnostic wrapper for generating a response. Bridges the gaps between the Servlet API and the
+ * Portlet API.
+ */
+public interface Response
+{
+    /**
+     * Returns a PrintWriter object to which output may be sent. Invoking flush() on the writer will
+     * commit the output.
+     */
+    PrintWriter getPrintWriter() throws IOException;
+
+    /**
+     * Returns an OutputStream to which byte-oriented output may be sent. Invoking flush() on the
+     * stream will commit the output.
+     */
+    OutputStream getOutputStream() throws IOException;
+
+    /**
+     * Encodes the URL, ensuring that a session id is included (if a session exists, and as
+     * necessary depending on the client browser's use of cookies).
+     * 
+     * @param URL
+     * @return the same URL or a different one with additional information to track the user session
+     */
+    String encodeURL(String URL);
+
+    /**
+     * Encodes the URL for use as a redirect, ensuring that a session id is included (if a session
+     * exists, and as necessary depending on the client browser's use of cookies).
+     * 
+     * @param URL
+     * @return the same URL or a different one with additional information to track the user session
+     */
+    String encodeRedirectURL(String URL);
+
+    /**
+     * Sends a redirect to the client.
+     * 
+     * @param URL
+     *            full or partial (relative) URL to send to the client
+     * @see #encodeRedirectURL(String)
+     */
+    void sendRedirect(String URL) throws IOException;
+
+    /**
+     * Sends an error response to the client using the specified status. The server defaults to
+     * creating the response to look like an HTML-formatted server error page containing the
+     * specified message, setting the content type to "text/html", leaving cookies and other headers
+     * unmodified. If an error-page declaration has been made for the web application corresponding
+     * to the status code passed in, it will be served back in preference to the suggested msg
+     * parameter.
+     * <p>
+     * If the response has already been committed, this method throws an IllegalStateException.
+     * After using this method, the response should be considered to be committed and should not be
+     * written to.
+     * 
+     * @param sc
+     *            the error status code
+     * @param msg
+     *            the descriptive message
+     * @exception IOException
+     *                If an input or output exception occurs
+     * @exception IllegalStateException
+     *                If the response was committed
+     */
+    void sendError(int sc, String message) throws IOException;
+
+    /**
+     * Sets the length of the content body in the response; this method sets the HTTP Content-Length
+     * header.
+     * 
+     * @param length
+     *            the length of the content
+     */
+    void setContentLength(int length);
+
+    /**
+     * Sets a response header with the given name and date-value. The date is specified in terms of
+     * milliseconds since the epoch. If the header had already been set, the new value overwrites
+     * the previous one.
+     * 
+     * @param name
+     *            the name of the header to set
+     * @param date
+     *            the assigned date value
+     */
+    void setDateHeader(String name, long date);
+}

Copied: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/Session.java (from r480115, tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/WebSession.java)
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/Session.java?view=diff&rev=482719&p1=tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/WebSession.java&r1=480115&p2=tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/Session.java&r2=482719
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/WebSession.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/Session.java Tue Dec  5 09:35:05 2006
@@ -12,32 +12,33 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package org.apache.tapestry.services;
-
-import java.util.List;
-
-import javax.servlet.http.HttpSession;
-
-/**
- * Generic version of {@link HttpSession}.
- */
-public interface WebSession
-{
-    /**
-     * Returns a list of the names of all attributes stored in the session. The names are returned
-     * sorted alphabetically.
-     */
-    List<String> getAttributeNames();
-
-    /**
-     * Returns a list of the names of all attributes stored in the session whose name has the
-     * provided prefix. The names are returned in alphabetical order.
-     */
-    List<String> getAttributeNames(String prefix);
-
-    /** Returns the value previously stored in the session. */
-    Object getAttribute(String name);
-
-    /** Sets the value of an attribute. If the value is null, then the attribute is deleted. */
-    void setAttribute(String name, Object value);
-}
+package org.apache.tapestry.services;
+
+import java.util.List;
+
+import javax.servlet.http.HttpSession;
+
+/**
+ * Generic version of {@link HttpSession}, used to bridge the gaps between the Servlet API and the
+ * Portlet API.
+ */
+public interface Session
+{
+    /**
+     * Returns a list of the names of all attributes stored in the session. The names are returned
+     * sorted alphabetically.
+     */
+    List<String> getAttributeNames();
+
+    /**
+     * Returns a list of the names of all attributes stored in the session whose name has the
+     * provided prefix. The names are returned in alphabetical order.
+     */
+    List<String> getAttributeNames(String prefix);
+
+    /** Returns the value previously stored in the session. */
+    Object getAttribute(String name);
+
+    /** Sets the value of an attribute. If the value is null, then the attribute is deleted. */
+    void setAttribute(String name, Object value);
+}

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/TapestryModule.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/TapestryModule.java?view=diff&rev=482719&r1=482718&r2=482719
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/TapestryModule.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/TapestryModule.java Tue Dec  5 09:35:05 2006
@@ -44,9 +44,11 @@
 import org.apache.tapestry.internal.bindings.LiteralBindingFactory;
 import org.apache.tapestry.internal.bindings.MessageBindingFactory;
 import org.apache.tapestry.internal.services.ApplicationGlobalsImpl;
+import org.apache.tapestry.internal.services.AssetDispatcher;
 import org.apache.tapestry.internal.services.AssetInjectWorker;
 import org.apache.tapestry.internal.services.AssetSourceImpl;
 import org.apache.tapestry.internal.services.BindingSourceImpl;
+import org.apache.tapestry.internal.services.ClasspathAssetAliasManagerImpl;
 import org.apache.tapestry.internal.services.CommonResourcesInjectionProvider;
 import org.apache.tapestry.internal.services.ComponentClassFactoryImpl;
 import org.apache.tapestry.internal.services.ComponentClassResolverImpl;
@@ -58,7 +60,7 @@
 import org.apache.tapestry.internal.services.ComponentResourcesInjectionProvider;
 import org.apache.tapestry.internal.services.ComponentSourceImpl;
 import org.apache.tapestry.internal.services.ComponentWorker;
-import org.apache.tapestry.internal.services.ContextAssetFactory;
+import org.apache.tapestry.internal.services.ContextImpl;
 import org.apache.tapestry.internal.services.DefaultInjectionProvider;
 import org.apache.tapestry.internal.services.EnvironmentImpl;
 import org.apache.tapestry.internal.services.EnvironmentalWorker;
@@ -66,8 +68,8 @@
 import org.apache.tapestry.internal.services.InfrastructureImpl;
 import org.apache.tapestry.internal.services.InfrastructureManagerImpl;
 import org.apache.tapestry.internal.services.InjectAnonymousWorker;
-import org.apache.tapestry.internal.services.InjectPageWorker;
 import org.apache.tapestry.internal.services.InjectNamedWorker;
+import org.apache.tapestry.internal.services.InjectPageWorker;
 import org.apache.tapestry.internal.services.InternalModule;
 import org.apache.tapestry.internal.services.LinkFactory;
 import org.apache.tapestry.internal.services.MarkupWriterImpl;
@@ -80,7 +82,12 @@
 import org.apache.tapestry.internal.services.PersistWorker;
 import org.apache.tapestry.internal.services.PersistentFieldManagerImpl;
 import org.apache.tapestry.internal.services.RequestGlobalsImpl;
+import org.apache.tapestry.internal.services.RequestImpl;
 import org.apache.tapestry.internal.services.RequestPageCache;
+import org.apache.tapestry.internal.services.ResourceCache;
+import org.apache.tapestry.internal.services.ResourceDigestGeneratorImpl;
+import org.apache.tapestry.internal.services.ResourceStreamer;
+import org.apache.tapestry.internal.services.ResponseImpl;
 import org.apache.tapestry.internal.services.RetainWorker;
 import org.apache.tapestry.internal.services.SessionPersistentFieldStrategy;
 import org.apache.tapestry.internal.services.StaticFilesFilter;
@@ -88,9 +95,6 @@
 import org.apache.tapestry.internal.services.SupportsInformalParametersWorker;
 import org.apache.tapestry.internal.services.UnclaimedFieldWorker;
 import org.apache.tapestry.internal.services.UpdateListenerHub;
-import org.apache.tapestry.internal.services.WebContextImpl;
-import org.apache.tapestry.internal.services.WebRequestImpl;
-import org.apache.tapestry.internal.services.WebResponseImpl;
 import org.apache.tapestry.ioc.Configuration;
 import org.apache.tapestry.ioc.IOCUtilities;
 import org.apache.tapestry.ioc.MappedConfiguration;
@@ -135,7 +139,7 @@
 
     private final PageResponseRenderer _pageResponseRenderer;
 
-    private final WebRequest _request;
+    private final Request _request;
 
     private final Environment _environment;
 
@@ -153,8 +157,8 @@
     ApplicationGlobals applicationGlobals, @InjectService("tapestry.ioc.ChainBuilder")
     ChainBuilder chainBuilder, @InjectService("tapestry.internal.RequestPageCache")
     RequestPageCache requestPageCache, @InjectService("tapestry.internal.PageResponseRenderer")
-    PageResponseRenderer pageResponseRenderer, @Inject("infrastructure:request")
-    WebRequest request, @InjectService("Environment")
+    PageResponseRenderer pageResponseRenderer, @Inject("infrastructure:Request")
+    Request request, @InjectService("Environment")
     Environment environment, @InjectService("tapestry.ioc.StrategyBuilder")
     StrategyBuilder strategyBuilder)
     {
@@ -170,23 +174,28 @@
         _strategyBuilder = strategyBuilder;
     }
 
-    private static <T> void add(Configuration<InfrastructureContribution> configuration,
-            ServiceLocator locator, Class<T> serviceInterface)
+    /**
+     * Invoked from
+     * {@link #contributeInfrastructure(Configuration, ServiceLocator, Request, Response, TypeCoercer)}
+     * to contribute services from the tapestry module where the unqualified class name of the
+     * service interface matches the unqualified service id. This unqualified name is used as the
+     * infrastructure alias.
+     */
+    @SuppressWarnings("unchecked")
+    private static void add(Configuration<InfrastructureContribution> configuration,
+            ServiceLocator locator, Class... serviceInterfaces)
     {
-        String className = serviceInterface.getName();
-        int dotx = className.lastIndexOf('.');
-        String serviceId = className.substring(dotx + 1);
-
-        // Convert first character to lower case to form the property name.
-
-        String propertyName = serviceId.substring(0, 1).toLowerCase() + serviceId.substring(1);
+        for (Class serviceInterface : serviceInterfaces)
+        {
+            String serviceId = IOCUtilities.toSimpleId(serviceInterface.getName());
 
-        T service = locator.getService(serviceId, serviceInterface);
+            Object service = locator.getService(serviceId, serviceInterface);
 
-        InfrastructureContribution contribution = new InfrastructureContribution(propertyName,
-                service);
+            InfrastructureContribution contribution = new InfrastructureContribution(serviceId,
+                    service);
 
-        configuration.add(contribution);
+            configuration.add(contribution);
+        }
     }
 
     public static ApplicationGlobals buildApplicationGlobals()
@@ -194,10 +203,10 @@
         return new ApplicationGlobalsImpl();
     }
 
-    public WebContext buildWebContext(@InjectService("ApplicationGlobals")
+    public Context buildContext(@InjectService("ApplicationGlobals")
     ApplicationGlobals globals)
     {
-        return _shadowBuilder.build(globals, "webContext", WebContext.class);
+        return _shadowBuilder.build(globals, "context", Context.class);
     }
 
     public ServletApplicationInitializer buildServletApplicationInitializer(Log log,
@@ -213,7 +222,7 @@
 
                 // And now, down the (Web) ApplicationInitializer pipeline ...
 
-                initializer.initializeApplication(new WebContextImpl(context));
+                initializer.initializeApplication(new ContextImpl(context));
             }
         };
 
@@ -231,7 +240,7 @@
     {
         ApplicationInitializer terminator = new ApplicationInitializer()
         {
-            public void initializeApplication(WebContext context)
+            public void initializeApplication(Context context)
             {
                 _applicationGlobals.store(context);
             }
@@ -255,8 +264,8 @@
     }
 
     public HttpServletRequestHandler buildHttpServletRequestHandler(Log log,
-            List<HttpServletRequestFilter> configuration, @InjectService("WebRequestHandler")
-            final WebRequestHandler handler)
+            List<HttpServletRequestFilter> configuration, @InjectService("RequestHandler")
+            final RequestHandler handler)
     {
         HttpServletRequestHandler terminator = new HttpServletRequestHandler()
         {
@@ -265,7 +274,7 @@
             {
                 _requestGlobals.store(request, response);
 
-                return handler.service(new WebRequestImpl(request), new WebResponseImpl(response));
+                return handler.service(new RequestImpl(request), new ResponseImpl(response));
             }
         };
 
@@ -316,27 +325,27 @@
      * Builds a shadow of the RequestGlobals.request property. Note again that the shadow can be an
      * ordinary singleton, even though RequestGlobals is perthread.
      */
-    public WebRequest buildWebRequest()
+    public Request buildRequest()
     {
-        return _shadowBuilder.build(_requestGlobals, "request", WebRequest.class);
+        return _shadowBuilder.build(_requestGlobals, "request", Request.class);
     }
 
     /**
      * Builds a shadow of the RequestGlobals.response property. Note again that the shadow can be an
      * ordinary singleton, even though RequestGlobals is perthread.
      */
-    public WebResponse buildWebResponse()
+    public Response buildResponse()
     {
-        return _shadowBuilder.build(_requestGlobals, "response", WebResponse.class);
+        return _shadowBuilder.build(_requestGlobals, "response", Response.class);
     }
 
-    public WebRequestHandler buildWebRequestHandler(Log log, List<WebRequestFilter> configuration,
+    public RequestHandler buildRequestHandler(Log log, List<RequestFilter> configuration,
             @InjectService("MasterDispatcher")
             final Dispatcher masterDispatcher)
     {
-        WebRequestHandler terminator = new WebRequestHandler()
+        RequestHandler terminator = new RequestHandler()
         {
-            public boolean service(WebRequest request, WebResponse response) throws IOException
+            public boolean service(Request request, Response response) throws IOException
             {
                 _requestGlobals.store(request, response);
 
@@ -346,8 +355,8 @@
 
         return _pipelineBuilder.build(
                 log,
-                WebRequestHandler.class,
-                WebRequestFilter.class,
+                RequestHandler.class,
+                RequestFilter.class,
                 configuration,
                 terminator);
     }
@@ -357,20 +366,19 @@
      * and terminates the pipeline by returning false. Generally, most filters should be ordered
      * after this filter.
      */
-    public static void contributeWebRequestHandler(
-            OrderedConfiguration<WebRequestFilter> configuration, @InjectService("WebContext")
-            WebContext webContext,
-            @InjectService("tapestry.internal.DefaultRequestExceptionHandler")
+    public static void contributeRequestHandler(OrderedConfiguration<RequestFilter> configuration,
+            @InjectService("Context")
+            Context context, @InjectService("tapestry.internal.DefaultRequestExceptionHandler")
             final RequestExceptionHandler exceptionHandler)
     {
-        WebRequestFilter staticFilesFilter = new StaticFilesFilter(webContext);
+        RequestFilter staticFilesFilter = new StaticFilesFilter(context);
 
         configuration.add("StaticFilesFilter", staticFilesFilter);
 
-        WebRequestFilter errorFilter = new WebRequestFilter()
+        RequestFilter errorFilter = new RequestFilter()
         {
-            public boolean service(WebRequest request, WebResponse response,
-                    WebRequestHandler handler) throws IOException
+            public boolean service(Request request, Response response, RequestHandler handler)
+                    throws IOException
             {
                 try
                 {
@@ -396,22 +404,27 @@
      */
     public static void contributeInfrastructure(
             Configuration<InfrastructureContribution> configuration, ServiceLocator locator,
-            @InjectService("WebRequest")
-            WebRequest request, @InjectService("WebResponse")
-            WebResponse response, @InjectService("tapestry.ioc.TypeCoercer")
+            @InjectService("Request")
+            Request request, @InjectService("Response")
+            Response response, @InjectService("tapestry.ioc.TypeCoercer")
             TypeCoercer typeCoercer)
     {
-        add(configuration, locator, MarkupWriterFactory.class);
-        add(configuration, locator, PersistentFieldManager.class);
-        add(configuration, locator, Environment.class);
-        add(configuration, locator, ComponentSource.class);
-        add(configuration, locator, BindingSource.class);
-        add(configuration, locator, ComponentMessagesSource.class);
-        add(configuration, locator, AssetSource.class);
-
-        configuration.add(new InfrastructureContribution("request", request));
-        configuration.add(new InfrastructureContribution("response", response));
-        configuration.add(new InfrastructureContribution("typeCoercer", typeCoercer));
+        add(
+                configuration,
+                locator,
+                MarkupWriterFactory.class,
+                PersistentFieldManager.class,
+                Environment.class,
+                ComponentSource.class,
+                BindingSource.class,
+                ComponentMessagesSource.class,
+                AssetSource.class,
+                ResourceDigestGenerator.class,
+                ClasspathAssetAliasManager.class,
+                Request.class,
+                Response.class);
+
+        configuration.add(new InfrastructureContribution("TypeCoercer", typeCoercer));
     }
 
     /**
@@ -430,16 +443,28 @@
     public void contributeMasterDispatcher(OrderedConfiguration<Dispatcher> configuration,
             @InjectService("tapestry.internal.LinkFactory")
             LinkFactory linkFactory, @InjectService("ComponentEventHandler")
-            ComponentEventHandler componentEventHandler)
+            ComponentEventHandler componentEventHandler,
+            @Inject("infrastructure:ClasspathAssetAliasManager")
+            ClasspathAssetAliasManager aliasManager,
+            @InjectService("tapestry.internal.ResourceCache")
+            ResourceCache resourceCache, @InjectService("tapestry.internal.ResourceStreamer")
+            ResourceStreamer streamer)
     {
+        // This goes first because an asset to be streamed may have an file extension, such as
+        // ".html", that will confuse the later dispatchers.
+
         configuration.add(
-                "HTML",
-                new PageRenderDispatcher(_pageResponseRenderer, _requestPageCache));
+                "Asset",
+                new AssetDispatcher(streamer, aliasManager, resourceCache),
+                "before:PageRender");
+
+        configuration.add("PageRender", new PageRenderDispatcher(_pageResponseRenderer,
+                _requestPageCache));
 
         // This goes after the HTML one so that the "." in ".html" doesn't confuse it.
 
         configuration.add("ComponentEvent", new ComponentEventDispatcher(componentEventHandler,
-                _requestPageCache, linkFactory), "after:HTML");
+                _requestPageCache, linkFactory), "after:PageRender");
     }
 
     public static ComponentClassResolver buildComponentClassResolver(
@@ -548,7 +573,7 @@
             InjectionProvider injectionProvider, @InjectService("Environment")
             Environment environment, @InjectService("tapestry.ComponentClassResolver")
             ComponentClassResolver resolver, @InjectService("tapestry.internal.RequestPageCache")
-            RequestPageCache requestPageCache, @Inject("infrastructure:assetSource")
+            RequestPageCache requestPageCache, @Inject("infrastructure:AssetSource")
             AssetSource assetSource)
     {
         // TODO: Proper scheduling of all of this. Since a given field or method should
@@ -765,11 +790,30 @@
         return new AssetSourceImpl(configuration);
     }
 
-    public void contributeAssetSource(MappedConfiguration<String, AssetFactory> configuration)
+    public void contributeAssetSource(MappedConfiguration<String, AssetFactory> configuration,
+            @InjectService("tapestry.internal.ContextAssetFactory")
+            AssetFactory contextAssetFactory,
+            @InjectService("tapestry.internal.ClasspathAssetFactory")
+            AssetFactory classpathAssetFactory)
     {
-        AssetFactory contextAssetFactory = new ContextAssetFactory(_request, _applicationGlobals
-                .getWebContext());
-
         configuration.add("context", contextAssetFactory);
+        configuration.add("classpath", classpathAssetFactory);
+    }
+
+    public static ResourceDigestGenerator buildResourceDigestGenerator()
+    {
+        return new ResourceDigestGeneratorImpl();
+    }
+
+    public ClasspathAssetAliasManager buildClasspathAssetAliasManager(
+            Map<String, String> configuration)
+    {
+        return new ClasspathAssetAliasManagerImpl(_request, configuration);
+    }
+
+    public static void contributeClasspathAssetAliasManager(
+            MappedConfiguration<String, String> configuration)
+    {
+        configuration.add("tapestry/", "org/apache/tapestry/");
     }
 }

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/TapestryTestCase.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/TapestryTestCase.java?view=diff&rev=482719&r1=482718&r2=482719
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/TapestryTestCase.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/TapestryTestCase.java Tue Dec  5 09:35:05 2006
@@ -53,14 +53,16 @@
 import org.apache.tapestry.services.Binding;
 import org.apache.tapestry.services.BindingFactory;
 import org.apache.tapestry.services.ClassTransformation;
+import org.apache.tapestry.services.ClasspathAssetAliasManager;
 import org.apache.tapestry.services.ComponentClassResolver;
 import org.apache.tapestry.services.InjectionProvider;
 import org.apache.tapestry.services.MethodSignature;
-import org.apache.tapestry.services.WebContext;
-import org.apache.tapestry.services.WebRequest;
-import org.apache.tapestry.services.WebRequestHandler;
-import org.apache.tapestry.services.WebResponse;
-import org.apache.tapestry.services.WebSession;
+import org.apache.tapestry.services.ResourceDigestGenerator;
+import org.apache.tapestry.services.Context;
+import org.apache.tapestry.services.Request;
+import org.apache.tapestry.services.RequestHandler;
+import org.apache.tapestry.services.Response;
+import org.apache.tapestry.services.Session;
 
 /**
  * Base test case that adds a number of convienience factory and training methods for the public
@@ -70,7 +72,7 @@
 {
 
     protected final Resource _simpleComponentResource = new ClasspathResource(
-                "org/apache/tapestry/internal/services/SimpleComponent.class");
+            "org/apache/tapestry/internal/services/SimpleComponent.class");
 
     protected final void train_findFieldsWithAnnotation(ClassTransformation transformation,
             Class<? extends Annotation> annotationClass, String... fieldNames)
@@ -243,9 +245,9 @@
         expect(tf.findMethodsWithAnnotation(annotationType)).andReturn(sigs);
     }
 
-    protected final WebRequest newWebRequest()
+    protected final Request newRequest()
     {
-        return newMock(WebRequest.class);
+        return newMock(Request.class);
     }
 
     protected final void train_provideInjection(InjectionProvider provider, String fieldName,
@@ -303,14 +305,14 @@
         expect(binding.get()).andReturn(value);
     }
 
-    protected final void train_encodeURL(WebResponse response, String inputURL, String outputURL)
+    protected final void train_encodeURL(Response response, String inputURL, String outputURL)
     {
         expect(response.encodeURL(inputURL)).andReturn(outputURL);
     }
 
-    protected final WebResponse newWebResponse()
+    protected final Response newResponse()
     {
-        return newMock(WebResponse.class);
+        return newMock(Response.class);
     }
 
     protected void train_getAttribute(HttpSession session, String attributeName, Object value)
@@ -334,27 +336,27 @@
         return newMock(HttpSession.class);
     }
 
-    protected final void train_getAttributeNames(WebSession session, String prefix, String... names)
+    protected final void train_getAttributeNames(Session session, String prefix, String... names)
     {
         expect(session.getAttributeNames(prefix)).andReturn(Arrays.asList(names));
     }
 
-    protected final void train_getAttribute(WebSession session, String name, Object attribute)
+    protected final void train_getAttribute(Session session, String name, Object attribute)
     {
         expect(session.getAttribute(name)).andReturn(attribute);
     }
 
-    protected final WebSession newWebSession()
+    protected final Session newSession()
     {
-        return newMock(WebSession.class);
+        return newMock(Session.class);
     }
 
-    protected final void train_getSession(WebRequest request, boolean create, WebSession session)
+    protected final void train_getSession(Request request, boolean create, Session session)
     {
         expect(request.getSession(create)).andReturn(session);
     }
 
-    protected final void train_encodeRedirectURL(WebResponse response, String URI, String encoded)
+    protected final void train_encodeRedirectURL(Response response, String URI, String encoded)
     {
         expect(response.encodeRedirectURL(URI)).andReturn(encoded);
     }
@@ -386,19 +388,18 @@
         expect(resources.getContainer()).andReturn(container).atLeastOnce();
     }
 
-    protected final WebRequestHandler newWebRequestHandler()
+    protected final RequestHandler newRequestHandler()
     {
-        return newMock(WebRequestHandler.class);
+        return newMock(RequestHandler.class);
     }
 
-
-
-    protected final void train_service(WebRequestHandler handler, WebRequest request, WebResponse response, boolean result) throws IOException
+    protected final void train_service(RequestHandler handler, Request request,
+            Response response, boolean result) throws IOException
     {
         expect(handler.service(request, response)).andReturn(result);
     }
 
-    protected final void train_getLocale(WebRequest request, Locale locale)
+    protected final void train_getLocale(Request request, Locale locale)
     {
         expect(request.getLocale()).andReturn(locale).atLeastOnce();
     }
@@ -438,9 +439,9 @@
         return newMock(AssetFactory.class);
     }
 
-    protected final WebContext newWebContext()
+    protected final Context newContext()
     {
-        return newMock(WebContext.class);
+        return newMock(Context.class);
     }
 
     protected final void train_getClassName(ClassTransformation transformation, String className)
@@ -453,8 +454,62 @@
         expect(annotation.value()).andReturn(value).atLeastOnce();
     }
 
-    protected final <T extends Annotation> void train_getMethodAnnotation(ClassTransformation ct, MethodSignature signature, Class<T> annotationClass, T annotation)
+    protected final <T extends Annotation> void train_getMethodAnnotation(ClassTransformation ct,
+            MethodSignature signature, Class<T> annotationClass, T annotation)
     {
         expect(ct.getMethodAnnotation(signature, annotationClass)).andReturn(annotation);
+    }
+
+    protected final ClasspathAssetAliasManager newClasspathAssetAliasManager()
+    {
+        return newMock(ClasspathAssetAliasManager.class);
+    }
+
+    protected final void train_toClientURL(ClasspathAssetAliasManager manager, String resourcePath,
+            String clientURL)
+    {
+        expect(manager.toClientURL(resourcePath)).andReturn(clientURL);
+    }
+
+    protected final ResourceDigestGenerator newResourceDigestGenerator()
+    {
+        return newMock(ResourceDigestGenerator.class);
+    }
+
+    protected final void train_generateChecksum(ResourceDigestGenerator generator, URL url,
+            String digest)
+    {
+        expect(generator.generateDigest(url)).andReturn(digest);
+    }
+
+    protected final void train_requiresDigest(ResourceDigestGenerator generator, String path,
+            boolean requiresDigest)
+    {
+        expect(generator.requiresDigest(path)).andReturn(requiresDigest);
+    }
+
+    protected final void train_toURL(Resource resource, URL url)
+    {
+        expect(resource.toURL()).andReturn(url).atLeastOnce();
+    }
+
+    protected final void train_getPath(Resource r, String path)
+    {
+        expect(r.getPath()).andReturn(path).atLeastOnce();
+    }
+
+    protected final void train_getPath(Request request, String path)
+    {
+        expect(request.getPath()).andReturn(path).atLeastOnce();
+    }
+
+    protected final void train_toResourcePath(ClasspathAssetAliasManager manager, String clientURL, String resourcePath)
+    {
+        expect(manager.toResourcePath(clientURL)).andReturn(resourcePath).atLeastOnce();
+    }
+
+    protected final void train_getDateHeader(Request request, String name, long value)
+    {
+        expect(request.getDateHeader(name)).andReturn(value).atLeastOnce();
     }
 }

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/internal/services/ServicesStrings.properties
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/internal/services/ServicesStrings.properties?view=diff&rev=482719&r1=482718&r2=482719
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/internal/services/ServicesStrings.properties (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/internal/services/ServicesStrings.properties Tue Dec  5 09:35:05 2006
@@ -61,4 +61,5 @@
 component-instance-is-not-a-page=Method %s (for component %s) returned component %s, which is not a page component. The page containing the component will render the client response.
 failure-reading-component-messages=Unable to read component message catalog from %s: %s
 unknown-asset-prefix=Unknown prefix for asset path '%s'.
-asset-does-not-exist=Unable to locate asset '%s' (the file does not exist).
\ No newline at end of file
+asset-does-not-exist=Unable to locate asset '%s' (the file does not exist).
+wrong-asset-digest=The asset digest in the request does not match the actual digest for asset '%s'. This indicates that the content of the asset has changed between requests. 
\ No newline at end of file