You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@wicket.apache.org by iv...@apache.org on 2010/08/31 23:35:32 UTC

svn commit: r991339 - in /wicket/trunk/wicket/src: main/java/org/apache/wicket/ main/java/org/apache/wicket/mock/ main/java/org/apache/wicket/request/mapper/ main/java/org/apache/wicket/request/resource/ main/java/org/apache/wicket/settings/ test/java/...

Author: ivaynberg
Date: Tue Aug 31 21:35:31 2010
New Revision: 991339

URL: http://svn.apache.org/viewvc?rev=991339&view=rev
Log:
applied 3021 patch
Issue: WICKET-3021

Modified:
    wicket/trunk/wicket/src/main/java/org/apache/wicket/SystemMapper.java
    wicket/trunk/wicket/src/main/java/org/apache/wicket/mock/MockApplication.java
    wicket/trunk/wicket/src/main/java/org/apache/wicket/request/mapper/BasicResourceReferenceMapper.java
    wicket/trunk/wicket/src/main/java/org/apache/wicket/request/mapper/ResourceReferenceMapper.java
    wicket/trunk/wicket/src/main/java/org/apache/wicket/request/resource/PackageResourceReference.java
    wicket/trunk/wicket/src/main/java/org/apache/wicket/request/resource/ResourceReference.java
    wicket/trunk/wicket/src/main/java/org/apache/wicket/settings/IResourceSettings.java
    wicket/trunk/wicket/src/main/java/org/apache/wicket/settings/Settings.java
    wicket/trunk/wicket/src/test/java/org/apache/wicket/request/mapper/BasicResourceReferenceMapperTest.java

Modified: wicket/trunk/wicket/src/main/java/org/apache/wicket/SystemMapper.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket/src/main/java/org/apache/wicket/SystemMapper.java?rev=991339&r1=991338&r2=991339&view=diff
==============================================================================
--- wicket/trunk/wicket/src/main/java/org/apache/wicket/SystemMapper.java (original)
+++ wicket/trunk/wicket/src/main/java/org/apache/wicket/SystemMapper.java Tue Aug 31 21:35:31 2010
@@ -24,7 +24,7 @@ import org.apache.wicket.request.mapper.
 import org.apache.wicket.request.mapper.ResourceReferenceMapper;
 import org.apache.wicket.request.mapper.parameter.PageParametersEncoder;
 import org.apache.wicket.util.IProvider;
-
+import org.apache.wicket.util.ValueProvider;
 
 /**
  * Mapper that encapsulates mappers that are necessary for Wicket to function.
@@ -34,20 +34,35 @@ import org.apache.wicket.util.IProvider;
  */
 public class SystemMapper extends CompoundRequestMapper
 {
+	private final Application application;
+
 	/**
 	 * Constructor
 	 */
 	public SystemMapper(Application application)
 	{
+		this.application = application;
 		add(RestartResponseAtInterceptPageException.MAPPER);
 		add(new HomePageMapper());
 		add(new PageInstanceMapper());
 		add(new BookmarkableMapper());
 		add(new ResourceReferenceMapper(new PageParametersEncoder(),
-			new ParentFolderPlaceholderProvider(application)));
+			                              new ParentFolderPlaceholderProvider(application),
+			                              useTimestampsProvider()));
 		add(new BufferedResponseMapper());
 	}
 
+	private IProvider<Boolean> useTimestampsProvider()
+	{
+		return new IProvider<Boolean>()
+		{
+			public Boolean get()
+			{
+				return application.getResourceSettings().getUseTimestampOnResources();
+			}
+		};
+	}
+
 	private static class ParentFolderPlaceholderProvider implements IProvider<String>
 	{
 		private final Application application;

Modified: wicket/trunk/wicket/src/main/java/org/apache/wicket/mock/MockApplication.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket/src/main/java/org/apache/wicket/mock/MockApplication.java?rev=991339&r1=991338&r2=991339&view=diff
==============================================================================
--- wicket/trunk/wicket/src/main/java/org/apache/wicket/mock/MockApplication.java (original)
+++ wicket/trunk/wicket/src/main/java/org/apache/wicket/mock/MockApplication.java Tue Aug 31 21:35:31 2010
@@ -62,6 +62,7 @@ public class MockApplication extends Web
 		super.internalInit();
 		setSessionStoreProvider(new MockSessionStoreProvider());
 		setPageManagerProvider(new MockPageManagerProvider());
+		getResourceSettings().setUseTimestampOnResources(false);
 	}
 
 	private static class MockSessionStoreProvider implements IProvider<ISessionStore>

