You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@wicket.apache.org by mg...@apache.org on 2015/06/24 14:58:31 UTC

[25/50] [abbrv] wicket git commit: [WICKET-5909] Session style is not taken into account when loading mounted resources.

[WICKET-5909] Session style is not taken into account when loading mounted resources.


Project: http://git-wip-us.apache.org/repos/asf/wicket/repo
Commit: http://git-wip-us.apache.org/repos/asf/wicket/commit/00c1e3b5
Tree: http://git-wip-us.apache.org/repos/asf/wicket/tree/00c1e3b5
Diff: http://git-wip-us.apache.org/repos/asf/wicket/diff/00c1e3b5

Branch: refs/heads/master
Commit: 00c1e3b5fe83814f0dbda56cc4587a763a5eb6c7
Parents: 1e5a5e2
Author: Andrea Del Bene <“adelbene@apache.org”>
Authored: Mon Jun 15 13:01:17 2015 +0200
Committer: Martin Tzvetanov Grigorov <mg...@apache.org>
Committed: Wed Jun 24 14:56:33 2015 +0300

----------------------------------------------------------------------
 .../mapper/AbstractResourceReferenceMapper.java | 156 ---------------
 .../mapper/BasicResourceReferenceMapper.java    |   6 +-
 .../core/request/mapper/ResourceMapper.java     |   2 +
 .../apache/wicket/markup/html/media/Source.java |   2 +-
 .../request/resource/PackageResource.java       |  12 +-
 .../resource/PackageResourceReference.java      |  68 ++++++-
 .../apache/wicket/resource/ResourceUtil.java    | 194 ++++++++++++++++++-
 .../org/apache/wicket/util/image/ImageUtil.java |   2 +-
 .../AbstractResourceReferenceMapperOwnTest.java |   5 +-
 .../resource/CssPackageResourceTest.java        |   3 +
 .../resource/JavaScriptPackageResourceTest.java |   5 +-
 .../wicket/resource/ResourceUtilTest.java       | 137 +++++++++++++
 .../org/apache/wicket/util/lang/Objects.java    |  16 ++
 .../org/apache/wicket/util/string/Strings.java  |  15 ++
 14 files changed, 443 insertions(+), 180 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/wicket/blob/00c1e3b5/wicket-core/src/main/java/org/apache/wicket/core/request/mapper/AbstractResourceReferenceMapper.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/core/request/mapper/AbstractResourceReferenceMapper.java b/wicket-core/src/main/java/org/apache/wicket/core/request/mapper/AbstractResourceReferenceMapper.java
index f95ca9e..7dea46e 100644
--- a/wicket-core/src/main/java/org/apache/wicket/core/request/mapper/AbstractResourceReferenceMapper.java
+++ b/wicket-core/src/main/java/org/apache/wicket/core/request/mapper/AbstractResourceReferenceMapper.java
@@ -16,12 +16,8 @@
  */
 package org.apache.wicket.core.request.mapper;
 
-import java.util.Locale;
-
 import org.apache.wicket.request.Url;
 import org.apache.wicket.request.resource.ResourceReference;
