Author: pete
Date: Wed Jun 29 22:32:59 2011
New Revision: 1141298

URL: http://svn.apache.org/viewvc?rev=1141298&view=rev
Log:
WICKET-3846 rework resource caching so it will by default work in clusters, 
also made the whole caching stuff pluggable and easier to extend

Added:
    
wicket/trunk/wicket-core/src/main/java/org/apache/wicket/request/resource/caching/FilenameWithVersionResourceCachingStrategy.java
      - copied, changed from r1141191, 
wicket/trunk/wicket-core/src/main/java/org/apache/wicket/request/resource/caching/AbstractFilenameWithVersionResourceCachingStrategy.java
    
wicket/trunk/wicket-core/src/main/java/org/apache/wicket/request/resource/caching/QueryStringWithVersionResourceCachingStrategy.java
      - copied, changed from r1141191, 
wicket/trunk/wicket-core/src/main/java/org/apache/wicket/request/resource/caching/QueryStringWithTimestampResourceCachingStrategy.java
    
wicket/trunk/wicket-core/src/main/java/org/apache/wicket/request/resource/caching/version/
    
wicket/trunk/wicket-core/src/main/java/org/apache/wicket/request/resource/caching/version/CachingResourceVersion.java
    
wicket/trunk/wicket-core/src/main/java/org/apache/wicket/request/resource/caching/version/IResourceVersion.java
    
wicket/trunk/wicket-core/src/main/java/org/apache/wicket/request/resource/caching/version/LastModifiedResourceVersion.java
    
wicket/trunk/wicket-core/src/main/java/org/apache/wicket/request/resource/caching/version/MessageDigestResourceVersion.java
    
wicket/trunk/wicket-core/src/main/java/org/apache/wicket/request/resource/caching/version/RequestCycleCachedResourceVersion.java
    
wicket/trunk/wicket-core/src/main/java/org/apache/wicket/request/resource/caching/version/StaticResourceVersion.java
Removed:
    
wicket/trunk/wicket-core/src/main/java/org/apache/wicket/request/resource/caching/AbstractFilenameWithVersionResourceCachingStrategy.java
    
wicket/trunk/wicket-core/src/main/java/org/apache/wicket/request/resource/caching/AbstractResourceCachingStrategy.java
    
wicket/trunk/wicket-core/src/main/java/org/apache/wicket/request/resource/caching/FilenameWithStaticVersionResourceCachingStrategy.java
    
wicket/trunk/wicket-core/src/main/java/org/apache/wicket/request/resource/caching/FilenameWithTimestampResourceCachingStrategy.java
    
wicket/trunk/wicket-core/src/main/java/org/apache/wicket/request/resource/caching/QueryStringWithTimestampResourceCachingStrategy.java
Modified:
    
wicket/trunk/wicket-core/src/main/java/org/apache/wicket/request/resource/PackageResource.java
    
wicket/trunk/wicket-core/src/main/java/org/apache/wicket/request/resource/caching/IResourceCachingStrategy.java
    
wicket/trunk/wicket-core/src/main/java/org/apache/wicket/request/resource/caching/NoOpResourceCachingStrategy.java
    
wicket/trunk/wicket-core/src/main/java/org/apache/wicket/settings/def/ResourceSettings.java
    
wicket/trunk/wicket-core/src/test/java/org/apache/wicket/request/mapper/BasicResourceReferenceMapperTest.java

Modified: 
wicket/trunk/wicket-core/src/main/java/org/apache/wicket/request/resource/PackageResource.java
URL: 
http://svn.apache.org/viewvc/wicket/trunk/wicket-core/src/main/java/org/apache/wicket/request/resource/PackageResource.java?rev=1141298&r1=1141297&r2=1141298&view=diff
==============================================================================
--- 
wicket/trunk/wicket-core/src/main/java/org/apache/wicket/request/resource/PackageResource.java
 (original)
+++ 
wicket/trunk/wicket-core/src/main/java/org/apache/wicket/request/resource/PackageResource.java
 Wed Jun 29 22:32:59 2011
@@ -304,7 +304,7 @@ public class PackageResource extends Abs
         * 
         * @return resource stream or <code>null</code> if not found
         */