Modified: wicket/trunk/wicket/src/main/java/org/apache/wicket/request/mapper/BasicResourceReferenceMapper.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket/src/main/java/org/apache/wicket/request/mapper/BasicResourceReferenceMapper.java?rev=991339&r1=991338&r2=991339&view=diff
==============================================================================
--- wicket/trunk/wicket/src/main/java/org/apache/wicket/request/mapper/BasicResourceReferenceMapper.java (original)
+++ wicket/trunk/wicket/src/main/java/org/apache/wicket/request/mapper/BasicResourceReferenceMapper.java Tue Aug 31 21:35:31 2010
@@ -22,47 +22,48 @@ import org.apache.wicket.request.Url;
 import org.apache.wicket.request.handler.resource.ResourceReferenceRequestHandler;
 import org.apache.wicket.request.mapper.parameter.IPageParametersEncoder;
 import org.apache.wicket.request.mapper.parameter.PageParameters;
-import org.apache.wicket.request.mapper.parameter.PageParametersEncoder;
 import org.apache.wicket.request.resource.ResourceReference;
+import org.apache.wicket.util.IProvider;
 import org.apache.wicket.util.lang.WicketObjects;
+import org.apache.wicket.util.time.Time;
+
+import java.util.List;
+import java.util.StringTokenizer;
 
 /**
  * Generic {@link ResourceReference} encoder that encodes and decodes non-mounted
  * {@link ResourceReference}s.
  * <p>
  * Decodes and encodes the following URLs:
- * 
+ *
  * <pre>
  *    /wicket/resource/org.apache.wicket.ResourceScope/name
  *    /wicket/resource/org.apache.wicket.ResourceScope/name?en
  *    /wicket/resource/org.apache.wicket.ResourceScope/name?-style
  *    /wicket/resource/org.apache.wicket.ResourceScope/resource/name.xyz?en_EN-style
  * </pre>
- * 
+ *
  * @author Matej Knopp
  * @author igor.vaynberg
  */
 class BasicResourceReferenceMapper extends AbstractResourceReferenceMapper
 {
+	private static final String TIMESTAMP_PREFIX = "-ts";
 	private final IPageParametersEncoder pageParametersEncoder;
 
+	// if true, timestamps should be added to resource names
+	private final IProvider<Boolean> timestamps;
+
 	/**
 	 * Construct.
-	 * 
+	 *
 	 * @param pageParametersEncoder
 	 * @param relativePathPartEscapeSequence
 	 */
-	public BasicResourceReferenceMapper(IPageParametersEncoder pageParametersEncoder)
+	public BasicResourceReferenceMapper(IPageParametersEncoder pageParametersEncoder, IProvider<Boolean> timestamps)
 	{
 		this.pageParametersEncoder = pageParametersEncoder;
-	}
-
-	/**
-	 * Construct.
-	 */
-	public BasicResourceReferenceMapper()
-	{
-		this(new PageParametersEncoder());
+		this.timestamps = timestamps;
 	}
 
 	/**
@@ -73,17 +74,30 @@ class BasicResourceReferenceMapper exten
 		Url url = request.getUrl();
 
 		if (url.getSegments().size() >= 4 &&
-			urlStartsWith(url, getContext().getNamespace(), getContext().getResourceIdentifier()))
+				urlStartsWith(url, getContext().getNamespace(), getContext().getResourceIdentifier()))
 		{
 			String className = url.getSegments().get(2);
 			StringBuilder name = new StringBuilder();
-			for (int i = 3; i < url.getSegments().size(); ++i)
+			int segmentsSize = url.getSegments().size();
+			for (int i = 3; i < segmentsSize; ++i)
 			{
+				String segment = url.getSegments().get(i);
+
+				// if timestamps are enabled the last segment (=resource name)
+				// should be stripped of timestamps
+				if (isTimestampsEnabled() && i + 1 == segmentsSize)
+				{
+					// The last segment eventually contains a timestamp which we have to remove
+					// resource lookup will not care about timestamp but always deliver the
+					// most current version of the resource. After all this whole timestamp
+					// thing is about caching on proxies and browsers but does not affect wicket.
+					segment = stripTimestampFromResourceName(segment);
+				}
 				if (name.length() > 0)
 				{
 					name.append("/");
 				}
-				name.append(url.getSegments().get(i));
+				name.append(segment);
 			}
 
 			ResourceReference.UrlAttributes attributes = getResourceReferenceAttributes(url);
@@ -108,6 +122,50 @@ class BasicResourceReferenceMapper exten
 		return null;
 	}
 
+	private boolean isTimestampsEnabled()
+	{
+		return timestamps.get();
+	}
+
+	/**
+	 * strip timestamp information from resource name
+	 *
+	 * @param resourceName
+	 * @return
+	 */
+
+	private String stripTimestampFromResourceName(final String resourceName)
+	{
+		int pos = resourceName.lastIndexOf('.');
+
+		final String fullname = pos == -1 ? resourceName : resourceName.substring(0, pos);
+		final String extension = pos == -1 ? null : resourceName.substring(pos);
+
+		pos = fullname.lastIndexOf(TIMESTAMP_PREFIX);
+
+		if (pos != -1)
+		{
+			final String timestamp = fullname.substring(pos + TIMESTAMP_PREFIX.length());
+			final String basename = fullname.substring(0, pos);
+
+			try
+			{
+				Long.parseLong(timestamp); // just check the timestamp is numeric
+
+				// create filename without timestamp for resource lookup
+				return extension == null ? basename : basename + extension;
+			}
+			catch (NumberFormatException e)
+			{
+				// some strange case of coincidence where the filename contains the timestamp prefix
+				// but the timestamp itself is non-numeric - we interpret this situation as
+				// "file has no timestamp"
+
+			}
+		}
+		return resourceName;
+	}
+
 	protected Class<?> resolveClass(String name)
 	{
 		return WicketObjects.resolveClass(name);
@@ -128,14 +186,48 @@ class BasicResourceReferenceMapper exten
 			ResourceReferenceRequestHandler referenceRequestHandler = (ResourceReferenceRequestHandler)requestHandler;
 			ResourceReference reference = referenceRequestHandler.getResourceReference();
 			Url url = new Url();
-			url.getSegments().add(getContext().getNamespace());
-			url.getSegments().add(getContext().getResourceIdentifier());
-			url.getSegments().add(getClassName(reference.getScope()));
-			String nameParts[] = reference.getName().split("/");
-			for (String name : nameParts)
+
+			List<String> segments = url.getSegments();
+			segments.add(getContext().getNamespace());
+			segments.add(getContext().getResourceIdentifier());
+			segments.add(getClassName(reference.getScope()));
+
+			StringTokenizer tokens = new StringTokenizer(reference.getName(), "/");
+
+			while (tokens.hasMoreTokens())
 			{
-				url.getSegments().add(name);
+				String token = tokens.nextToken();
+
+				// on the last component of the resource path add the timestamp 
+				if (isTimestampsEnabled() && tokens.hasMoreTokens() == false)
+				{
+					// get last modification of resource
+					Time lastModified = reference.getLastModified();
+
+					// if resource provides a timestamp we include it in resource name
+					if (lastModified != null)
+					{
+						// check if resource name has extension
+						int extensionAt = token.lastIndexOf('.');
+
+						// create timestamped version of filename:
+						//
+						//   filename := [basename][timestamp-prefix][last-modified-milliseconds](.extension)
+						//
+						StringBuilder filename = new StringBuilder();
+						filename.append(extensionAt == -1 ? token : token.substring(0, extensionAt));
+						filename.append(TIMESTAMP_PREFIX);
+						filename.append(lastModified.getMilliseconds());
+
+						if (extensionAt != -1)
+							filename.append(token.substring(extensionAt));
+
+						token = filename.toString();
+					}
+				}
+				segments.add(token);
 			}
+
 			encodeResourceReferenceAttributes(url, reference);
 			PageParameters parameters = referenceRequestHandler.getPageParameters();
 			if (parameters != null)

Modified: wicket/trunk/wicket/src/main/java/org/apache/wicket/request/mapper/ResourceReferenceMapper.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket/src/main/java/org/apache/wicket/request/mapper/ResourceReferenceMapper.java?rev=991339&r1=991338&r2=991339&view=diff
==============================================================================
--- wicket/trunk/wicket/src/main/java/org/apache/wicket/request/mapper/ResourceReferenceMapper.java (original)
+++ wicket/trunk/wicket/src/main/java/org/apache/wicket/request/mapper/ResourceReferenceMapper.java Tue Aug 31 21:35:31 2010
@@ -44,18 +44,12 @@ public class ResourceReferenceMapper ext
 	 * 
 	 * @param pageParametersEncoder
 	 * @param parentPathPartEscapeSequence
+	 * @param timestamps
 	 */
 	public ResourceReferenceMapper(IPageParametersEncoder pageParametersEncoder,
-		IProvider<String> parentPathPartEscapeSequence)
+	                               IProvider<String> parentPathPartEscapeSequence,
+	                               IProvider<Boolean> useTimestamps)
 	{
-		super(new BasicResourceReferenceMapper(pageParametersEncoder), parentPathPartEscapeSequence);
-	}
-
-	/**
-	 * Construct.
-	 */
-	public ResourceReferenceMapper()
-	{
-		this(new PageParametersEncoder(), new NullProvider<String>());
+		super(new BasicResourceReferenceMapper(pageParametersEncoder, useTimestamps), parentPathPartEscapeSequence);
 	}
 }