-import org.apache.wicket.util.lang.Args;
-import org.apache.wicket.util.string.Strings;
 
 /**
  * Base class for encoding and decoding {@link ResourceReference}s
@@ -31,158 +27,6 @@ import org.apache.wicket.util.string.Strings;
 public abstract class AbstractResourceReferenceMapper extends AbstractComponentMapper
 {
 	/**
-	 * Escapes any occurrences of <em>-</em> character in the style and variation
-	 * attributes with <em>~</em>. Any occurrence of <em>~</em> is encoded as <em>~~</em>.
-	 *
-	 * @param attribute
-	 *      the attribute to escape
-	 * @return the attribute with escaped separator character
-	 */
-	public static CharSequence escapeAttributesSeparator(String attribute)
-	{
-		CharSequence tmp = Strings.replaceAll(attribute, "~", "~~");
-		return Strings.replaceAll(tmp, "-", "~");
-	}
-
-	/**
-	 * Reverts the escaping applied by {@linkplain #escapeAttributesSeparator(String)} - unescapes
-	 * occurrences of <em>~</em> character in the style and variation attributes with <em>-</em>.
-	 *
-	 * @param attribute
-	 *      the attribute to unescape
-	 * @return the attribute with escaped separator character
-	 */
-	public static String unescapeAttributesSeparator(String attribute)
-	{
-		String tmp = attribute.replaceAll("(\\w)~(\\w)", "$1-$2");
-		return Strings.replaceAll(tmp, "~~", "~").toString();
-	}
-
-	protected final String encodeResourceReferenceAttributes(ResourceReference.UrlAttributes attributes)
-	{
-		if (attributes == null ||
-			(attributes.getLocale() == null && attributes.getStyle() == null && attributes.getVariation() == null))
-		{
-			return null;
-		}
-		else
-		{
-			StringBuilder res = new StringBuilder(32);
-			if (attributes.getLocale() != null)
-			{
-				res.append(attributes.getLocale());
-			}
-			boolean styleEmpty = Strings.isEmpty(attributes.getStyle());
-			if (!styleEmpty)
-			{
-				res.append('-');
-				res.append(escapeAttributesSeparator(attributes.getStyle()));
-			}
-			if (!Strings.isEmpty(attributes.getVariation()))
-			{
-				if (styleEmpty)
-				{
-					res.append("--");
-				}
-				else
-				{
-					res.append('-');
-				}
-				res.append(escapeAttributesSeparator(attributes.getVariation()));
-			}
-			return res.toString();
-		}
-	}
-
-	private static String nonEmpty(String s)
-	{
-		if (Strings.isEmpty(s))
-		{
-			return null;
-		}
-		else
-		{
-			return s;
-		}
-	}
-
-	protected final ResourceReference.UrlAttributes decodeResourceReferenceAttributes(String attributes)
-	{
-		Locale locale = null;
-		String style = null;
-		String variation = null;
-
-		if (Strings.isEmpty(attributes) == false)
-		{
-			String split[] = Strings.split(attributes, '-');
-			locale = parseLocale(split[0]);
-			if (split.length == 2)
-			{
-				style = nonEmpty(unescapeAttributesSeparator(split[1]));
-			}
-			else if (split.length == 3)
-			{
-				style = nonEmpty(unescapeAttributesSeparator(split[1]));
-				variation = nonEmpty(unescapeAttributesSeparator(split[2]));
-			}
-		}
-		return new ResourceReference.UrlAttributes(locale, style, variation);
-	}
-
-	private static Locale parseLocale(String locale)
-	{
-		if (Strings.isEmpty(locale))
-		{
-			return null;
-		}
-		else
-		{
-			String parts[] = locale.toLowerCase().split("_", 3);
-			if (parts.length == 1)
-			{
-				return new Locale(parts[0]);
-			}
-			else if (parts.length == 2)
-			{
-				return new Locale(parts[0], parts[1]);
-			}
-			else if (parts.length == 3)
-			{
-				return new Locale(parts[0], parts[1], parts[2]);
-			}
-			else
-			{
-				return null;
-			}
-		}
-	}
-
-	protected void encodeResourceReferenceAttributes(Url url, ResourceReference reference)
-	{
-		String encoded = encodeResourceReferenceAttributes(reference.getUrlAttributes());
-		if (!Strings.isEmpty(encoded))
-		{
-			url.getQueryParameters().add(new Url.QueryParameter(encoded, ""));
-		}
-	}
-
-	protected ResourceReference.UrlAttributes getResourceReferenceAttributes(Url url)
-	{
-		Args.notNull(url, "url");
-
-		if (url.getQueryParameters().size() > 0)
-		{
-			Url.QueryParameter param = url.getQueryParameters().get(0);
-			if (Strings.isEmpty(param.getValue()))
-			{
-				return decodeResourceReferenceAttributes(param.getName());
-			}
-		}
-		return new ResourceReference.UrlAttributes(null, null, null);
-	}
-
-
-	/**
 	 * {@inheritDoc}
 	 *
 	 * Remove the first parameter because it brings meta information like locale

http://git-wip-us.apache.org/repos/asf/wicket/blob/00c1e3b5/wicket-core/src/main/java/org/apache/wicket/core/request/mapper/BasicResourceReferenceMapper.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/core/request/mapper/BasicResourceReferenceMapper.java b/wicket-core/src/main/java/org/apache/wicket/core/request/mapper/BasicResourceReferenceMapper.java
index e7d14b7..e954ede 100755
--- a/wicket-core/src/main/java/org/apache/wicket/core/request/mapper/BasicResourceReferenceMapper.java
+++ b/wicket-core/src/main/java/org/apache/wicket/core/request/mapper/BasicResourceReferenceMapper.java
@@ -33,6 +33,7 @@ import org.apache.wicket.request.resource.ResourceReferenceRegistry;
 import org.apache.wicket.request.resource.caching.IResourceCachingStrategy;
 import org.apache.wicket.request.resource.caching.IStaticCacheableResource;
 import org.apache.wicket.request.resource.caching.ResourceUrl;
+import org.apache.wicket.resource.ResourceUtil;
 import org.apache.wicket.resource.bundles.ResourceBundleReference;
 import org.apache.wicket.util.IProvider;
 import org.apache.wicket.util.lang.Args;
@@ -124,7 +125,7 @@ public class BasicResourceReferenceMapper extends AbstractResourceReferenceMappe
 				name.append(segment);
 			}
 
-			ResourceReference.UrlAttributes attributes = getResourceReferenceAttributes(url);
+			ResourceReference.UrlAttributes attributes = ResourceUtil.decodeResourceReferenceAttributes(url);
 
 			Class<?> scope = resolveClass(className);
 
@@ -212,7 +213,8 @@ public class BasicResourceReferenceMapper extends AbstractResourceReferenceMappe
 				// need to remove indexed parameters otherwise the URL won't be able to decode
 				parameters.clearIndexed();
 			}
-			encodeResourceReferenceAttributes(url, reference);
+
+			ResourceUtil.encodeResourceReferenceAttributes(url, reference);
 
 			StringTokenizer tokens = new StringTokenizer(reference.getName(), "/");
 

http://git-wip-us.apache.org/repos/asf/wicket/blob/00c1e3b5/wicket-core/src/main/java/org/apache/wicket/core/request/mapper/ResourceMapper.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/core/request/mapper/ResourceMapper.java b/wicket-core/src/main/java/org/apache/wicket/core/request/mapper/ResourceMapper.java
index cc6f6d3..c438319 100644
--- a/wicket-core/src/main/java/org/apache/wicket/core/request/mapper/ResourceMapper.java
+++ b/wicket-core/src/main/java/org/apache/wicket/core/request/mapper/ResourceMapper.java
@@ -37,6 +37,7 @@ import org.apache.wicket.request.resource.ResourceReference;
 import org.apache.wicket.request.resource.caching.IResourceCachingStrategy;
 import org.apache.wicket.request.resource.caching.IStaticCacheableResource;
 import org.apache.wicket.request.resource.caching.ResourceUrl;
+import org.apache.wicket.resource.ResourceUtil;
 import org.apache.wicket.util.lang.Args;
 import org.apache.wicket.util.string.Strings;
 
@@ -202,6 +203,7 @@ public class ResourceMapper extends AbstractMapper implements IRequestMapper
 		// add caching information
 		addCachingDecoration(url, parameters);
 
+		ResourceUtil.encodeResourceReferenceAttributes(url, resourceReference);
 		// create url
 		return encodePageParameters(url, parameters, parametersEncoder);
 	}

http://git-wip-us.apache.org/repos/asf/wicket/blob/00c1e3b5/wicket-core/src/main/java/org/apache/wicket/markup/html/media/Source.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/markup/html/media/Source.java b/wicket-core/src/main/java/org/apache/wicket/markup/html/media/Source.java
index 4abdca9..1621365 100755
--- a/wicket-core/src/main/java/org/apache/wicket/markup/html/media/Source.java
+++ b/wicket-core/src/main/java/org/apache/wicket/markup/html/media/Source.java
@@ -196,7 +196,7 @@ public class Source extends WebMarkupContainer
 			else if (resourceReference != null)
 			{
 				PackageResource resource = resourceReference.getResource();
-				IResourceStream resourceStream = resource.getResourceStream();
+				IResourceStream resourceStream = resource.getCacheableResourceStream();
 				String contentType = resourceStream.getContentType();
 				tag.put("type", contentType);
 			}

http://git-wip-us.apache.org/repos/asf/wicket/blob/00c1e3b5/wicket-core/src/main/java/org/apache/wicket/request/resource/PackageResource.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/request/resource/PackageResource.java b/wicket-core/src/main/java/org/apache/wicket/request/resource/PackageResource.java
index 2253446..b5b2777 100644
--- a/wicket-core/src/main/java/org/apache/wicket/request/resource/PackageResource.java
+++ b/wicket-core/src/main/java/org/apache/wicket/request/resource/PackageResource.java
@@ -299,7 +299,7 @@ public class PackageResource extends AbstractResource implements IStaticCacheabl
 	{
 		final ResourceResponse resourceResponse = new ResourceResponse();
 
-		final IResourceStream resourceStream = getResourceStream();
+		final IResourceStream resourceStream = getCacheableResourceStream();
 
 		// bail out if resource stream could not be found
 		if (resourceStream == null)
@@ -431,13 +431,12 @@ public class PackageResource extends AbstractResource implements IStaticCacheabl
 
 
 	/**
-	 * be aware that method takes the current wicket session's locale and style into account when
-	 * locating the stream.
+	 * Locate resource stream for current resource. Be aware that method takes the current wicket session's
+	 * locale and style into account when locating the stream.
 	 *
-	 * @return resource stream
+	 * @return resource stream or <code>null</code> if not found
 	 *
 	 * @see org.apache.wicket.request.resource.caching.IStaticCacheableResource#getCacheableResourceStream()
-	 * @see #getResourceStream()
 	 */
 	@Override
 	public IResourceStream getCacheableResourceStream()