-       protected IResourceStream getResourceStream()
+       public IResourceStream getResourceStream()
        {
                // Locate resource
                return ThreadContext.getApplication()

Copied: 
wicket/trunk/wicket-core/src/main/java/org/apache/wicket/request/resource/caching/FilenameWithVersionResourceCachingStrategy.java
 (from r1141191, 
wicket/trunk/wicket-core/src/main/java/org/apache/wicket/request/resource/caching/AbstractFilenameWithVersionResourceCachingStrategy.java)
URL: 
http://svn.apache.org/viewvc/wicket/trunk/wicket-core/src/main/java/org/apache/wicket/request/resource/caching/FilenameWithVersionResourceCachingStrategy.java?p2=wicket/trunk/wicket-core/src/main/java/org/apache/wicket/request/resource/caching/FilenameWithVersionResourceCachingStrategy.java&p1=wicket/trunk/wicket-core/src/main/java/org/apache/wicket/request/resource/caching/AbstractFilenameWithVersionResourceCachingStrategy.java&r1=1141191&r2=1141298&rev=1141298&view=diff
==============================================================================
--- 
wicket/trunk/wicket-core/src/main/java/org/apache/wicket/request/resource/caching/AbstractFilenameWithVersionResourceCachingStrategy.java
 (original)
+++ 
wicket/trunk/wicket-core/src/main/java/org/apache/wicket/request/resource/caching/FilenameWithVersionResourceCachingStrategy.java
 Wed Jun 29 22:32:59 2011
@@ -19,15 +19,17 @@ package org.apache.wicket.request.resour
 import org.apache.wicket.request.http.WebResponse;
 import org.apache.wicket.request.resource.AbstractResource;
 import org.apache.wicket.request.resource.ResourceReference;
+import org.apache.wicket.request.resource.caching.version.IResourceVersion;
 import org.apache.wicket.util.lang.Args;
 
 /**
- * base resource caching strategy that adds a version string for the 
+ * resource caching strategy that adds a version string for the 
  * requested resource to the filename.
  * <p/>
- * versioned_filename := [basename][version-suffix][version](.extension)
+ * versioned_filename := [basename][version-prefix][version](.extension)
  * <p/>
- * the <code>version</code> must not contain the <code>version-suffix</code>.
+ * the <code>version</code> must not contain the <code>version-prefix</code> so
+ * please use an unambigous value for the <code>version-prefix</code>.
  * <p/> 
  * Since browsers and proxies use the versioned filename of the resource url 
  * as a cache key a change to the version will cause a cache miss and 
subsequent 
@@ -36,39 +38,64 @@ import org.apache.wicket.util.lang.Args;
  * <p/>
  * 
  * @author Peter Ertl
+ * 
+ * @since 1.5
  */
-public abstract class AbstractFilenameWithVersionResourceCachingStrategy 
-       extends AbstractResourceCachingStrategy
+public class FilenameWithVersionResourceCachingStrategy implements 
IResourceCachingStrategy
 {
+       private static final String DEFAULT_VERSION_PREFIX = "-ver-";
+       
        /** 
-        * suffix that marks the beginning the of the version 
-        * string inside the resource filename */
-       private final String versionSuffix;
+        * prefix that marks the beginning the of the version 
+        * string contained in the decorated resource filename 
+        * */
+       private final String versionPrefix;
+
+       /**
+        * resource version provider
+        */
+       private final IResourceVersion resourceVersion;
 
        /**
         * Constructor
         * 
-        * @param versionSuffix
-        *            string appended to the filename before the version string
+        * @param resourceVersion
+        *            resource version object
         */
-       public AbstractFilenameWithVersionResourceCachingStrategy(String 
versionSuffix)
+       public FilenameWithVersionResourceCachingStrategy(IResourceVersion 
resourceVersion)
        {
-               this.versionSuffix = Args.notEmpty(versionSuffix, 
"versionSuffix");
+               this(DEFAULT_VERSION_PREFIX, resourceVersion);
+       }
+
+       /**
+        * Constructor
+        * 
+        * @param versionPrefix
+        *            string appended after the base filename before the 
version string
+        *            and followed by the extension            
+        * @param resourceVersion
+        *            resource version object
+        */
+       public FilenameWithVersionResourceCachingStrategy(String versionPrefix,
+                                                         IResourceVersion 
resourceVersion)
+       {
+               this.resourceVersion = Args.notNull(resourceVersion, 
"resourceVersion");
+               this.versionPrefix = Args.notEmpty(versionPrefix, 
"versionPrefix");
        }
 
        /**
         * @return string appended to the filename before the version string
         */
-       public final String getVersionSuffix()
+       public final String getVersionPrefix()
        {
-               return versionSuffix;
+               return versionPrefix;
        }
 
        public void decorateUrl(ResourceUrl url, ResourceReference reference)
        {
                // get version string for requested resource
-               final String version = getVersionStringForResource(reference);
-               
+               final String version = 
this.resourceVersion.getVersion(reference);
+
                // ignore resource if no version information is available
                if (version == null)
                {
@@ -84,7 +111,7 @@ public abstract class AbstractFilenameWi
                // create filename with version:
                //
                // filename :=
-               // [basename][version-suffix][version](.extension)
+               // [basename][version-prefix][version](.extension)
                //
                final StringBuilder versionedFilename = new StringBuilder();
                
@@ -98,7 +125,7 @@ public abstract class AbstractFilenameWi
                        versionedFilename.append(filename.substring(0, 
extensionAt));
                }
                // add version suffix
-               versionedFilename.append(versionSuffix);
+               versionedFilename.append(versionPrefix);
                
                // add version
                versionedFilename.append(version);
@@ -126,7 +153,7 @@ public abstract class AbstractFilenameWi
                final String extension = pos == -1 ? null : 
filename.substring(pos);
 
                // get position of version string
-               pos = fullname.lastIndexOf(versionSuffix);
+               pos = fullname.lastIndexOf(versionPrefix);
 
                // remove version string if it exists
                if (pos != -1)
@@ -141,15 +168,6 @@ public abstract class AbstractFilenameWi
        }
 
        /**
-        * get string that uniquely identifies the current version of the 
resource
-        * 
-        * @param reference
-        *          resource reference
-        * @return string that uniquely identifies the current version of the 
resource
-        */
-       protected abstract String getVersionStringForResource(ResourceReference 
reference);
-
-       /**
         * set resource caching to maximum and set cache-visibility to 'public'
         * 
         * @param response

Modified: 
wicket/trunk/wicket-core/src/main/java/org/apache/wicket/request/resource/caching/IResourceCachingStrategy.java
URL: 
http://svn.apache.org/viewvc/wicket/trunk/wicket-core/src/main/java/org/apache/wicket/request/resource/caching/IResourceCachingStrategy.java?rev=1141298&r1=1141297&r2=1141298&view=diff
==============================================================================
--- 
wicket/trunk/wicket-core/src/main/java/org/apache/wicket/request/resource/caching/IResourceCachingStrategy.java
 (original)
+++ 
wicket/trunk/wicket-core/src/main/java/org/apache/wicket/request/resource/caching/IResourceCachingStrategy.java
 Wed Jun 29 22:32:59 2011
@@ -22,10 +22,13 @@ import org.apache.wicket.request.resourc
 /**
  * caching strategy for resources
  * <p/>
- * it can add and remove caching information to the filename and query string 
parameters of the
- * requested resource
+ * it can add and remove caching information to the filename and query 
+ * string parameters of the requested resource to control caches in the
+ * browser and on the internet. It also can set http response caching headers.
  * 
  * @author Peter Ertl
+ * 
+ * @since 1.5
  */
 public interface IResourceCachingStrategy
 {

Modified: 
wicket/trunk/wicket-core/src/main/java/org/apache/wicket/request/resource/caching/NoOpResourceCachingStrategy.java
URL: 
http://svn.apache.org/viewvc/wicket/trunk/wicket-core/src/main/java/org/apache/wicket/request/resource/caching/NoOpResourceCachingStrategy.java?rev=1141298&r1=1141297&r2=1141298&view=diff
==============================================================================
--- 
wicket/trunk/wicket-core/src/main/java/org/apache/wicket/request/resource/caching/NoOpResourceCachingStrategy.java
 (original)
+++ 
wicket/trunk/wicket-core/src/main/java/org/apache/wicket/request/resource/caching/NoOpResourceCachingStrategy.java
 Wed Jun 29 22:32:59 2011
@@ -21,13 +21,17 @@ import org.apache.wicket.request.resourc
 
 /**
  * resource caching strategy that does nothing
+ * <p/>
+ * caching will resources will effectively be disabled
  * 
  * @author Peter Ertl
+ * 
+ * @since 1.5
  */
 public class NoOpResourceCachingStrategy implements IResourceCachingStrategy
 {
        /**
-        * Global instance of noop strategy
+        * Global instance of {@link NoOpResourceCachingStrategy} strategy
         */
        public static final IResourceCachingStrategy INSTANCE = new 
NoOpResourceCachingStrategy();
 

Copied: 
wicket/trunk/wicket-core/src/main/java/org/apache/wicket/request/resource/caching/QueryStringWithVersionResourceCachingStrategy.java
 (from r1141191, 
wicket/trunk/wicket-core/src/main/java/org/apache/wicket/request/resource/caching/QueryStringWithTimestampResourceCachingStrategy.java)
URL: 
http://svn.apache.org/viewvc/wicket/trunk/wicket-core/src/main/java/org/apache/wicket/request/resource/caching/QueryStringWithVersionResourceCachingStrategy.java?p2=wicket/trunk/wicket-core/src/main/java/org/apache/wicket/request/resource/caching/QueryStringWithVersionResourceCachingStrategy.java&p1=wicket/trunk/wicket-core/src/main/java/org/apache/wicket/request/resource/caching/QueryStringWithTimestampResourceCachingStrategy.java&r1=1141191&r2=1141298&rev=1141298&view=diff
==============================================================================
--- 
wicket/trunk/wicket-core/src/main/java/org/apache/wicket/request/resource/caching/QueryStringWithTimestampResourceCachingStrategy.java
 (original)
+++ 
wicket/trunk/wicket-core/src/main/java/org/apache/wicket/request/resource/caching/QueryStringWithVersionResourceCachingStrategy.java
 Wed Jun 29 22:32:59 2011
@@ -20,57 +20,73 @@ import org.apache.wicket.request.http.We
 import org.apache.wicket.request.mapper.parameter.INamedParameters;
 import org.apache.wicket.request.resource.AbstractResource;
 import org.apache.wicket.request.resource.ResourceReference;
+import org.apache.wicket.request.resource.caching.version.IResourceVersion;
 import org.apache.wicket.util.lang.Args;
-import org.apache.wicket.util.time.Time;
 
 /**
  * resource caching strategy that adds a last-modified timestamp to the query 
string of the resource
  * (this is similar to how wicket 1.4 does it when enabling timestamps on 
resources).
  * 
  * @author Peter Ertl
+ * 
+ * @since 1.5
  */
-public class QueryStringWithTimestampResourceCachingStrategy extends
-       AbstractResourceCachingStrategy
+public class QueryStringWithVersionResourceCachingStrategy implements 
IResourceCachingStrategy
 {
-       private static final String DEFAULT_TIMESTAMP_PARAMETER = "ts";
+       private static final String DEFAULT_VERSION_PARAMETER = "ver";
+
+       /**
+        * query string parameter name that contains the version string for the 
resource
+        */
+       private final String versionParameter;
 
-       private final String timestampParameter;
+       /**
+        * resource version provider
+        */
+       private final IResourceVersion resourceVersion;
 
        /**
         * Constructor
+        * 
+        * @param resourceVersion
+        *                resource version provider
         */
-       public QueryStringWithTimestampResourceCachingStrategy()
+       public QueryStringWithVersionResourceCachingStrategy(IResourceVersion 
resourceVersion)
        {
-               this(DEFAULT_TIMESTAMP_PARAMETER);
+               this(DEFAULT_VERSION_PARAMETER, resourceVersion);
        }
 
        /**
         * Constructor
-        * 
-        * @param timestampParameter
+        *
+        * @param versionParameter
         *            name of timestamp parameter which will be added to query 
string
+        *            and contain the resource version string
+        * @param resourceVersion
+        *                resource version provider
         */
-       public QueryStringWithTimestampResourceCachingStrategy(String 
timestampParameter)
+       public QueryStringWithVersionResourceCachingStrategy(String 
versionParameter, 
+                                                            IResourceVersion 
resourceVersion)
        {
-               Args.notEmpty(timestampParameter, "timestampParameter");
-               this.timestampParameter = timestampParameter;
+               this.versionParameter = Args.notEmpty(versionParameter, 
"timestampParameter");
+               this.resourceVersion = Args.notNull(resourceVersion, 
"resourceVersion");
        }
 
        /**
         * @return name of timestamp parameter which will be added to query 
string
         */
-       public final String getTimestampParameter()
+       public final String getVersionParameter()
        {
-               return timestampParameter;
+               return versionParameter;
        }
 
        public void decorateUrl(ResourceUrl url, final ResourceReference 
reference)
        {
-               Time lastModified = getLastModified(reference);
+               String version = resourceVersion.getVersion(reference);
 
-               if (lastModified != null)
+               if (version != null)
                {
-                       url.getParameters().set(timestampParameter, 
lastModified.getMilliseconds());
+                       url.getParameters().set(versionParameter, version);
                }
        }
 
@@ -80,7 +96,7 @@ public class QueryStringWithTimestampRes
                
                if (parameters != null)
                {
-                       parameters.remove(timestampParameter);
+                       parameters.remove(versionParameter);
                }
        }
 

Added: 
wicket/trunk/wicket-core/src/main/java/org/apache/wicket/request/resource/caching/version/CachingResourceVersion.java
URL: 
http://svn.apache.org/viewvc/wicket/trunk/wicket-core/src/main/java/org/apache/wicket/request/resource/caching/version/CachingResourceVersion.java?rev=1141298&view=auto
==============================================================================
--- 
wicket/trunk/wicket-core/src/main/java/org/apache/wicket/request/resource/caching/version/CachingResourceVersion.java
 (added)
+++ 
wicket/trunk/wicket-core/src/main/java/org/apache/wicket/request/resource/caching/version/CachingResourceVersion.java
 Wed Jun 29 22:32:59 2011
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.wicket.request.resource.caching.version;
+
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+import org.apache.wicket.request.resource.ResourceReference;
+import org.apache.wicket.util.lang.Args;
+
+/**
+ * Caches the results of a delegating {@link IResourceVersion} instance
+ * 
+ * @autor Peter Ertl
+ * 
+ * @since 1.5
+ */
+public class CachingResourceVersion implements IResourceVersion
+{
+       private static final String NULL_VALUE = "null";
+
+       private final IResourceVersion delegate;
+       private final ConcurrentMap<ResourceReference, String> cache;
+
+       public CachingResourceVersion(IResourceVersion delegate)
+       {
+               this.delegate = Args.notNull(delegate, "delegate");
+               this.cache = new ConcurrentHashMap<ResourceReference, String>();
+       }
+
+       public String getVersion(ResourceReference resourceReference)
+       {
+               String version = cache.get(resourceReference);
+
+               if (version == null)
+               {
+                       version = delegate.getVersion(resourceReference);
+
+                       if (version == null)
+                       {
+                               version = NULL_VALUE;
+                       }
+                       cache.put(resourceReference, version);
+               }
+
+               //noinspection StringEquality
+               if (version == NULL_VALUE)
+               {
+                       return null;
+               }
+               return version;
+       }
+}

Added: 
wicket/trunk/wicket-core/src/main/java/org/apache/wicket/request/resource/caching/version/IResourceVersion.java
URL: 
http://svn.apache.org/viewvc/wicket/trunk/wicket-core/src/main/java/org/apache/wicket/request/resource/caching/version/IResourceVersion.java?rev=1141298&view=auto
==============================================================================
--- 
wicket/trunk/wicket-core/src/main/java/org/apache/wicket/request/resource/caching/version/IResourceVersion.java
 (added)
+++ 
wicket/trunk/wicket-core/src/main/java/org/apache/wicket/request/resource/caching/version/IResourceVersion.java
 Wed Jun 29 22:32:59 2011
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.wicket.request.resource.caching.version;
+
+import org.apache.wicket.request.resource.ResourceReference;
+
+/**
+ * Provides a version string for a resource specified by {@link 
ResourceReference} 
+ * <p/>
+ * the version string will be used as a caching key for resources
+ * 
+ * @see 
org.apache.wicket.request.resource.caching.QueryStringWithVersionResourceCachingStrategy
+ * @see 
org.apache.wicket.request.resource.caching.FilenameWithVersionResourceCachingStrategy
+ * 
+ * @author Peter Ertl
+ * 
+ * @since 1.5
+ */
+public interface IResourceVersion
+{
+       /**
+        * get unique string identifying the version of the resource
+        * 
+        * @param resourceReference
+        *             reference to resource
+        * @return unique version string
+        */
+       String getVersion(ResourceReference resourceReference);
+}

Added: 
wicket/trunk/wicket-core/src/main/java/org/apache/wicket/request/resource/caching/version/LastModifiedResourceVersion.java
URL: 
http://svn.apache.org/viewvc/wicket/trunk/wicket-core/src/main/java/org/apache/wicket/request/resource/caching/version/LastModifiedResourceVersion.java?rev=1141298&view=auto
==============================================================================
--- 
wicket/trunk/wicket-core/src/main/java/org/apache/wicket/request/resource/caching/version/LastModifiedResourceVersion.java
 (added)
+++ 
wicket/trunk/wicket-core/src/main/java/org/apache/wicket/request/resource/caching/version/LastModifiedResourceVersion.java
 Wed Jun 29 22:32:59 2011
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.wicket.request.resource.caching.version;
+
+import org.apache.wicket.request.resource.ResourceReference;
+import org.apache.wicket.util.time.Time;
+
+/**
+ * Uses the last modified timestamp of a {@link ResourceReference} 
+ * in milliseconds as a version string.
+ *
+ * @author Peter Ertl
+ *
+ * @since 1.5
+ */
+public class LastModifiedResourceVersion implements IResourceVersion
+{
+       public String getVersion(ResourceReference resourceReference)
+       {
+               final Time lastModified = resourceReference.getLastModified();
+
+               if (lastModified == null)
+               {
+                       return null;
+               }
+               return String.valueOf(lastModified.getMilliseconds());
+       }
+}

Added: 
wicket/trunk/wicket-core/src/main/java/org/apache/wicket/request/resource/caching/version/MessageDigestResourceVersion.java
URL: 
http://svn.apache.org/viewvc/wicket/trunk/wicket-core/src/main/java/org/apache/wicket/request/resource/caching/version/MessageDigestResourceVersion.java?rev=1141298&view=auto
==============================================================================
--- 
wicket/trunk/wicket-core/src/main/java/org/apache/wicket/request/resource/caching/version/MessageDigestResourceVersion.java
 (added)
+++ 
wicket/trunk/wicket-core/src/main/java/org/apache/wicket/request/resource/caching/version/MessageDigestResourceVersion.java
 Wed Jun 29 22:32:59 2011
@@ -0,0 +1,188 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.wicket.request.resource.caching.version;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.math.BigInteger;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+
+import org.apache.wicket.WicketRuntimeException;
+import org.apache.wicket.request.resource.IResource;
+import org.apache.wicket.request.resource.PackageResource;
+import org.apache.wicket.request.resource.ResourceReference;
+import org.apache.wicket.util.io.IOUtils;
+import org.apache.wicket.util.lang.Args;
+import org.apache.wicket.util.resource.IResourceStream;
+import org.apache.wicket.util.resource.ResourceStreamNotFoundException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * uses the message digest of a {@link PackageResource} as a version string
+ *
+ * @author Peter Ertl
+ *
+ * @since 1.5
+ */
+public class MessageDigestResourceVersion implements IResourceVersion
+{
+       private static final Logger log = 
LoggerFactory.getLogger(MessageDigestResourceVersion.class);
+
+       private static final String DEFAULT_ALGORITHM = "MD5";
+       private static final int DEFAULT_BUFFER_SIZE = 8192;
+
+       /** message digest algorithm for computing hashes */
+       private final String algorithm;
+
+       /** buffer size for computing the digest */
+       private final int bufferSize;
+
+       /**
+        * create an instance using {@value #DEFAULT_ALGORITHM}
+        */
+       public MessageDigestResourceVersion()
+       {
+               this(DEFAULT_ALGORITHM, DEFAULT_BUFFER_SIZE);
+       }
+
+       /**
+        * create an instance using an algorihm that can be 
+        * retrieved by Java Cryptography Architecture (JCA) 
+        * using {@link MessageDigest#getInstance(String)} and 
+        * using an fixed-size internal buffer for digest computation of
+        * {@value #DEFAULT_BUFFER_SIZE} bytes.
+        *
+        * @param algorithm
+        *           digest algorithm
+        */
+       public MessageDigestResourceVersion(String algorithm)
+       {
+               this(algorithm, DEFAULT_BUFFER_SIZE);
+       }
+
+       /**
+        * create an instance using an algorihm that can be 
+        * retrieved by Java Cryptography Architecture (JCA) 
+        * using {@link MessageDigest#getInstance(String)} and 
+        * using an specified internal buffer for digest computation.
+        *
+        * @param algorithm
+        *           digest algorithm
+        * @param bufferSize
+        *           internal buffer size for digest computation
+        */
+       public MessageDigestResourceVersion(String algorithm, int bufferSize)
+       {
+               this.algorithm = Args.notEmpty(algorithm, "algorithm");
+               this.bufferSize = bufferSize;
+       }
+
+       public String getVersion(ResourceReference resourceReference)
+       {
+               final IResource resource = resourceReference.getResource();
+
+               if (PackageResource.class.isInstance(resource) == false)
+               {
+                       log.warn("message digests are only available with 
package " +
+                                "resource, not with " + resourceReference);
+
+                       return null;
+               }
+
+               // get resource data
+               final PackageResource packageResource = 
(PackageResource)resource;
+               final IResourceStream resourceStream = 
packageResource.getResourceStream();
+
+               if (resourceStream == null)
+               {
+                       log.debug("could not get resource stream for " + 
resource);
+                       return null;
+               }
+
+               try
+               {
+                       // get binary hash
+                       final byte[] hash = computeDigest(resourceStream);
+
+                       // convert to hexadecimal
+                       return new BigInteger(hash).toString(16);
+               }
+               catch (ResourceStreamNotFoundException e)
+               {
+                       log.warn("resource stream not found for " + resource);
+                       return null;
+               }
+               catch (IOException e)
+               {
+                       log.warn("resource stream not be read for " + resource, 
e);
+                       return null;
+               }
+       }
+
+       /**
+        * get instance of message digest provider from JCA
+        * 
+        * @return message digest provider
+        */
+       protected MessageDigest getMessageDigest()
+       {
+               try
+               {
+                       return MessageDigest.getInstance(algorithm);
+               }
+               catch (NoSuchAlgorithmException e)
+               {
+                       throw new WicketRuntimeException("message digest " + 
algorithm + " not found", e);
+               }
+       }
+
+       /**
+        * compute digest for resource stream
+        * 
+        * @param resourceStream
+        *           resource stream to compute message digest for
+        * 
+        * @return binary message digest
+        * 
+        * @throws ResourceStreamNotFoundException
+        * @throws IOException
+        */
+       protected byte[] computeDigest(IResourceStream resourceStream)
+               throws ResourceStreamNotFoundException, IOException
+       {
+               final MessageDigest digest = getMessageDigest();
+               final InputStream inputStream = resourceStream.getInputStream();
+
+               try
+               {
+                       final byte[] buf = new byte[bufferSize];
+                       int len;
+
+                       while ((len = inputStream.read(buf)) != -1)
+                       {
+                               digest.update(buf, 0, len);
+                       }
+                       return digest.digest();
+               }
+               finally
+               {
+                       IOUtils.closeQuietly(inputStream);
+               }
+       }
+}

Added: 
wicket/trunk/wicket-core/src/main/java/org/apache/wicket/request/resource/caching/version/RequestCycleCachedResourceVersion.java
URL: 
http://svn.apache.org/viewvc/wicket/trunk/wicket-core/src/main/java/org/apache/wicket/request/resource/caching/version/RequestCycleCachedResourceVersion.java?rev=1141298&view=auto
==============================================================================
--- 
wicket/trunk/wicket-core/src/main/java/org/apache/wicket/request/resource/caching/version/RequestCycleCachedResourceVersion.java
 (added)
+++ 
wicket/trunk/wicket-core/src/main/java/org/apache/wicket/request/resource/caching/version/RequestCycleCachedResourceVersion.java
 Wed Jun 29 22:32:59 2011
@@ -0,0 +1,99 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.wicket.request.resource.caching.version;
+
+import java.util.Map;
+
+import org.apache.wicket.MetaDataKey;
+import org.apache.wicket.ThreadContext;
+import org.apache.wicket.request.cycle.RequestCycle;
+import org.apache.wicket.request.resource.ResourceReference;
+import org.apache.wicket.util.lang.Args;
+import org.apache.wicket.util.lang.Generics;
+
+/**
+ * Caches the results of a delegating {@link IResourceVersion} instance
+ * in the current request meta data. It will be cached for the lifetime
+ * of the current http request.
+ *
+ * @author Peter Ertl
+ *
+ * @since 1.5
+ */
+public class RequestCycleCachedResourceVersion implements IResourceVersion
+{
+       private static final MetaDataKey<Map<ResourceReference, String>> 
CACHE_KEY =
+               new MetaDataKey<Map<ResourceReference, String>>()
+               {
+                       private static final long serialVersionUID = 1L;
+               };
+
+       /**
+        * resource version provider which will actually do 
+        * the work and retrieve the version
+        */
+       private final IResourceVersion delegate;
+
+       /**
+        * Constructor
+        * 
+        * @param delegate
+        *           resource version provider to cache
+        */
+       public RequestCycleCachedResourceVersion(IResourceVersion delegate)
+       {
+               this.delegate = Args.notNull(delegate, "delegate");
+       }
+
+       public String getVersion(ResourceReference resourceReference)
+       {
+               // get current request cycle
+               final RequestCycle requestCycle = 
ThreadContext.getRequestCycle();
+
+               Map<ResourceReference, String> cache = null;
+
+               // is request cycle available?
+               if (requestCycle != null)
+               {
+                       // retrieve cache from current request cycle
+                       cache = requestCycle.getMetaData(CACHE_KEY);
+
+                       // create it on first call
+                       if (cache == null)
+                       {
+                               requestCycle.setMetaData(CACHE_KEY, cache = 
Generics.newHashMap());
+                       }
+                       
+                       // lookup timestamp from cache (may contain NULL values 
which are valid)
+                       if (cache.containsKey(resourceReference))
+                       {
+                               return cache.get(resourceReference);
+                       }
+               }
+               
+               // no cache entry found, query version from delegate
+               final String version = delegate.getVersion(resourceReference);
+
+               // store value in cache (if it is available)
+               if (cache != null)
+               {
+                       cache.put(resourceReference, version);
+               }
+               
+               return version;
+       }
+}

Added: 
wicket/trunk/wicket-core/src/main/java/org/apache/wicket/request/resource/caching/version/StaticResourceVersion.java
URL: 
http://svn.apache.org/viewvc/wicket/trunk/wicket-core/src/main/java/org/apache/wicket/request/resource/caching/version/StaticResourceVersion.java?rev=1141298&view=auto
==============================================================================
--- 
wicket/trunk/wicket-core/src/main/java/org/apache/wicket/request/resource/caching/version/StaticResourceVersion.java
 (added)
+++ 
wicket/trunk/wicket-core/src/main/java/org/apache/wicket/request/resource/caching/version/StaticResourceVersion.java
 Wed Jun 29 22:32:59 2011
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.wicket.request.resource.caching.version;
+
+import org.apache.wicket.request.resource.ResourceReference;
+import org.apache.wicket.util.lang.Args;
+
+/**
+ * provides a static version string for all queries resources 
+ *
+ * @author Peter Ertl
+ *
+ * @since 1.5
+ */
+public class StaticResourceVersion implements IResourceVersion
+{
+       private final String version;
+
+       /**
+        * Constructor
+        *
+        * @param version
+        *             static version string to deliver for all queries 
resources
+        */
+       public StaticResourceVersion(String version)
+       {
+               this.version = Args.notNull(version, "version");
+       }
+
+       public String getVersion(ResourceReference resourceReference)
+       {
+               return version;
+       }
+}

Modified: 
wicket/trunk/wicket-core/src/main/java/org/apache/wicket/settings/def/ResourceSettings.java
URL: 
http://svn.apache.org/viewvc/wicket/trunk/wicket-core/src/main/java/org/apache/wicket/settings/def/ResourceSettings.java?rev=1141298&r1=1141297&r2=1141298&view=diff
==============================================================================
--- 
wicket/trunk/wicket-core/src/main/java/org/apache/wicket/settings/def/ResourceSettings.java
 (original)
+++ 
wicket/trunk/wicket-core/src/main/java/org/apache/wicket/settings/def/ResourceSettings.java
 Wed Jun 29 22:32:59 2011
@@ -27,9 +27,14 @@ import org.apache.wicket.javascript.IJav
 import org.apache.wicket.markup.html.IPackageResourceGuard;
 import org.apache.wicket.markup.html.PackageResourceGuard;
 import org.apache.wicket.request.http.WebResponse;
-import 
org.apache.wicket.request.resource.caching.FilenameWithTimestampResourceCachingStrategy;
+import 
org.apache.wicket.request.resource.caching.FilenameWithVersionResourceCachingStrategy;
 import org.apache.wicket.request.resource.caching.IResourceCachingStrategy;
 import org.apache.wicket.request.resource.caching.NoOpResourceCachingStrategy;
+import 
org.apache.wicket.request.resource.caching.version.CachingResourceVersion;
+import org.apache.wicket.request.resource.caching.version.IResourceVersion;
+import 
org.apache.wicket.request.resource.caching.version.LastModifiedResourceVersion;
+import 
org.apache.wicket.request.resource.caching.version.MessageDigestResourceVersion;
+import 
org.apache.wicket.request.resource.caching.version.RequestCycleCachedResourceVersion;
 import org.apache.wicket.resource.PropertiesFactory;
 import org.apache.wicket.resource.loader.ClassStringResourceLoader;
 import org.apache.wicket.resource.loader.ComponentStringResourceLoader;
@@ -112,8 +117,10 @@ public class ResourceSettings implements
        private String parentFolderPlaceholder = null;
 
        // resource caching strategy
-       private IResourceCachingStrategy resourceCachingStrategy = new 
FilenameWithTimestampResourceCachingStrategy();
-
+       private IResourceCachingStrategy resourceCachingStrategy;
+       
+       // application these settings are bound to
+       private final Application application;
 
        /**
         * Construct
@@ -122,6 +129,7 @@ public class ResourceSettings implements
         */
        public ResourceSettings(final Application application)
        {
+               this.application = application;
                stringResourceLoaders.add(new ComponentStringResourceLoader());
                stringResourceLoaders.add(new PackageStringResourceLoader());
                stringResourceLoaders.add(new 
ClassStringResourceLoader(application.getClass()));
@@ -426,6 +434,23 @@ public class ResourceSettings implements
         */
        public IResourceCachingStrategy getCachingStrategy()
        {
+               if (resourceCachingStrategy == null)
+               {
+                       final IResourceVersion resourceVersion;
+
+                       if (application.usesDevelopmentConfig())
+                       {
+                               // use file last modified for resource cache 
keys
+                               resourceVersion = new 
RequestCycleCachedResourceVersion(new LastModifiedResourceVersion());
+                       }
+                       else
+                       {
+                               // use md5 message digest for resource cache 
keys
+                               resourceVersion = new 
CachingResourceVersion(new MessageDigestResourceVersion());
+                       }
+                       resourceCachingStrategy =
+                               new 
FilenameWithVersionResourceCachingStrategy(resourceVersion);
+               }
                return resourceCachingStrategy;
        }
 

Modified: 
wicket/trunk/wicket-core/src/test/java/org/apache/wicket/request/mapper/BasicResourceReferenceMapperTest.java
URL: 
http://svn.apache.org/viewvc/wicket/trunk/wicket-core/src/test/java/org/apache/wicket/request/mapper/BasicResourceReferenceMapperTest.java?rev=1141298&r1=1141297&r2=1141298&view=diff
==============================================================================
--- 
wicket/trunk/wicket-core/src/test/java/org/apache/wicket/request/mapper/BasicResourceReferenceMapperTest.java
 (original)
+++ 
wicket/trunk/wicket-core/src/test/java/org/apache/wicket/request/mapper/BasicResourceReferenceMapperTest.java
 Wed Jun 29 22:32:59 2011
@@ -18,26 +18,23 @@ package org.apache.wicket.request.mapper
 
 import java.util.Locale;
 
-import org.apache.wicket.ThreadContext;
 import org.apache.wicket.request.IRequestHandler;
 import org.apache.wicket.request.Url;
-import org.apache.wicket.request.cycle.RequestCycle;
 import 
org.apache.wicket.request.handler.resource.ResourceReferenceRequestHandler;
 import org.apache.wicket.request.mapper.parameter.INamedParameters;
 import org.apache.wicket.request.mapper.parameter.PageParameters;
 import org.apache.wicket.request.mapper.parameter.PageParametersEncoder;
 import org.apache.wicket.request.resource.IResource;
 import org.apache.wicket.request.resource.ResourceReference;
-import 
org.apache.wicket.request.resource.caching.FilenameWithStaticVersionResourceCachingStrategy;
-import 
org.apache.wicket.request.resource.caching.FilenameWithTimestampResourceCachingStrategy;
+import 
org.apache.wicket.request.resource.caching.FilenameWithVersionResourceCachingStrategy;
 import org.apache.wicket.request.resource.caching.IResourceCachingStrategy;
 import org.apache.wicket.request.resource.caching.NoOpResourceCachingStrategy;
 import org.apache.wicket.request.resource.caching.ResourceUrl;
+import 
org.apache.wicket.request.resource.caching.version.LastModifiedResourceVersion;
+import 
org.apache.wicket.request.resource.caching.version.StaticResourceVersion;
 import org.apache.wicket.util.IProvider;
 import org.apache.wicket.util.ValueProvider;
-import org.apache.wicket.util.tester.WicketTester;
 import org.apache.wicket.util.time.Time;
-import org.mockito.Mockito;
 
 /**
  * @author Matej Knopp
@@ -47,8 +44,9 @@ public class BasicResourceReferenceMappe
        private static final IProvider<IResourceCachingStrategy> NO_CACHING = 
new ValueProvider<IResourceCachingStrategy>(
                NoOpResourceCachingStrategy.INSTANCE);
 
-       private static final 
IProvider<FilenameWithTimestampResourceCachingStrategy> 
CACHE_FILENAME_WITH_TIMESTAMP = new 
ValueProvider<FilenameWithTimestampResourceCachingStrategy>(
-               new FilenameWithTimestampResourceCachingStrategy());
+       private static final 
IProvider<FilenameWithVersionResourceCachingStrategy> 
CACHE_FILENAME_WITH_TIMESTAMP =
+               new ValueProvider<FilenameWithVersionResourceCachingStrategy>(
+                       new FilenameWithVersionResourceCachingStrategy(new 
LastModifiedResourceVersion()));
 
        /**
         * Construct.
@@ -461,47 +459,11 @@ public class BasicResourceReferenceMappe
                Url url = encoderWithTimestamps.mapHandler(handler);
 
                // check that url contains timestamp
-               String timestampPart = 
CACHE_FILENAME_WITH_TIMESTAMP.get().getVersionSuffix() +
+               String timestampPart = 
CACHE_FILENAME_WITH_TIMESTAMP.get().getVersionPrefix() +
                        Long.toString(millis) + "?";
                assertTrue(url.toString().contains(timestampPart));
        }
 
-       /**
-        * 
-        */
-       public void testLastModifiedTimestampCache()
-       {
-               long millis = 87654321L;
-               final ResourceReferenceWithTimestamp reference = new 
ResourceReferenceWithTimestamp(
-                       Time.millis(millis));
-               final IRequestHandler handler = new 
ResourceReferenceRequestHandler(reference, null);
-
-               WicketTester tester = new WicketTester();
-
-               // setup mock request cycle
-               RequestCycle cycle = Mockito.mock(RequestCycle.class);
-               ThreadContext.setRequestCycle(cycle);
-
-               // request url with timestamp
-               Url url1 = encoderWithTimestamps.mapHandler(handler);
-               assertNotNull(url1);
-               assertEquals(1, reference.lastModifiedInvocationCount);
-
-               // subsequent request should take timestamp from request cycle 
scoped cache
-               Url url2 = encoderWithTimestamps.mapHandler(handler);
-               assertNotNull(url2);
-
-               Url url3 = encoderWithTimestamps.mapHandler(handler);
-               assertNotNull(url3);
-
-               assertEquals(1, reference.lastModifiedInvocationCount);
-
-               // urls should be equal
-               assertEquals(url1, url2);
-               assertEquals(url1, url3);
-               tester.destroy();
-       }
-
        public void testVersionStringInResourceFilename()
        {
                final IResource resource = new IResource()
@@ -521,8 +483,8 @@ public class BasicResourceReferenceMappe
                                }
                        };
 
-               FilenameWithStaticVersionResourceCachingStrategy strategy =
-                       new 
FilenameWithStaticVersionResourceCachingStrategy("-version-", "foobar");
+               IResourceCachingStrategy strategy =
+                       new 
FilenameWithVersionResourceCachingStrategy("-version-", new 
StaticResourceVersion("foobar"));
 
                INamedParameters params = new PageParameters();
                ResourceUrl url = new ResourceUrl("test.js", params);
@@ -562,7 +524,7 @@ public class BasicResourceReferenceMappe
                assertEquals("test.txt", url.getFileName());
 
                // check a version that contains a dot which also marks the 
filename extension
-               strategy = new 
FilenameWithStaticVersionResourceCachingStrategy("-version-", "1.0.4-beta");
+               strategy = new 
FilenameWithVersionResourceCachingStrategy("-version-", new 
StaticResourceVersion("1.0.4-beta"));
                url = new ResourceUrl("test.txt", params);
                strategy.decorateUrl(url, reference);
                assertEquals("test-version-1.0.4-beta.txt", url.getFileName());


Reply via email to