Modified: wicket/trunk/wicket/src/main/java/org/apache/wicket/request/resource/PackageResourceReference.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket/src/main/java/org/apache/wicket/request/resource/PackageResourceReference.java?rev=991339&r1=991338&r2=991339&view=diff
==============================================================================
--- wicket/trunk/wicket/src/main/java/org/apache/wicket/request/resource/PackageResourceReference.java (original)
+++ wicket/trunk/wicket/src/main/java/org/apache/wicket/request/resource/PackageResourceReference.java Tue Aug 31 21:35:31 2010
@@ -19,11 +19,13 @@ package org.apache.wicket.request.resour
 import java.util.Locale;
 import java.util.concurrent.ConcurrentMap;
 
+import org.apache.wicket.Application;
 import org.apache.wicket.Session;
-import org.apache.wicket.ThreadContext;
 import org.apache.wicket.util.lang.Generics;
 import org.apache.wicket.util.lang.Packages;
+import org.apache.wicket.util.resource.IResourceStream;
 import org.apache.wicket.util.resource.locator.IResourceStreamLocator;
+import org.apache.wicket.util.time.Time;
 
 public class PackageResourceReference extends ResourceReference
 {
@@ -33,7 +35,7 @@ public class PackageResourceReference ex
 
 	/**
 	 * Construct.
-	 * 
+	 *
 	 * @param key
 	 */
 	public PackageResourceReference(final Key key)
@@ -43,7 +45,7 @@ public class PackageResourceReference ex
 
 	/**
 	 * Construct.
-	 * 
+	 *
 	 * @param scope
 	 * @param name
 	 * @param locale
@@ -58,7 +60,7 @@ public class PackageResourceReference ex
 
 	/**
 	 * Construct.
-	 * 
+	 *
 	 * @param scope
 	 * @param name
 	 */
@@ -69,7 +71,7 @@ public class PackageResourceReference ex
 
 	/**
 	 * Construct.
-	 * 
+	 *
 	 * @param name
 	 */
 	public PackageResourceReference(final String name)
@@ -86,78 +88,85 @@ public class PackageResourceReference ex
 		return new PackageResource(getScope(), getName(), getLocale(), getStyle(), getVariation());
 	}
 