@@ -449,10 +448,11 @@ public class PackageResource extends AbstractResource implements IStaticCacheabl
 	 * locate resource stream for current resource
 	 * 
 	 * @return resource stream or <code>null</code> if not found
+	 * @deprecated use {@link #getCacheableResourceStream} instead.
 	 */
 	public IResourceStream getResourceStream()
 	{
-		return internalGetResourceStream(style, locale);
+		return getCacheableResourceStream();
 	}
 
 	/**

http://git-wip-us.apache.org/repos/asf/wicket/blob/00c1e3b5/wicket-core/src/main/java/org/apache/wicket/request/resource/PackageResourceReference.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/request/resource/PackageResourceReference.java b/wicket-core/src/main/java/org/apache/wicket/request/resource/PackageResourceReference.java
index 4bd20f0..746dad8 100644
--- a/wicket-core/src/main/java/org/apache/wicket/request/resource/PackageResourceReference.java
+++ b/wicket-core/src/main/java/org/apache/wicket/request/resource/PackageResourceReference.java
@@ -22,6 +22,9 @@ import java.util.concurrent.ConcurrentMap;
 import org.apache.wicket.Application;
 import org.apache.wicket.Session;
 import org.apache.wicket.core.util.resource.locator.IResourceStreamLocator;
+import org.apache.wicket.request.Url;
+import org.apache.wicket.request.cycle.RequestCycle;
+import org.apache.wicket.resource.ResourceUtil;
 import org.apache.wicket.util.lang.Generics;
 import org.apache.wicket.util.lang.Packages;
 import org.apache.wicket.util.resource.IResourceStream;
@@ -120,20 +123,24 @@ public class PackageResourceReference extends ResourceReference
 
 		final PackageResource resource;
 
+		final Url url = RequestCycle.get().getRequest().getUrl();
+		//resource attributes (locale, style, variation) might be encoded in the URL
+		final UrlAttributes urlAttributes = ResourceUtil.decodeResourceReferenceAttributes(url);
+
 		if (CSS_EXTENSION.equals(extension))
 		{
-			resource = new CssPackageResource(getScope(), getName(), getLocale(), getStyle(),
-				getVariation()).readBuffered(readBuffered);
+			resource = new CssPackageResource(getScope(), getName(), getCurrentLocale(urlAttributes),
+				getCurrentStyle(urlAttributes), getCurrentVariation(urlAttributes)).readBuffered(readBuffered);
 		}
 		else if (JAVASCRIPT_EXTENSION.equals(extension))
 		{
-			resource = new JavaScriptPackageResource(getScope(), getName(), getLocale(),
-				getStyle(), getVariation()).readBuffered(readBuffered);
+			resource = new JavaScriptPackageResource(getScope(), getName(), getCurrentLocale(urlAttributes),
+				getCurrentStyle(urlAttributes), getCurrentVariation(urlAttributes)).readBuffered(readBuffered);
 		}
 		else
 		{
-			resource = new PackageResource(getScope(), getName(), getLocale(), getStyle(),
-				getVariation()).readBuffered(readBuffered);
+			resource = new PackageResource(getScope(), getName(), getCurrentLocale(urlAttributes),
+				getCurrentStyle(urlAttributes), getCurrentVariation(urlAttributes)).readBuffered(readBuffered);
 		}
 
 		removeCompressFlagIfUnnecessary(resource);
@@ -179,14 +186,59 @@ public class PackageResourceReference extends ResourceReference
 			stream.getVariation());
 	}
 
+	private Locale getCurrentLocale(UrlAttributes attributes)
+	{
+		Locale currentLocale = getCurrentLocale();
+
+		return currentLocale != null ? currentLocale : attributes.getLocale();
+	}
+
 	private Locale getCurrentLocale()
 	{
-		return getLocale() != null ? getLocale() : Session.get().getLocale();
+		final Locale locale = getLocale();
+
+		if (locale != null)
+		{
+			return locale;
+		}
+
+		if (Session.exists())
+		{
+			return Session.get().getLocale();
+		}
+
+		return locale;
+	}
+
+	private String getCurrentStyle(UrlAttributes attributes)
+	{
+		String currentStyle = getCurrentStyle();
+
+		return currentStyle != null ? currentStyle : attributes.getStyle();
 	}
 
 	private String getCurrentStyle()
 	{
-		return getStyle() != null ? getStyle() : Session.get().getStyle();
+		final String style = getStyle();
+
+		if (style != null)
+		{
+			return style;
+		}
+
+		if (Session.exists())
+		{
+			return Session.get().getStyle();
+		}
+
+		return style;
+	}
+
+	private String getCurrentVariation(UrlAttributes attributes)
+	{
+		final String variation = getVariation();
+
+		return variation != null ? variation : attributes.getVariation();
 	}
 
 	/**

http://git-wip-us.apache.org/repos/asf/wicket/blob/00c1e3b5/wicket-core/src/main/java/org/apache/wicket/resource/ResourceUtil.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/resource/ResourceUtil.java b/wicket-core/src/main/java/org/apache/wicket/resource/ResourceUtil.java
index 3f03207..0f41ccc 100644
--- a/wicket-core/src/main/java/org/apache/wicket/resource/ResourceUtil.java
+++ b/wicket-core/src/main/java/org/apache/wicket/resource/ResourceUtil.java
@@ -19,11 +19,16 @@ package org.apache.wicket.resource;
 import java.io.IOException;
 import java.io.InputStream;
 import java.nio.charset.Charset;
+import java.util.Locale;
 
 import org.apache.wicket.WicketRuntimeException;
+import org.apache.wicket.request.Url;
+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.apache.wicket.util.string.Strings;
 
 /**
  * Utilities for resources.
@@ -32,10 +37,176 @@ import org.apache.wicket.util.resource.ResourceStreamNotFoundException;
  */
 public class ResourceUtil
 {
+	/**
+	 * Reads resource reference attributes (style, locale, variation) encoded in the given string.
+	 *
+	 * @param encodedAttributes
+	 * 			the string containing the resource attributes
+	 * @return the encoded attributes
+	 *
+	 * @see ResourceReference.UrlAttributes
+	 */
+	public static ResourceReference.UrlAttributes decodeResourceReferenceAttributes(String encodedAttributes)
+	{
+		Locale locale = null;
+		String style = null;
+		String variation = null;
 
-	private ResourceUtil()
+		if (Strings.isEmpty(encodedAttributes) == false)
+		{
+			String split[] = Strings.split(encodedAttributes, '-');
+			locale = parseLocale(split[0]);
+			if (split.length == 2)
+			{
+				style = Strings.defaultIfEmpty(unescapeAttributesSeparator(split[1]), null);
+			}
+			else if (split.length == 3)
+			{
+				style = Strings.defaultIfEmpty(unescapeAttributesSeparator(split[1]), null);
+				variation = Strings.defaultIfEmpty(unescapeAttributesSeparator(split[2]), null);
+			}
+		}
+		return new ResourceReference.UrlAttributes(locale, style, variation);
+	}
+
+	/**
+	 * Reads resource reference attributes (style, locale, variation) encoded in the given URL.
+	 *
+	 * @param url
+	 * 			the url containing the resource attributes
+	 * @return the encoded attributes
+	 *
+	 * @see ResourceReference.UrlAttributes
+	 */
+	public static ResourceReference.UrlAttributes decodeResourceReferenceAttributes(Url url)
 	{
-		// no-op
+		Args.notNull(url, "url");
+
+		if (url.getQueryParameters().size() > 0)
+		{
+			Url.QueryParameter param = url.getQueryParameters().get(0);
+			if (Strings.isEmpty(param.getValue()))
+			{
+				return decodeResourceReferenceAttributes(param.getName());
+			}
+		}
+		return new ResourceReference.UrlAttributes(null, null, null);
+	}
+
+	/**
+	 * Encodes the given resource reference attributes returning the corresponding textual representation.
+	 *
+	 * @param attributes
+	 * 		the resource reference attributes to encode
+	 * @return the textual representation for the given attributes
+	 *
+	 * @see ResourceReference.UrlAttributes
+	 */
+	public static String encodeResourceReferenceAttributes(ResourceReference.UrlAttributes attributes)
+	{
+		if (attributes == null ||
+			(attributes.getLocale() == null && attributes.getStyle() == null && attributes.getVariation() == null))
+		{
+			return null;
+		}
+		else
+		{
+			StringBuilder res = new StringBuilder(32);
+			if (attributes.getLocale() != null)
+			{
+				res.append(attributes.getLocale());
+			}
+			boolean styleEmpty = Strings.isEmpty(attributes.getStyle());
+			if (!styleEmpty)
+			{
+				res.append('-');
+				res.append(escapeAttributesSeparator(attributes.getStyle()));
+			}
+			if (!Strings.isEmpty(attributes.getVariation()))
+			{
+				if (styleEmpty)
+				{
+					res.append("--");
+				}
+				else
+				{
+					res.append('-');
+				}
+				res.append(escapeAttributesSeparator(attributes.getVariation()));
+			}
+			return res.toString();
+		}
+	}
+
+	/**
+	 * Encodes the attributes of the given resource reference in the specified url.
+	 *
+	 * @param url
+	 * 			the resource reference attributes to encode
+	 * @param reference
+	 *
+	 * @see ResourceReference.UrlAttributes
+	 * @see Url
+	 */
+	public static void encodeResourceReferenceAttributes(Url url, ResourceReference reference)
+	{
+		Args.notNull(url, "url");
+		Args.notNull(reference, "reference");
+
+		String encoded = encodeResourceReferenceAttributes(reference.getUrlAttributes());
+		if (!Strings.isEmpty(encoded))
+		{
+			url.getQueryParameters().add(new Url.QueryParameter(encoded, ""));
+		}
+	}
+
+	/**
+	 * Escapes any occurrences of <em>-</em> character in the style and variation
+	 * attributes with <em>~</em>. Any occurrence of <em>~</em> is encoded as <em>~~</em>.
+	 *
+	 * @param attribute
+	 *      the attribute to escape
+	 * @return the attribute with escaped separator character
+	 */
+	public static CharSequence escapeAttributesSeparator(String attribute)
+	{
+		CharSequence tmp = Strings.replaceAll(attribute, "~", "~~");
+		return Strings.replaceAll(tmp, "-", "~");
+	}
+
+	/**
+	 * Parses the string representation of a {@link java.util.Locale} (for example 'en_GB').
+	 *
+	 * @param locale
+	 * 		the string representation of a {@link java.util.Locale}
+	 * @return the corresponding {@link java.util.Locale} instance
+	 */
+	public static Locale parseLocale(String locale)
+	{
+		if (Strings.isEmpty(locale))
+		{
+			return null;
+		}
+		else
+		{
+			String parts[] = locale.toLowerCase().split("_", 3);
+			if (parts.length == 1)
+			{
+				return new Locale(parts[0]);
+			}
+			else if (parts.length == 2)
+			{
+				return new Locale(parts[0], parts[1]);
+			}
+			else if (parts.length == 3)
+			{
+				return new Locale(parts[0], parts[1], parts[2]);
+			}
+			else
+			{
+				return null;
+			}
+		}
 	}
 
 	/**
@@ -91,4 +262,23 @@ public class ResourceUtil
 			throw new WicketRuntimeException("failed to locate stream from " + resourceStream, e);
 		}
 	}
+
+	/**
+	 * Reverts the escaping applied by {@linkplain #escapeAttributesSeparator(String)} - unescapes
+	 * occurrences of <em>~</em> character in the style and variation attributes with <em>-</em>.
+	 *
+	 * @param attribute
+	 *      the attribute to unescape
+	 * @return the attribute with escaped separator character
+	 */
+	public static String unescapeAttributesSeparator(String attribute)
+	{
+		String tmp = attribute.replaceAll("(\\w)~(\\w)", "$1-$2");
+		return Strings.replaceAll(tmp, "~~", "~").toString();
+	}
+
+	private ResourceUtil()
+	{
+		// no-op
+	}
 }

http://git-wip-us.apache.org/repos/asf/wicket/blob/00c1e3b5/wicket-core/src/main/java/org/apache/wicket/util/image/ImageUtil.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/util/image/ImageUtil.java b/wicket-core/src/main/java/org/apache/wicket/util/image/ImageUtil.java
index fca5877..6309308 100644
--- a/wicket-core/src/main/java/org/apache/wicket/util/image/ImageUtil.java
+++ b/wicket-core/src/main/java/org/apache/wicket/util/image/ImageUtil.java
@@ -51,7 +51,7 @@ public class ImageUtil
 	public static CharSequence createBase64EncodedImage(PackageResourceReference imageReference,
 		boolean removeWhitespaces) throws ResourceStreamNotFoundException, IOException
 	{
-		IResourceStream resourceStream = imageReference.getResource().getResourceStream();
+		IResourceStream resourceStream = imageReference.getResource().getCacheableResourceStream();
 		InputStream inputStream = resourceStream.getInputStream();
 		try
 		{

http://git-wip-us.apache.org/repos/asf/wicket/blob/00c1e3b5/wicket-core/src/test/java/org/apache/wicket/core/request/mapper/AbstractResourceReferenceMapperOwnTest.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/test/java/org/apache/wicket/core/request/mapper/AbstractResourceReferenceMapperOwnTest.java b/wicket-core/src/test/java/org/apache/wicket/core/request/mapper/AbstractResourceReferenceMapperOwnTest.java
index 478fe19..1345687 100644
--- a/wicket-core/src/test/java/org/apache/wicket/core/request/mapper/AbstractResourceReferenceMapperOwnTest.java
+++ b/wicket-core/src/test/java/org/apache/wicket/core/request/mapper/AbstractResourceReferenceMapperOwnTest.java
@@ -19,6 +19,7 @@ package org.apache.wicket.core.request.mapper;
 import org.apache.wicket.request.IRequestHandler;
 import org.apache.wicket.request.Request;
 import org.apache.wicket.request.Url;
+import org.apache.wicket.resource.ResourceUtil;
 import org.junit.Assert;
 import org.junit.Test;
 
@@ -31,7 +32,7 @@ public class AbstractResourceReferenceMapperOwnTest extends Assert
 	public void testEscapeAttributesSeparator() throws Exception
 	{
 		AbstractResourceReferenceMapper mapper = new Mapper();
-		CharSequence escaped = mapper.escapeAttributesSeparator("my-style~is~~cool");
+		CharSequence escaped = ResourceUtil.escapeAttributesSeparator("my-style~is~~cool");
 		assertEquals("my~style~~is~~~~cool", escaped.toString());
 	}
 
@@ -39,7 +40,7 @@ public class AbstractResourceReferenceMapperOwnTest extends Assert
 	public void testUnescapeAttributesSeparator() throws Exception
 	{
 		AbstractResourceReferenceMapper mapper = new Mapper();
-		CharSequence escaped = mapper.unescapeAttributesSeparator("my~style~~is~~~~cool");
+		CharSequence escaped = ResourceUtil.unescapeAttributesSeparator("my~style~~is~~~~cool");
 		assertEquals("my-style~is~~cool", escaped.toString());
 	}
 

http://git-wip-us.apache.org/repos/asf/wicket/blob/00c1e3b5/wicket-core/src/test/java/org/apache/wicket/request/resource/CssPackageResourceTest.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/test/java/org/apache/wicket/request/resource/CssPackageResourceTest.java b/wicket-core/src/test/java/org/apache/wicket/request/resource/CssPackageResourceTest.java
index 06a6f44..59cd3ac 100644
--- a/wicket-core/src/test/java/org/apache/wicket/request/resource/CssPackageResourceTest.java
+++ b/wicket-core/src/test/java/org/apache/wicket/request/resource/CssPackageResourceTest.java
@@ -16,6 +16,8 @@
  */
 package org.apache.wicket.request.resource;
 
+import java.util.Locale;
+
 import org.apache.wicket.WicketTestCase;
 import org.apache.wicket.css.ICssCompressor;
 import org.apache.wicket.markup.html.PackageResourceTest;
@@ -109,6 +111,7 @@ public class CssPackageResourceTest extends WicketTestCase
 		CssPackageResource resource = new CssPackageResource(PackageResourceTest.class,
 			"packaged1.txt", null, null, null);
 
+		tester.getSession().setLocale(Locale.ROOT);
 		tester.getApplication().getResourceSettings().setCssCompressor(null);
 		tester.startResource(resource);
 		assertEquals("TEST", tester.getLastResponseAsString());

http://git-wip-us.apache.org/repos/asf/wicket/blob/00c1e3b5/wicket-core/src/test/java/org/apache/wicket/request/resource/JavaScriptPackageResourceTest.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/test/java/org/apache/wicket/request/resource/JavaScriptPackageResourceTest.java b/wicket-core/src/test/java/org/apache/wicket/request/resource/JavaScriptPackageResourceTest.java
index 39fd9c6..45cb49f 100644
--- a/wicket-core/src/test/java/org/apache/wicket/request/resource/JavaScriptPackageResourceTest.java
+++ b/wicket-core/src/test/java/org/apache/wicket/request/resource/JavaScriptPackageResourceTest.java
@@ -18,6 +18,7 @@ package org.apache.wicket.request.resource;
 
 import java.io.IOException;
 import java.io.InputStream;
+import java.util.Locale;
 
 import org.apache.wicket.WicketTestCase;
 import org.apache.wicket.javascript.IJavaScriptCompressor;
@@ -122,7 +123,7 @@ public class JavaScriptPackageResourceTest extends WicketTestCase
 		tester.startResource(resource);
 		assertEquals(RESOURCE_COMPRESSED, tester.getLastResponseAsString());
 		InputStream cacheableStream = resource.getCacheableResourceStream().getInputStream();
-		InputStream stream = resource.getResourceStream().getInputStream();
+		InputStream stream = resource.getCacheableResourceStream().getInputStream();
 		assertEquals(IOUtils.toString(cacheableStream), IOUtils.toString(stream));
 	}
 
@@ -149,7 +150,7 @@ public class JavaScriptPackageResourceTest extends WicketTestCase
 	{
 		JavaScriptPackageResource resource = new JavaScriptPackageResource(
 			PackageResourceTest.class, "packaged1.txt", null, null, null);
-
+		tester.getSession().setLocale(Locale.ROOT);
 		tester.getApplication().getResourceSettings().setJavaScriptCompressor(null);
 		tester.startResource(resource);
 		assertEquals("TEST", tester.getLastResponseAsString());

http://git-wip-us.apache.org/repos/asf/wicket/blob/00c1e3b5/wicket-core/src/test/java/org/apache/wicket/resource/ResourceUtilTest.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/test/java/org/apache/wicket/resource/ResourceUtilTest.java b/wicket-core/src/test/java/org/apache/wicket/resource/ResourceUtilTest.java
new file mode 100644
index 0000000..3cfa584
--- /dev/null
+++ b/wicket-core/src/test/java/org/apache/wicket/resource/ResourceUtilTest.java
@@ -0,0 +1,137 @@
+/*
+ * 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.resource;
+
+import java.util.Locale;
+
+import org.apache.wicket.request.Url;
+import org.apache.wicket.request.resource.ResourceReference;
+import org.apache.wicket.request.resource.ResourceReference.UrlAttributes;
+import org.junit.Assert;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+
+public class ResourceUtilTest extends Assert
+{
+	@Test
+	public void decodeResourceReferenceAttributesWithString() throws Exception
+	{
+		String urlParameter = "en_GB-style-variation";
+		UrlAttributes attributes = ResourceUtil.decodeResourceReferenceAttributes(urlParameter);
+
+		assertEquals(Locale.UK, attributes.getLocale());
+		assertEquals("style", attributes.getStyle());
+		assertEquals("variation", attributes.getVariation());
+
+		attributes = ResourceUtil.decodeResourceReferenceAttributes("it_IT");
+
+		assertEquals(Locale.ITALY, attributes.getLocale());
+		assertNull(attributes.getStyle());
+		assertNull(attributes.getVariation());
+
+		attributes = ResourceUtil.decodeResourceReferenceAttributes("-style-variation");
+		assertNull(attributes.getLocale());
+		assertEquals("style", attributes.getStyle());
+		assertEquals("variation", attributes.getVariation());
+
+		attributes = ResourceUtil.decodeResourceReferenceAttributes("--variation");
+		assertNull(attributes.getLocale());
+		assertNull(attributes.getStyle());
+		assertEquals("variation", attributes.getVariation());
+
+		attributes = ResourceUtil.decodeResourceReferenceAttributes("-style");
+		assertNull(attributes.getLocale());
+		assertEquals("style", attributes.getStyle());
+		assertNull(attributes.getVariation());
+	}
+
+	@Test
+	public void decodeResourceReferenceAttributesWithUrl() throws Exception
+	{
+		Url url = Url.parse("www.funny.url/?param1=value1");
+		UrlAttributes attributes = ResourceUtil.decodeResourceReferenceAttributes(url);
+
+		assertEquals(new UrlAttributes(null, null, null), attributes);
+
+		url = Url.parse("www.funny.url/?de_DE");
+		attributes = ResourceUtil.decodeResourceReferenceAttributes(url);
+		assertEquals(Locale.GERMANY, attributes.getLocale());
+		assertNull(attributes.getStyle());
+		assertNull(attributes.getVariation());
+
+		url = Url.parse("www.funny.url/?-style");
+		attributes = ResourceUtil.decodeResourceReferenceAttributes(url);
+		assertNull(attributes.getLocale());
+		assertEquals("style", attributes.getStyle());
+		assertNull(attributes.getVariation());
+	}
+
+	@Test
+	public void encodeResourceReferenceAttributes() throws Exception
+	{
+		UrlAttributes attributes = new UrlAttributes(null, null, null);
+		assertNull(ResourceUtil.encodeResourceReferenceAttributes(attributes));
+
+		attributes = new UrlAttributes(Locale.CANADA_FRENCH, "style", "variation");
+
+		assertEquals("fr_CA-style-variation", ResourceUtil.encodeResourceReferenceAttributes(attributes));
+
+		attributes = new UrlAttributes(null, null, "variation");
+
+		assertEquals("--variation", ResourceUtil.encodeResourceReferenceAttributes(attributes));
+	}
+
+	@Test
+	public void encodeResourceReferenceAttributesWithResource() throws Exception
+	{
+		ResourceReference resourceReference = Mockito.mock(ResourceReference.class);
+
+		//test with all null attributes
+		UrlAttributes attributes = new UrlAttributes(null, null, null);
+
+		String urlString = "www.funny.url";
+		Url url = Url.parse(urlString);
+
+		Mockito.when(resourceReference.getUrlAttributes()).thenReturn(attributes);
+		ResourceUtil.encodeResourceReferenceAttributes(url, resourceReference);
+
+		assertEquals(urlString, url.toString());
+
+		Mockito.reset(resourceReference);
+
+		//test with locale, style and variation
+		attributes = new UrlAttributes(Locale.CANADA_FRENCH, "style", "variation");
+
+		Mockito.when(resourceReference.getUrlAttributes()).thenReturn(attributes);
+		ResourceUtil.encodeResourceReferenceAttributes(url, resourceReference);
+
+		assertEquals(urlString + "?fr_CA-style-variation", url.toString());
+
+		Mockito.reset(resourceReference);
+
+		//test with just variation
+		attributes = new UrlAttributes(null, null, "variation");
+		url = Url.parse(urlString);
+
+		Mockito.when(resourceReference.getUrlAttributes()).thenReturn(attributes);
+		ResourceUtil.encodeResourceReferenceAttributes(url, resourceReference);
+
+		assertEquals(urlString + "?--variation", url.toString());
+
+	}
+}

http://git-wip-us.apache.org/repos/asf/wicket/blob/00c1e3b5/wicket-util/src/main/java/org/apache/wicket/util/lang/Objects.java
----------------------------------------------------------------------
diff --git a/wicket-util/src/main/java/org/apache/wicket/util/lang/Objects.java b/wicket-util/src/main/java/org/apache/wicket/util/lang/Objects.java
index 4757401..ef5c0e5 100755
--- a/wicket-util/src/main/java/org/apache/wicket/util/lang/Objects.java
+++ b/wicket-util/src/main/java/org/apache/wicket/util/lang/Objects.java
@@ -767,9 +767,25 @@ public final class Objects
 	}
 
 	/**
+	 * Returns the original object if this one is != null. If the original object is null
+	 * the default one is returned. The default object has no restriction, it might be itself null.
+	 *
+	 * @param originalObj
+	 * 			the original object
+	 * @param defaultObj
+	 * 			the default object
+	 * @return the original object if not null, the default one otherwise.
+	 */
+	public static <T> T defaultIfNull(T originalObj, T defaultObj)
+	{
+		return originalObj != null ? originalObj : defaultObj;
+	}
+
+	/**
 	 * Instantiation not allowed
 	 */
 	private Objects()
 	{
 	}
+
 }

http://git-wip-us.apache.org/repos/asf/wicket/blob/00c1e3b5/wicket-util/src/main/java/org/apache/wicket/util/string/Strings.java
----------------------------------------------------------------------
diff --git a/wicket-util/src/main/java/org/apache/wicket/util/string/Strings.java b/wicket-util/src/main/java/org/apache/wicket/util/string/Strings.java
index 49119f7..bbcf70a 100755
--- a/wicket-util/src/main/java/org/apache/wicket/util/string/Strings.java
+++ b/wicket-util/src/main/java/org/apache/wicket/util/string/Strings.java
@@ -1562,4 +1562,19 @@ public final class Strings
 					String.format("Cannot convert '%s' to enum constant of type '%s'.", value, enumClass), e);
 		}
 	}
+
+	/**
+	 * Returns the original string if this one is not empty (i.e. {@link #isEmpty(CharSequence)} returns false),
+	 * otherwise the default one is returned. The default string might be itself an empty one.
+	 *
+	 * @param originalString
+	 * 				the original sting value
+	 * @param defaultValue
+	 * 				the default string to return if the original is empty
+	 * @return 	the original string value if not empty, the default one otherwise
+	 */
+	public static String defaultIfEmpty(String originalString, String defaultValue)
+	{
+		return isEmpty(originalString) ? defaultValue : originalString;
+	}
 }