WICKET-5827 Allow to apply multiple Javascript / CSS compressors Re-implement CssUrlReplacer
Project: http://git-wip-us.apache.org/repos/asf/wicket/repo Commit: http://git-wip-us.apache.org/repos/asf/wicket/commit/08f8a556 Tree: http://git-wip-us.apache.org/repos/asf/wicket/tree/08f8a556 Diff: http://git-wip-us.apache.org/repos/asf/wicket/diff/08f8a556 Branch: refs/heads/master Commit: 08f8a556722b8b803430194ab8e80d00199a5401 Parents: b87b459 Author: Martin Tzvetanov Grigorov <mgrigo...@apache.org> Authored: Fri Feb 6 00:20:57 2015 +0200 Committer: Martin Tzvetanov Grigorov <mgrigo...@apache.org> Committed: Fri Feb 6 00:20:57 2015 +0200 ---------------------------------------------------------------------- .../request/resource/CssPackageResource.java | 17 +++- .../wicket/resource/CompositeCssCompressor.java | 22 ++++- .../apache/wicket/resource/CssUrlReplacer.java | 94 +++++--------------- .../IScopeAwareTextResourceProcessor.java | 17 ++++ .../wicket/resource/CssUrlReplacerTest.java | 75 ++++++++++++++++ 5 files changed, 148 insertions(+), 77 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/wicket/blob/08f8a556/wicket-core/src/main/java/org/apache/wicket/request/resource/CssPackageResource.java ---------------------------------------------------------------------- diff --git a/wicket-core/src/main/java/org/apache/wicket/request/resource/CssPackageResource.java b/wicket-core/src/main/java/org/apache/wicket/request/resource/CssPackageResource.java index f6cf010..72e2dc1 100644 --- a/wicket-core/src/main/java/org/apache/wicket/request/resource/CssPackageResource.java +++ b/wicket-core/src/main/java/org/apache/wicket/request/resource/CssPackageResource.java @@ -20,6 +20,7 @@ import java.util.Locale; import org.apache.wicket.Application; import org.apache.wicket.css.ICssCompressor; +import org.apache.wicket.resource.IScopeAwareTextResourceProcessor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -32,6 +33,8 @@ public class CssPackageResource extends PackageResource private static final Logger log = LoggerFactory.getLogger(CssPackageResource.class); + private final String name; + /** * Construct. * @@ -46,6 +49,8 @@ public class CssPackageResource extends PackageResource { super(scope, name, locale, style, variation); + this.name = name; + // CSS resources can be compressed if there is configured ICssCompressor setCompress(true); } @@ -62,7 +67,17 @@ public class CssPackageResource extends PackageResource try { String nonCompressed = new String(processedResponse, "UTF-8"); - return compressor.compress(nonCompressed).getBytes(); + String output; + if (compressor instanceof IScopeAwareTextResourceProcessor) + { + IScopeAwareTextResourceProcessor scopeAwareProcessor = (IScopeAwareTextResourceProcessor) compressor; + output = scopeAwareProcessor.process(nonCompressed, getScope(), name); + } + else + { + output = compressor.compress(nonCompressed); + } + return output.getBytes(); } catch (Exception e) { http://git-wip-us.apache.org/repos/asf/wicket/blob/08f8a556/wicket-core/src/main/java/org/apache/wicket/resource/CompositeCssCompressor.java ---------------------------------------------------------------------- diff --git a/wicket-core/src/main/java/org/apache/wicket/resource/CompositeCssCompressor.java b/wicket-core/src/main/java/org/apache/wicket/resource/CompositeCssCompressor.java index 6756491..f23c937 100644 --- a/wicket-core/src/main/java/org/apache/wicket/resource/CompositeCssCompressor.java +++ b/wicket-core/src/main/java/org/apache/wicket/resource/CompositeCssCompressor.java @@ -41,7 +41,7 @@ import org.apache.wicket.css.ICssCompressor; * @author Tobias Soloschenko * */ -public class CompositeCssCompressor implements ICssCompressor +public class CompositeCssCompressor implements IScopeAwareTextResourceProcessor { /* Compressors to compress the CSS content */ private final List<ICssCompressor> compressors = new ArrayList<>(); @@ -62,16 +62,30 @@ public class CompositeCssCompressor implements ICssCompressor * given the original content is going to be returned. */ @Override - public String compress(String original) + public String process(String input, Class<?> scope, String name) { - String compressed = original; + String compressed = input; for (ICssCompressor compressor : compressors) { - compressed = compressor.compress(compressed); + if (compressor instanceof IScopeAwareTextResourceProcessor) + { + IScopeAwareTextResourceProcessor processor = (IScopeAwareTextResourceProcessor) compressor; + processor.process(compressed, scope, name); + } + else + { + compressed = compressor.compress(compressed); + } } return compressed; } + @Override + public String compress(String original) + { + throw new UnsupportedOperationException(CompositeCssCompressor.class.getSimpleName() + ".process() should be used instead!"); + } + /** * Adds a ICssCompressor to the list of delegates. * http://git-wip-us.apache.org/repos/asf/wicket/blob/08f8a556/wicket-core/src/main/java/org/apache/wicket/resource/CssUrlReplacer.java ---------------------------------------------------------------------- diff --git a/wicket-core/src/main/java/org/apache/wicket/resource/CssUrlReplacer.java b/wicket-core/src/main/java/org/apache/wicket/resource/CssUrlReplacer.java index 7c7864e..985c275 100644 --- a/wicket-core/src/main/java/org/apache/wicket/resource/CssUrlReplacer.java +++ b/wicket-core/src/main/java/org/apache/wicket/resource/CssUrlReplacer.java @@ -16,20 +16,10 @@ */ package org.apache.wicket.resource; -import java.net.URL; -import java.util.Collection; -import java.util.Collections; -import java.util.LinkedHashMap; -import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; -import org.apache.wicket.Application; -import org.apache.wicket.Component; -import org.apache.wicket.WicketRuntimeException; -import org.apache.wicket.application.IComponentInitializationListener; -import org.apache.wicket.core.util.lang.WicketObjects; -import org.apache.wicket.css.ICssCompressor; +import org.apache.wicket.request.Url; import org.apache.wicket.request.cycle.RequestCycle; import org.apache.wicket.request.resource.PackageResourceReference; @@ -46,78 +36,38 @@ import org.apache.wicket.request.resource.PackageResourceReference; * * @since 6.20.0 * @author Tobias Soloschenko - * */ -public class CssUrlReplacer implements ICssCompressor +public class CssUrlReplacer implements IScopeAwareTextResourceProcessor { - - // Holds the names of components - private final Map<String, String> componentNames = Collections.synchronizedMap(new LinkedHashMap<String, String>()); - // The pattern to find URLs in CSS resources - private static final Pattern urlPattern = Pattern.compile("url\\(['|\"]*(.*)['|\"]*\\)"); - - public CssUrlReplacer(Application application) - { - - // Create an instantiation listener to detect components - application.getComponentInitializationListeners().add( - new IComponentInitializationListener() - { - - @Override - public void onInitialize(Component component) - { - CssUrlReplacer.this.componentNames.put(component.getClass().getName(), - component.getClass().getSimpleName()); - } - }); - } + private static final Pattern URL_PATTERN = Pattern.compile("url\\(['|\"]*(.*?)['|\"]*\\)"); /** * Replaces the URLs of CSS resources with Wicket representatives. */ @Override - public String compress(String original) + public String process(String input, Class<?> scope, String name) { - Matcher matcher = CssUrlReplacer.urlPattern.matcher(original); - // Search for urls + PackageResourceReference cssReference = new PackageResourceReference(scope, name); + CharSequence urlToCss = RequestCycle.get().urlFor(cssReference, null); + Url cssUrl = Url.parse(urlToCss); + Matcher matcher = URL_PATTERN.matcher(input); + StringBuffer output = new StringBuffer(); + while (matcher.find()) { - Collection<String> componentNames = this.componentNames.keySet(); - for (String componentName : componentNames) - { - try - { - Class<?> componentClass = WicketObjects.resolveClass(componentName); - String url = matcher.group(1); - if (!url.contains("/")) - { - URL urlResource = componentClass.getResource(url); - // If the resource is not found skip it - if (urlResource != null) - { - PackageResourceReference packageResourceReference = new PackageResourceReference( - componentClass, url); - String replacedUrl = RequestCycle.get() - .urlFor(packageResourceReference, null) - .toString(); - StringBuilder urlBuilder = new StringBuilder(); - urlBuilder.append("url('"); - urlBuilder.append(replacedUrl); - urlBuilder.append("')"); - original = matcher.replaceFirst(urlBuilder.toString()); - } - } - } - catch (Exception e) - { - throw new WicketRuntimeException( - "A problem occurred during CSS url replacement.", e); - } - } - + Url imageRelativeUrl = Url.parse(matcher.group(1)); + Url cssUrlCopy = new Url(cssUrl); + cssUrlCopy.resolveRelative(imageRelativeUrl); + matcher.appendReplacement(output, "url('" + cssUrlCopy.toString() + "')"); } - return original; + matcher.appendTail(output); + return output.toString(); + } + + @Override + public String compress(String original) + { + throw new UnsupportedOperationException(CssUrlReplacer.class.getSimpleName() + ".process() should be used instead!"); } } http://git-wip-us.apache.org/repos/asf/wicket/blob/08f8a556/wicket-core/src/main/java/org/apache/wicket/resource/IScopeAwareTextResourceProcessor.java ---------------------------------------------------------------------- diff --git a/wicket-core/src/main/java/org/apache/wicket/resource/IScopeAwareTextResourceProcessor.java b/wicket-core/src/main/java/org/apache/wicket/resource/IScopeAwareTextResourceProcessor.java new file mode 100644 index 0000000..2b37c27 --- /dev/null +++ b/wicket-core/src/main/java/org/apache/wicket/resource/IScopeAwareTextResourceProcessor.java @@ -0,0 +1,17 @@ +package org.apache.wicket.resource; + +/** + * + */ +public interface IScopeAwareTextResourceProcessor extends ITextResourceCompressor +{ + /** + * Processes/manipulates a text resource. + * + * + * @param input + * @param scope + * @return The processed input + */ + public String process(String input, Class<?> scope, String name); +} http://git-wip-us.apache.org/repos/asf/wicket/blob/08f8a556/wicket-core/src/test/java/org/apache/wicket/resource/CssUrlReplacerTest.java ---------------------------------------------------------------------- diff --git a/wicket-core/src/test/java/org/apache/wicket/resource/CssUrlReplacerTest.java b/wicket-core/src/test/java/org/apache/wicket/resource/CssUrlReplacerTest.java new file mode 100644 index 0000000..157bd60 --- /dev/null +++ b/wicket-core/src/test/java/org/apache/wicket/resource/CssUrlReplacerTest.java @@ -0,0 +1,75 @@ +package org.apache.wicket.resource; + +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.is; + +import org.apache.wicket.WicketTestCase; +import org.junit.Test; + +public class CssUrlReplacerTest extends WicketTestCase +{ + @Test + public void sameFolderSingleQuotes() + { + String input = ".class {background-image: url('some.img');}"; + Class<?> scope = CssUrlReplacerTest.class; + String cssRelativePath = "res/css/some.css"; + CssUrlReplacer replacer = new CssUrlReplacer(); + + String processed = replacer.process(input, scope, cssRelativePath); + assertThat(processed, is(".class {background-image: url('./wicket/resource/org.apache.wicket.resource.CssUrlReplacerTest/res/css/some.img');}")); + } + + @Test + public void sameFolderDoubleQuotes() + { + String input = ".class {background-image: url(\"some.img\");}"; + Class<?> scope = CssUrlReplacerTest.class; + String cssRelativePath = "res/css/some.css"; + CssUrlReplacer replacer = new CssUrlReplacer(); + + String processed = replacer.process(input, scope, cssRelativePath); + assertThat(processed, is(".class {background-image: url('./wicket/resource/org.apache.wicket.resource.CssUrlReplacerTest/res/css/some.img');}")); + } + + @Test + public void parentFolderAppendFolder() + { + String input = ".class {background-image: url('../images/some.img');}"; + Class<?> scope = CssUrlReplacerTest.class; + String cssRelativePath = "res/css/some.css"; + CssUrlReplacer replacer = new CssUrlReplacer(); + + String processed = replacer.process(input, scope, cssRelativePath); + assertThat(processed, is(".class {background-image: url('./wicket/resource/org.apache.wicket.resource.CssUrlReplacerTest/res/images/some.img');}")); + } + + @Test + public void sameFolderAppendFolder() + { + String input = ".class {background-image: url('./images/some.img');}"; + Class<?> scope = CssUrlReplacerTest.class; + String cssRelativePath = "res/css/some.css"; + CssUrlReplacer replacer = new CssUrlReplacer(); + + String processed = replacer.process(input, scope, cssRelativePath); + assertThat(processed, is(".class {background-image: url('./wicket/resource/org.apache.wicket.resource.CssUrlReplacerTest/res/css/images/some.img');}")); + } + + @Test + public void severalUrls() + { + String input = + ".class {\n" + + "a: url('../images/a.img');\n" + + "b: url('./b.img');\n" + + "}"; + Class<?> scope = CssUrlReplacerTest.class; + String cssRelativePath = "res/css/some.css"; + CssUrlReplacer replacer = new CssUrlReplacer(); + + String processed = replacer.process(input, scope, cssRelativePath); + assertThat(processed, containsString("CssUrlReplacerTest/res/images/a.img');")); + assertThat(processed, containsString("CssUrlReplacerTest/res/css/b.img');")); + } +}