-	/**
-	 * 
-	 * @param locator
-	 * @param locale
-	 * @param style
-	 * @param variation
-	 * @return
-	 */
-	private UrlAttributes testResource(final IResourceStreamLocator locator, final Locale locale,
-		final String style, final String variation)
+	private StreamInfo lookupStream(IResourceStreamLocator locator,
+	                                Locale locale, String style, String variation)
 	{
 		String absolutePath = Packages.absolutePath(getScope(), getName());
+		IResourceStream stream = locator.locate(getScope(), absolutePath, style, variation, locale, null, true);
 
-		if (locator.locate(getScope(), absolutePath, style, variation, locale, null, true) != null)
-		{
-			return new UrlAttributes(locale, style, variation);
-		}
-		else
-		{
+		if (stream == null)
 			return null;
-		}
+
+		return new StreamInfo(stream, locale, style, variation);
 	}
 
-	/**
-	 * 
-	 * @param locale
-	 * @param style
-	 * @param variation
-	 * @return
-	 */
-	private UrlAttributes getUrlAttributes(final Locale locale, final String style,
-		final String variation)
+	private StreamInfo lookupStream(Locale locale, String style, String variation)
 	{
-		IResourceStreamLocator locator = ThreadContext.getApplication()
-			.getResourceSettings()
-			.getResourceStreamLocator();
+		IResourceStreamLocator locator = Application.get()
+				.getResourceSettings()
+				.getResourceStreamLocator();
 
-		UrlAttributes res = testResource(locator, locale, style, variation);
-		if (res == null)
-		{
-			res = testResource(locator, locale, style, null);
-		}
-		if (res == null)
+		StreamInfo info;
+
+		info = lookupStream(locator, locale, style, variation);
+		if (info == null)
 		{
-			res = testResource(locator, locale, null, variation);
+			info = lookupStream(locator, locale, style, null);
 		}
-		if (res == null)
+		if (info == null)
 		{
-			res = testResource(locator, null, style, variation);
+			info = lookupStream(locator, locale, null, variation);
 		}
-		if (res == null)
+		if (info == null)
 		{
-			res = testResource(locator, locale, null, null);
+			info = lookupStream(locator, null, style, variation);
 		}
-		if (res == null)
+		if (info == null)
 		{
-			res = testResource(locator, null, style, null);
+			info = lookupStream(locator, locale, null, null);
 		}
-		if (res == null)
+		if (info == null)
 		{
-			res = testResource(locator, null, null, variation);
+			info = lookupStream(locator, null, style, null);
 		}
-		if (res == null)
+		if (info == null)
 		{
-			res = new UrlAttributes(null, null, null);
+			info = lookupStream(locator, null, null, variation);
 		}
-		return res;
+		return info;
+	}
+
+	private UrlAttributes getUrlAttributes(Locale locale, String style, String variation)
+	{
+		StreamInfo info = lookupStream(locale, style, variation);
+
+		if (info != null)
+			return new UrlAttributes(info.locale, info.style, info.variation);
+
+		return new UrlAttributes(null, null, null);
+	}
+
+	private Locale getCurrentLocale()
+	{
+		return getLocale() != null ? getLocale() : Session.get().getLocale();
+	}
+
+	private String getCurrentStyle()
+	{
+		return getStyle() != null ? getStyle() : Session.get().getStyle();
+	}
+
+	@Override
+	public Time getLastModified()
+	{
+		StreamInfo info = lookupStream(getCurrentLocale(), getCurrentStyle(), getVariation());
+
+		if (info == null)
+			return null;
+
+		return info.stream.lastModifiedTime();
 	}
 
-	/**
-	 * @see org.apache.wicket.request.resource.ResourceReference#getUrlAttributes()
-	 */
 	@Override
 	public UrlAttributes getUrlAttributes()
 	{
@@ -165,12 +174,12 @@ public class PackageResourceReference ex
 		String style = getStyle() != null ? getStyle() : Session.get().getStyle();
 		String variation = getVariation();
 
+		UrlAttributes key = new UrlAttributes(locale, style, variation);
+
 		if (urlAttributesCacheMap == null)
 		{
 			urlAttributesCacheMap = Generics.newConcurrentHashMap();
 		}
-
-		UrlAttributes key = new UrlAttributes(locale, style, variation);
 		UrlAttributes value = urlAttributesCacheMap.get(key);
 		if (value == null)
 		{
@@ -180,4 +189,20 @@ public class PackageResourceReference ex
 
 		return value;
 	}
+
+	private static class StreamInfo
+	{
+		public final IResourceStream stream;
+		public final Locale locale;
+		public final String style;
+		public final String variation;
+
+		public StreamInfo(IResourceStream stream, Locale locale, String style, String variation)
+		{
+			this.stream = stream;
+			this.locale = locale;
+			this.style = style;
+			this.variation = variation;
+		}
+	}
 }

Modified: wicket/trunk/wicket/src/main/java/org/apache/wicket/request/resource/ResourceReference.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket/src/main/java/org/apache/wicket/request/resource/ResourceReference.java?rev=991339&r1=991338&r2=991339&view=diff
==============================================================================
--- wicket/trunk/wicket/src/main/java/org/apache/wicket/request/resource/ResourceReference.java (original)
+++ wicket/trunk/wicket/src/main/java/org/apache/wicket/request/resource/ResourceReference.java Tue Aug 31 21:35:31 2010
@@ -23,6 +23,7 @@ import org.apache.wicket.Application;
 import org.apache.wicket.util.lang.Args;
 import org.apache.wicket.util.lang.Objects;
 import org.apache.wicket.util.lang.WicketObjects;
+import org.apache.wicket.util.time.Time;
 
 /**
  * Reference to a resource. Can be used to reference global resources.
@@ -57,7 +58,7 @@ public abstract class ResourceReference 
 
 	/**
 	 * Creates new {@link ResourceReference} instance.
-	 * 
+	 *
 	 * @param scope
 	 *            mandatory parameter
 	 * @param name
@@ -154,7 +155,7 @@ public abstract class ResourceReference 
 	/**
 	 * Can be used to disable registering certain resource references in
 	 * {@link ResourceReferenceRegistry}.
-	 * 
+	 *
 	 * @return <code>true</code> if this reference can be registered, <code>false</code> otherwise.
 	 */
 	public boolean canBeRegistered()
@@ -163,6 +164,17 @@ public abstract class ResourceReference 
 	}
 
 	/**
+	 * return the last modification date of the referred resource
+	 * <p/>
+	 * 
+	 * @return last modification time or <code>null</code> if not supported
+	 */
+	public Time getLastModified()
+	{
+		return null;
+	}
+
+	/**
 	 * @see java.lang.Object#equals(java.lang.Object)
 	 */
 	@Override
@@ -299,18 +311,18 @@ public abstract class ResourceReference 
 
 		/**
 		 * Construct.
-		 * 
+	 * 
 		 * @param reference
-		 */
+	 */
 		public Key(final ResourceReference reference)
-		{
+	{
 			this(reference.getScope().getName(), reference.getName(), reference.getLocale(),
 				reference.getStyle(), reference.getVariation());
 		}
 
 		/**
 		 * Construct.
-		 * 
+		 *
 		 * @param scope
 		 * @param name
 		 * @param locale
@@ -338,8 +350,8 @@ public abstract class ResourceReference 
 		{
 			if (this == obj)
 			{
-				return true;
-			}
+		return true;
+	}
 			if (obj instanceof Key == false)
 			{
 				return false;
@@ -352,7 +364,7 @@ public abstract class ResourceReference 
 				Objects.equal(variation, that.variation);
 		}
 
-		/**
+	/**
 		 * @see java.lang.Object#hashCode()
 		 */
 		@Override
@@ -363,13 +375,13 @@ public abstract class ResourceReference 
 
 		/**
 		 * Gets scope.
-		 * 
+	 *
 		 * @return scope
-		 */
+	 */
 		public final String getScope()
-		{
+	{
 			return scope;
-		}
+	}
 
 		/**
 		 * @return Assuming scope ist a fully qualified class name, than get the associated class
@@ -377,11 +389,11 @@ public abstract class ResourceReference 
 		public final Class<?> getScopeClass()
 		{
 			return WicketObjects.resolveClass(scope);
-		}
+}
 
 		/**
 		 * Gets name.
-		 * 
+		 *
 		 * @return name
 		 */
 		public final String getName()
@@ -391,7 +403,7 @@ public abstract class ResourceReference 
 
 		/**
 		 * Gets locale.
-		 * 
+		 *
 		 * @return locale
 		 */
 		public final Locale getLocale()
@@ -401,7 +413,7 @@ public abstract class ResourceReference 
 
 		/**
 		 * Gets style.
-		 * 
+		 *
 		 * @return style
 		 */
 		public final String getStyle()
@@ -411,7 +423,7 @@ public abstract class ResourceReference 
 
 		/**
 		 * Gets variation.
-		 * 
+		 *
 		 * @return variation
 		 */
 		public final String getVariation()

Modified: wicket/trunk/wicket/src/main/java/org/apache/wicket/settings/IResourceSettings.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket/src/main/java/org/apache/wicket/settings/IResourceSettings.java?rev=991339&r1=991338&r2=991339&view=diff
==============================================================================
--- wicket/trunk/wicket/src/main/java/org/apache/wicket/settings/IResourceSettings.java (original)
+++ wicket/trunk/wicket/src/main/java/org/apache/wicket/settings/IResourceSettings.java Tue Aug 31 21:35:31 2010
@@ -365,4 +365,53 @@ public interface IResourceSettings
 	 *            character sequence which must not be ambiguous within urls
 	 */
 	void setParentFolderPlaceholder(String sequence);
+
+	/**
+	 * Control the usage of timestamps on resources
+	 * <p/>
+	 * Normally the resource names won't change when the resource ifself changes, for example when you add a new
+	 * style to your CSS sheet. This can be very annoying as browsers (and proxies) usally cache resources
+	 * in their cache based on the filename and therefore won't update. Unless you change the file name of the
+	 * resource, force a reload or clear the browser's cache the page will still render with your old CSS.
+	 * <p/>
+	 * Depending on HTTP response headers like 'Last-Modified' and 'Cache' automatic cache
+	 * invalidation can take very, very long or neven happen at all.
+	 * <p/>
+	 * Enabling timestamps on resources will inject the last modification time of the resource into
+	 * the filename (the name will look something like 'style-ts1282915831000.css' where the large number is
+	 * the last modified date in milliseconds and '-ts' is a prefix to avoid conflicts with
+	 * filenames that already contain a number before their extension.
+	 * *
+	 * <p/>
+	 * Since browsers and proxies use the filename of the resource as a cache key the changed filename will
+	 * not hit the cache and the page gets rendered with the changed file.
+	 * <p/>
+	 * @return <code>true</code> if timestamps are enabled
+	 */
+	boolean getUseTimestampOnResources();
+
+	/**
+	 * Control the usage of timestamps on resources
+	 * <p/>
+	 * Normally the resource names won't change when the resource ifself changes, for example when you add a new
+	 * style to your CSS sheet. This can be very annoying as browsers (and proxies) usally cache resources
+	 * in their cache based on the filename and therefore won't update. Unless you change the file name of the
+	 * resource, force a reload or clear the browser's cache the page will still render with your old CSS.
+	 * <p/>
+	 * Depending on HTTP response headers like 'Last-Modified' and 'Cache' automatic cache
+	 * invalidation can take very, very long or neven happen at all.
+	 * <p/>
+	 * Enabling timestamps on resources will inject the last modification time of the resource into
+	 * the filename (the name will look something like 'style-ts1282915831000.css' where the large number is
+	 * the last modified date in milliseconds and '-ts' is a prefix to avoid conflicts with
+	 * filenames that already contain a number before their extension.
+	 * *
+	 * <p/>
+	 * Since browsers and proxies use the filename of the resource as a cache key the changed filename will
+	 * not hit the cache and the page gets rendered with the changed file.
+	 * <p/>
+	 *
+	 * @param enable <code>true</code> for using timestamps on resource names
+	 */
+	void setUseTimestampOnResources(boolean enable);
 }

Modified: wicket/trunk/wicket/src/main/java/org/apache/wicket/settings/Settings.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket/src/main/java/org/apache/wicket/settings/Settings.java?rev=991339&r1=991338&r2=991339&view=diff
==============================================================================
--- wicket/trunk/wicket/src/main/java/org/apache/wicket/settings/Settings.java (original)
+++ wicket/trunk/wicket/src/main/java/org/apache/wicket/settings/Settings.java Tue Aug 31 21:35:31 2010
@@ -316,6 +316,9 @@ public final class Settings
 	/** escape string for '..' within resource keys */
 	private String parentFolderPlaceholder = null;
 
+	// use timestamps on resource file names
+	private boolean useTimestampOnResourcesName = true;
+
 	/** Default cache duration */
 	private int defaultCacheDuration = 3600;
 
@@ -1452,4 +1455,20 @@ public final class Settings
 	{
 		markupFactory = factory;
 	}
+
+	/**
+	 * @see IResourceSettings#getUseTimestampOnResources()
+	 */
+	public boolean getUseTimestampOnResources()
+	{
+		return useTimestampOnResourcesName;
+	}
+
+	/**
+	 * @see org.apache.wicket.settings.IResourceSettings#setUseTimestampOnResources(boolean)
+	 */
+	public void setUseTimestampOnResources(boolean useTimestampOnResourcesName)
+	{
+		this.useTimestampOnResourcesName = useTimestampOnResourcesName;
+	}
 }

Modified: wicket/trunk/wicket/src/test/java/org/apache/wicket/request/mapper/BasicResourceReferenceMapperTest.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket/src/test/java/org/apache/wicket/request/mapper/BasicResourceReferenceMapperTest.java?rev=991339&r1=991338&r2=991339&view=diff
==============================================================================
--- wicket/trunk/wicket/src/test/java/org/apache/wicket/request/mapper/BasicResourceReferenceMapperTest.java (original)
+++ wicket/trunk/wicket/src/test/java/org/apache/wicket/request/mapper/BasicResourceReferenceMapperTest.java Tue Aug 31 21:35:31 2010
@@ -22,12 +22,16 @@ import org.apache.wicket.request.IReques
 import org.apache.wicket.request.Url;
 import org.apache.wicket.request.handler.resource.ResourceReferenceRequestHandler;
 import org.apache.wicket.request.mapper.parameter.PageParameters;
+import org.apache.wicket.request.mapper.parameter.PageParametersEncoder;
+import org.apache.wicket.util.ValueProvider;
 
 /**
  * @author Matej Knopp
  */
 public class BasicResourceReferenceMapperTest extends AbstractResourceReferenceMapperTest
 {
+	private static final ValueProvider<Boolean> TIMESTAMPS = new ValueProvider<Boolean>(false);
+
 	/**
 	 * Construct.
 	 */
@@ -35,7 +39,7 @@ public class BasicResourceReferenceMappe
 	{
 	}
 
-	private final BasicResourceReferenceMapper encoder = new BasicResourceReferenceMapper()
+	private final BasicResourceReferenceMapper encoder = new BasicResourceReferenceMapper(new PageParametersEncoder(), TIMESTAMPS)
 	{
 		@Override
 		protected IMapperContext getContext()