diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/resource/AbstractVersionStrategy.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/resource/AbstractVersionStrategy.java index 8cb3c3b5f4..17d72700e8 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/resource/AbstractVersionStrategy.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/resource/AbstractVersionStrategy.java @@ -6,6 +6,7 @@ import java.util.regex.Pattern; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.springframework.util.Assert; import org.springframework.util.StringUtils; /** @@ -20,73 +21,106 @@ import org.springframework.util.StringUtils; * version string. * * @author Brian Clozel + * @author Rossen Stoyanchev * @since 4.1 */ public abstract class AbstractVersionStrategy implements VersionStrategy { - private static final Pattern pattern = Pattern.compile("-(\\S*)\\."); - protected final Log logger = LogFactory.getLog(getClass()); - /** - * Extracts a version string from the request path, as a suffix in the resource - * file name. - * @param requestPath the request path to extract the version string from - * @return a version string or an empty string if none was found - */ - protected String extractVersionFromFilename(String requestPath) { - Matcher matcher = pattern.matcher(requestPath); - if (matcher.find()) { - String match = matcher.group(1); - return match.contains("-") ? match.substring(match.lastIndexOf("-") + 1) : match; - } - else { - return ""; - } + private final VersionPathStrategy pathStrategy; + + + protected AbstractVersionStrategy(VersionPathStrategy pathStrategy) { + Assert.notNull(pathStrategy, "'pathStrategy' is required"); + this.pathStrategy = pathStrategy; } - /** - * Deletes the given candidate version string from the request path. - * The version string should be a suffix in the resource file name. - */ - protected String deleteVersionFromFilename(String requestPath, String candidateVersion) { - return StringUtils.delete(requestPath, "-" + candidateVersion); + + public VersionPathStrategy getVersionPathStrategy() { + return this.pathStrategy; } - /** - * Adds the given version string to the baseUrl, as a file name suffix. - */ - protected String addVersionToFilename(String baseUrl, String version) { - String baseFilename = StringUtils.stripFilenameExtension(baseUrl); - String extension = StringUtils.getFilenameExtension(baseUrl); - return baseFilename + "-" + version + "." + extension; + + @Override + public String extractVersion(String requestPath) { + return this.pathStrategy.extractVersion(requestPath); } - /** - * Extracts a version string from the request path, as a prefix in the request path. - * @param requestPath the request path to extract the version string from - * @return a version string or an empty string if none was found - */ - protected String extractVersionAsPrefix(String requestPath, String prefix) { - if (requestPath.startsWith(prefix)) { - return prefix; - } - return ""; + @Override + public String removeVersion(String requestPath, String version) { + return this.pathStrategy.removeVersion(requestPath, version); + } + + @Override + public String addVersion(String requestPath, String version) { + return this.pathStrategy.addVersion(requestPath, version); } + /** - * Deletes the given candidate version string from the request path. - * The version string should be a prefix in the request path. + * A prefix-based {@code VersionPathStrategy}, + * e.g. {@code "{version}/path/foo.js"}. */ - protected String deleteVersionAsPrefix(String requestPath, String version) { - return requestPath.substring(version.length()); + protected static class PrefixVersionPathStrategy implements VersionPathStrategy { + + private final String prefix; + + + public PrefixVersionPathStrategy(String version) { + Assert.hasText(version, "'version' is required and must not be empty"); + this.prefix = version; + } + + @Override + public String extractVersion(String requestPath) { + return (requestPath.startsWith(this.prefix) ? this.prefix : null); + } + + @Override + public String removeVersion(String requestPath, String version) { + return requestPath.substring(this.prefix.length()); + } + + @Override + public String addVersion(String path, String version) { + return (this.prefix.endsWith("/") || path.startsWith("/") ? this.prefix + path : this.prefix + "/" + path); + } + } /** - * Adds the given version string to the baseUrl, as a prefix in the request path. + * File name-based {@code VersionPathStrategy}, + * e.g. {@code "path/foo-{version}.css"}. */ - protected String addVersionAsPrefix(String baseUrl, String version) { - return version + baseUrl; + protected static class FileNameVersionPathStrategy implements VersionPathStrategy { + + private static final Pattern pattern = Pattern.compile("-(\\S*)\\."); + + + @Override + public String extractVersion(String requestPath) { + Matcher matcher = pattern.matcher(requestPath); + if (matcher.find()) { + String match = matcher.group(1); + return match.contains("-") ? match.substring(match.lastIndexOf("-") + 1) : match; + } + else { + return null; + } + } + + @Override + public String removeVersion(String requestPath, String version) { + return StringUtils.delete(requestPath, "-" + version); + } + + @Override + public String addVersion(String requestPath, String version) { + String baseFilename = StringUtils.stripFilenameExtension(requestPath); + String extension = StringUtils.getFilenameExtension(requestPath); + return baseFilename + "-" + version + "." + extension; + } } } diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/resource/ContentBasedVersionStrategy.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/resource/ContentBasedVersionStrategy.java deleted file mode 100644 index 778e2e03e2..0000000000 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/resource/ContentBasedVersionStrategy.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright 2002-2014 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.springframework.web.servlet.resource; - -import java.io.IOException; -import java.util.List; - -import org.springframework.core.io.Resource; -import org.springframework.util.DigestUtils; -import org.springframework.util.FileCopyUtils; - -/** - * A {@code VersionStrategy} that handles version strings as a Hex MD5 hash in resource file names. - * - *

For example the path "styles/foo-e36d2e05253c6c7085a91522ce43a0b4.css" will - * match to "styles/foo.css" assuming the hash computed from the content of - * "foo.css" matches the hash in the path. - * - * @author Jeremy Grelle - * @author Rossen Stoyanchev - * @author Sam Brannen - * @author Brian Clozel - * @since 4.1 - * @see VersionResourceResolver - */ -public class ContentBasedVersionStrategy extends AbstractVersionStrategy { - - @Override - public String extractVersionFromPath(String requestPath) { - return extractVersionFromFilename(requestPath); - } - - @Override - public String deleteVersionFromPath(String requestPath, String candidateVersion) { - return deleteVersionFromFilename(requestPath, candidateVersion); - } - - @Override - public boolean resourceVersionMatches(Resource baseResource, String candidateVersion) { - String resourceHash = calculateHash(baseResource); - return candidateVersion.equals(resourceHash); - } - - @Override - public String addVersionToUrl(String baseUrl, List locations, ResourceResolverChain chain) { - if (logger.isTraceEnabled()) { - logger.trace("Getting the original resource to calculate hash"); - } - Resource original = chain.resolveResource(null, baseUrl, locations); - String hash = calculateHash(original); - if (logger.isTraceEnabled()) { - logger.trace("Calculated hash=" + hash); - } - return addVersionToFilename(baseUrl, hash); - } - - private String calculateHash(Resource resource) { - try { - byte[] content = FileCopyUtils.copyToByteArray(resource.getInputStream()); - return DigestUtils.md5DigestAsHex(content); - } - catch (IOException e) { - logger.error("Failed to calculate hash for resource [" + resource + "]"); - return ""; - } - } - -} diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/resource/ContentVersionStrategy.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/resource/ContentVersionStrategy.java new file mode 100644 index 0000000000..c9a3c9175a --- /dev/null +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/resource/ContentVersionStrategy.java @@ -0,0 +1,53 @@ +/* + * Copyright 2002-2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.web.servlet.resource; + +import java.io.IOException; + +import org.springframework.core.io.Resource; +import org.springframework.util.DigestUtils; +import org.springframework.util.FileCopyUtils; + +/** + * A {@code VersionStrategy} that calculates an Hex MD5 hashes from the content + * of the resource and appends it to the file name, e.g. + * {@code "styles/main-e36d2e05253c6c7085a91522ce43a0b4.css"}. + * + * @author Brian Clozel + * @author Rossen Stoyanchev + * @since 4.1 + * @see VersionResourceResolver + */ +public class ContentVersionStrategy extends AbstractVersionStrategy { + + + public ContentVersionStrategy() { + super(new FileNameVersionPathStrategy()); + } + + + @Override + public String getResourceVersion(Resource resource) { + try { + byte[] content = FileCopyUtils.copyToByteArray(resource.getInputStream()); + return DigestUtils.md5DigestAsHex(content); + } + catch (IOException ex) { + throw new IllegalStateException("Failed to calculate hash for resource [" + resource + "]", ex); + } + } + +} diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/resource/FixedVersionStrategy.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/resource/FixedVersionStrategy.java index 9c8d9da229..eacc005202 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/resource/FixedVersionStrategy.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/resource/FixedVersionStrategy.java @@ -15,28 +15,18 @@ */ package org.springframework.web.servlet.resource; -import java.util.List; -import java.util.concurrent.Callable; - import org.springframework.core.io.Resource; -import org.springframework.util.Assert; /** - * A {@code VersionStrategy} that handles unique, static, application-wide version strings - * as prefixes in the request path. - * - *

Enables inserting a unique and static version String (e.g. reduced SHA, version name, - * release date) at the beginning of resource paths so that when a new version of the application - * is released, clients are forced to reload application resources. + * A {@code VersionStrategy} that relies on a fixed version applied as a request + * path prefix, e.g. reduced SHA, version name, release date, etc. * - *

This is useful when changing resource names is not an option (e.g. when - * using JavaScript module loaders). If that's not the case, the use of - * {@link ContentBasedVersionStrategy} provides more optimal performance since - * version is generated on a per-resource basis: only actually modified resources are reloaded - * by the client. + *

This is useful for example when {@link ContentVersionStrategy} cannot be + * used such as when using JavaScript module loaders which are in charge of + * loading the JavaScript resources and need to know their relative paths. * * @author Brian Clozel - * @author Sam Brannen + * @author Rossen Stoyanchev * @since 4.1 * @see VersionResourceResolver */ @@ -46,44 +36,17 @@ public class FixedVersionStrategy extends AbstractVersionStrategy { /** * Create a new FixedVersionStrategy with the given version string. - * @param fixedVersion the fixed version string to use - */ - public FixedVersionStrategy(String fixedVersion) { - Assert.hasText(fixedVersion, "version must not be null or empty"); - this.version = fixedVersion.endsWith("/") ? fixedVersion : fixedVersion + "/"; - } - - /** - * Create a new FixedVersionStrategy and get the version string to use by - * calling the given {@code Callable} instance. + * @param version the fixed version string to use */ - public FixedVersionStrategy(Callable versionInitializer) throws Exception { - String fixedVersion = versionInitializer.call(); - Assert.hasText(fixedVersion, "version must not be null or empty"); - this.version = fixedVersion.endsWith("/") ? fixedVersion : fixedVersion + "/"; - } - - @Override - public String extractVersionFromPath(String requestPath) { - - return extractVersionAsPrefix(requestPath, this.version); - } - - @Override - public String deleteVersionFromPath(String requestPath, String candidateVersion) { - return deleteVersionAsPrefix(requestPath, candidateVersion); + public FixedVersionStrategy(String version) { + super(new PrefixVersionPathStrategy(version)); + this.version = version; } - @Override - public boolean resourceVersionMatches(Resource baseResource, String candidateVersion) { - return this.version.equals(candidateVersion); - } @Override - public String addVersionToUrl(String baseUrl, List locations, - ResourceResolverChain chain) { - - return addVersionAsPrefix(baseUrl, this.version); + public String getResourceVersion(Resource resource) { + return this.version; } } diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/resource/VersionPathStrategy.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/resource/VersionPathStrategy.java new file mode 100644 index 0000000000..995145ed53 --- /dev/null +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/resource/VersionPathStrategy.java @@ -0,0 +1,51 @@ +/* + * Copyright 2002-2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.web.servlet.resource; + +/** + * A strategy for extracting and embedding a resource version in its URL path. + * + * @author Brian Clozel + * @author Rossen Stoyanchev + * @since 4.1 +*/ +public interface VersionPathStrategy { + + /** + * Extract the resource version from the request path. + * @param requestPath the request path to check + * @return the version string or {@code null} if none was found + */ + String extractVersion(String requestPath); + + /** + * Remove the version from the request path. It is assumed that the given + * version was extracted via {@link #extractVersion(String)}. + * @param requestPath the request path of the resource being resolved + * @param version the version obtained from {@link #extractVersion(String)} + * @return the request path with the version removed + */ + String removeVersion(String requestPath, String version); + + /** + * Add a version to the given request path. + * @param requestPath the requestPath + * @param version the version + * @return the requestPath updated with a version string + */ + String addVersion(String requestPath, String version); + +} diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/resource/VersionResourceResolver.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/resource/VersionResourceResolver.java index 0e195f615f..bd972c15f0 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/resource/VersionResourceResolver.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/resource/VersionResourceResolver.java @@ -50,6 +50,7 @@ public class VersionResourceResolver extends AbstractResourceResolver { private Map versionStrategyMap = Collections.emptyMap(); + /** * Set a Map with URL paths as keys and {@code VersionStrategy} * as values. @@ -59,10 +60,11 @@ public class VersionResourceResolver extends AbstractResourceResolver { * * @param versionStrategyMap map with URLs as keys and version strategies as values */ - public void setVersionStrategyMap(Map versionStrategyMap) { + public void setStrategyMap(Map versionStrategyMap) { this.versionStrategyMap = versionStrategyMap; } + @Override protected Resource resolveResourceInternal(HttpServletRequest request, String requestPath, List locations, ResourceResolverChain chain) { @@ -72,12 +74,12 @@ public class VersionResourceResolver extends AbstractResourceResolver { return resolved; } - VersionStrategy versionStrategy = findStrategy(requestPath); + VersionStrategy versionStrategy = getStrategyForPath(requestPath); if (versionStrategy == null) { return null; } - String candidateVersion = versionStrategy.extractVersionFromPath(requestPath); + String candidateVersion = versionStrategy.extractVersion(requestPath); if (StringUtils.isEmpty(candidateVersion)) { if (logger.isTraceEnabled()) { logger.trace("No version found in path=\"" + requestPath + "\""); @@ -85,7 +87,7 @@ public class VersionResourceResolver extends AbstractResourceResolver { return null; } - String simplePath = versionStrategy.deleteVersionFromPath(requestPath, candidateVersion); + String simplePath = versionStrategy.removeVersion(requestPath, candidateVersion); if (logger.isTraceEnabled()) { logger.trace("Extracted version from path, re-resolving without version, path=\"" + simplePath + "\""); @@ -96,7 +98,8 @@ public class VersionResourceResolver extends AbstractResourceResolver { return null; } - if (versionStrategy.resourceVersionMatches(baseResource, candidateVersion)) { + String actualVersion = versionStrategy.getResourceVersion(baseResource); + if (candidateVersion.equals(actualVersion)) { if (logger.isTraceEnabled()) { logger.trace("resource matches extracted version"); } @@ -113,11 +116,19 @@ public class VersionResourceResolver extends AbstractResourceResolver { protected String resolveUrlPathInternal(String resourceUrlPath, List locations, ResourceResolverChain chain) { String baseUrl = chain.resolveUrlPath(resourceUrlPath, locations); if (StringUtils.hasText(baseUrl)) { - VersionStrategy versionStrategy = findStrategy(resourceUrlPath); + VersionStrategy versionStrategy = getStrategyForPath(resourceUrlPath); if (versionStrategy == null) { return null; } - return versionStrategy.addVersionToUrl(baseUrl, locations, chain); + if (logger.isTraceEnabled()) { + logger.trace("Getting the original resource to determine version"); + } + Resource resource = chain.resolveResource(null, baseUrl, locations); + String version = versionStrategy.getResourceVersion(resource); + if (logger.isTraceEnabled()) { + logger.trace("Version=" + version); + } + return versionStrategy.addVersion(baseUrl, version); } return baseUrl; } @@ -126,7 +137,7 @@ public class VersionResourceResolver extends AbstractResourceResolver { * Finds a {@code VersionStrategy} for the request path of the requested resource. * @return an instance of a {@code VersionStrategy} or null if none matches that request path */ - protected VersionStrategy findStrategy(String requestPath) { + protected VersionStrategy getStrategyForPath(String requestPath) { String path = "/".concat(requestPath); List matchingPatterns = new ArrayList(); for (String pattern : this.versionStrategyMap.keySet()) { diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/resource/VersionStrategy.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/resource/VersionStrategy.java index 5385e036e0..1893566f9a 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/resource/VersionStrategy.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/resource/VersionStrategy.java @@ -15,50 +15,24 @@ */ package org.springframework.web.servlet.resource; -import java.util.List; - import org.springframework.core.io.Resource; /** - * A strategy for handling version strings in request paths when resolving - * static resources with a {@link VersionResourceResolver}. + * An extension of {@link VersionPathStrategy} that adds a method to determine the + * actual version of a {@link org.springframework.core.io.Resource Resource}. * * @author Brian Clozel + * @author Rossen Stoyanchev * @since 4.1 * @see VersionResourceResolver */ -public interface VersionStrategy { +public interface VersionStrategy extends VersionPathStrategy { /** - * Extracts a version string from the request path. - * @param requestPath the request path of the resource being resolved - * @return the version string or an empty string if none was found + * Get the version for the given resource. + * @param resource the resource to check + * @return the version, never {@code null} */ - String extractVersionFromPath(String requestPath); + String getResourceVersion(Resource resource); - /** - * Deletes the given candidate version string from the given request path. - * @param requestPath the request path of the resource being resolved - * @param candidateVersion the candidate version string - * @return the modified request path, without the version string - */ - String deleteVersionFromPath(String requestPath, String candidateVersion); - - /** - * Checks whether the given {@code Resource} matches the candidate version string. - * Useful when the version string is managed on a per-resource basis. - * @param baseResource the resource to check against the given version - * @param candidateVersion the candidate version for the given resource - * @return true if the resource matches the version string, false otherwise - */ - boolean resourceVersionMatches(Resource baseResource, String candidateVersion); - - /** - * Adds a version string to the given baseUrl. - * @param baseUrl the baseUrl of the requested resource - * @param locations the resource locations to resolve resources from - * @param chain the chain of resource resolvers - * @return the baseUrl updated with a version string - */ - String addVersionToUrl(String baseUrl, List locations, ResourceResolverChain chain); } diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/resource/AppCacheManifestTransformerTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/resource/AppCacheManifestTransformerTests.java index 567dad0425..75210d071a 100644 --- a/spring-webmvc/src/test/java/org/springframework/web/servlet/resource/AppCacheManifestTransformerTests.java +++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/resource/AppCacheManifestTransformerTests.java @@ -78,7 +78,7 @@ public class AppCacheManifestTransformerTests { VersionResourceResolver versionResourceResolver = new VersionResourceResolver(); versionResourceResolver - .setVersionStrategyMap(Collections.singletonMap("/**", new ContentBasedVersionStrategy())); + .setStrategyMap(Collections.singletonMap("/**", new ContentVersionStrategy())); List resolvers = new ArrayList(); resolvers.add(versionResourceResolver); diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/resource/ContentBasedVersionStrategyTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/resource/ContentBasedVersionStrategyTests.java index 9d2b0fc14d..f1b3fdfcaa 100644 --- a/spring-webmvc/src/test/java/org/springframework/web/servlet/resource/ContentBasedVersionStrategyTests.java +++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/resource/ContentBasedVersionStrategyTests.java @@ -15,10 +15,7 @@ */ package org.springframework.web.servlet.resource; -import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; -import java.util.List; import org.junit.Before; import org.junit.Test; @@ -31,65 +28,50 @@ import org.springframework.util.FileCopyUtils; import static org.junit.Assert.*; /** - * Unit tests for {@link org.springframework.web.servlet.resource.ContentBasedVersionStrategy} + * Unit tests for {@link ContentVersionStrategy} * @author Brian Clozel */ public class ContentBasedVersionStrategyTests { - private List locations; + private ContentVersionStrategy versionStrategy = new ContentVersionStrategy(); - private ContentBasedVersionStrategy versionStrategy = new ContentBasedVersionStrategy(); - - private ResourceResolverChain chain; @Before public void setup() { - this.locations = new ArrayList(); - this.locations.add(new ClassPathResource("test/", getClass())); - this.locations.add(new ClassPathResource("testalternatepath/", getClass())); - VersionResourceResolver versionResourceResolver = new VersionResourceResolver(); - versionResourceResolver.setVersionStrategyMap(Collections.singletonMap("/**", this.versionStrategy)); - this.chain = new DefaultResourceResolverChain(Arrays.asList(versionResourceResolver, new PathResourceResolver())); + versionResourceResolver.setStrategyMap(Collections.singletonMap("/**", this.versionStrategy)); } @Test - public void extractVersionFromPath() throws Exception { + public void extractVersion() throws Exception { String hash = "7fbe76cdac6093784895bb4989203e5a"; String path = "font-awesome/css/font-awesome.min-" + hash + ".css"; - assertEquals(hash, this.versionStrategy.extractVersionFromPath(path)); - assertEquals("", this.versionStrategy.extractVersionFromPath("foo/bar.css")); + assertEquals(hash, this.versionStrategy.extractVersion(path)); + assertNull(this.versionStrategy.extractVersion("foo/bar.css")); } @Test - public void deleteVersionFromPath() throws Exception { + public void removeVersion() throws Exception { String file = "font-awesome/css/font-awesome.min%s%s.css"; String hash = "7fbe76cdac6093784895bb4989203e5a"; - assertEquals(String.format(file, "", ""), this.versionStrategy.deleteVersionFromPath(String.format(file, "-", hash), hash)); - assertEquals("", this.versionStrategy.extractVersionFromPath("foo/bar.css")); + assertEquals(String.format(file, "", ""), this.versionStrategy.removeVersion(String.format(file, "-", hash), hash)); + assertNull(this.versionStrategy.extractVersion("foo/bar.css")); } @Test - public void resourceVersionMatches() throws Exception { + public void getResourceVersion() throws Exception { Resource expected = new ClassPathResource("test/bar.css", getClass()); String hash = DigestUtils.md5DigestAsHex(FileCopyUtils.copyToByteArray(expected.getInputStream())); - String wrongHash = "wronghash"; - - assertTrue(this.versionStrategy.resourceVersionMatches(expected, hash)); - assertFalse(this.versionStrategy.resourceVersionMatches(expected, wrongHash)); + assertEquals(hash, this.versionStrategy.getResourceVersion(expected)); } @Test public void addVersionToUrl() throws Exception { - String file = "bar.css"; - Resource expected = new ClassPathResource("test/" + file, getClass()); - String hash = DigestUtils.md5DigestAsHex(FileCopyUtils.copyToByteArray(expected.getInputStream())); - String path = "bar-" + hash + ".css"; - String resultUrl = this.versionStrategy.addVersionToUrl(file, this.locations, this.chain); - - assertEquals(path, resultUrl); + String requestPath = "test/bar.css"; + String version = "123"; + assertEquals("test/bar-123.css", this.versionStrategy.addVersion(requestPath, version)); } } diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/resource/CssLinkResourceTransformerTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/resource/CssLinkResourceTransformerTests.java index c4d391098b..5f93358ddf 100644 --- a/spring-webmvc/src/test/java/org/springframework/web/servlet/resource/CssLinkResourceTransformerTests.java +++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/resource/CssLinkResourceTransformerTests.java @@ -50,9 +50,9 @@ public class CssLinkResourceTransformerTests { @Before public void setUp() { Map versionStrategyMap = new HashMap<>(); - versionStrategyMap.put("/**", new ContentBasedVersionStrategy()); + versionStrategyMap.put("/**", new ContentVersionStrategy()); VersionResourceResolver versionResolver = new VersionResourceResolver(); - versionResolver.setVersionStrategyMap(versionStrategyMap); + versionResolver.setStrategyMap(versionStrategyMap); List resolvers = new ArrayList(); resolvers.add(versionResolver); diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/resource/FixedVersionStrategyTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/resource/FixedVersionStrategyTests.java index b3cab06411..8eeb0ab0ee 100644 --- a/spring-webmvc/src/test/java/org/springframework/web/servlet/resource/FixedVersionStrategyTests.java +++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/resource/FixedVersionStrategyTests.java @@ -15,16 +15,11 @@ */ package org.springframework.web.servlet.resource; -import java.util.Collections; -import java.util.concurrent.Callable; - import org.junit.Before; import org.junit.Test; import static org.junit.Assert.*; -import org.springframework.core.io.Resource; - /** * Unit tests for {@link org.springframework.web.servlet.resource.FixedVersionStrategy} * @author Brian Clozel @@ -33,49 +28,36 @@ public class FixedVersionStrategyTests { private final String version = "1df341f"; - private final String resourceId = "js/foo.js"; + private final String path = "js/foo.js"; + + private FixedVersionStrategy strategy; - private FixedVersionStrategy versionStrategy; @Before public void setup() { - this.versionStrategy = new FixedVersionStrategy(this.version); + this.strategy = new FixedVersionStrategy(this.version); } - @Test(expected = IllegalArgumentException.class) - public void constructWithEmptyPrefixVersion() throws Exception { - - FixedVersionStrategy versionStrategy = new FixedVersionStrategy(" "); - } @Test(expected = IllegalArgumentException.class) - public void constructWithEmptyCallableVersion() throws Exception { - - FixedVersionStrategy versionStrategy = new FixedVersionStrategy( - new Callable() { - @Override - public String call() throws Exception { - return " "; - } - }); + public void emptyPrefixVersion() throws Exception { + new FixedVersionStrategy(" "); } @Test - public void extractVersionFromPath() throws Exception { - assertEquals(this.version + "/", this.versionStrategy.extractVersionFromPath(this.version + "/" + this.resourceId)); - assertEquals("", this.versionStrategy.extractVersionFromPath(this.resourceId)); + public void extractVersion() throws Exception { + assertEquals(this.version, this.strategy.extractVersion(this.version + "/" + this.path)); + assertNull(this.strategy.extractVersion(this.path)); } @Test - public void deleteVersionFromPath() throws Exception { - assertEquals(this.resourceId, - this.versionStrategy.deleteVersionFromPath(this.version + "/" + this.resourceId, this.version + "/")); + public void removeVersion() throws Exception { + assertEquals("/" + this.path, this.strategy.removeVersion(this.version + "/" + this.path, this.version)); } @Test - public void addVersionToUrl() throws Exception { - assertEquals(this.version + "/" + this.resourceId, - this.versionStrategy.addVersionToUrl(this.resourceId, Collections.emptyList(), null)); - + public void addVersion() throws Exception { + assertEquals(this.version + "/" + this.path, this.strategy.addVersion(this.path, this.version)); } + } diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/resource/GzipResourceResolverTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/resource/GzipResourceResolverTests.java index 40a9ad18bf..b322f21c3a 100644 --- a/spring-webmvc/src/test/java/org/springframework/web/servlet/resource/GzipResourceResolverTests.java +++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/resource/GzipResourceResolverTests.java @@ -71,9 +71,9 @@ public class GzipResourceResolverTests { @Before public void setUp() { Map versionStrategyMap = new HashMap<>(); - versionStrategyMap.put("/**", new ContentBasedVersionStrategy()); + versionStrategyMap.put("/**", new ContentVersionStrategy()); VersionResourceResolver versionResolver = new VersionResourceResolver(); - versionResolver.setVersionStrategyMap(versionStrategyMap); + versionResolver.setStrategyMap(versionStrategyMap); List resolvers = new ArrayList(); resolvers.add(new GzipResourceResolver()); diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/resource/ResourceUrlProviderJavaConfigTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/resource/ResourceUrlProviderJavaConfigTests.java index 48749ff3eb..2641b763f0 100644 --- a/spring-webmvc/src/test/java/org/springframework/web/servlet/resource/ResourceUrlProviderJavaConfigTests.java +++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/resource/ResourceUrlProviderJavaConfigTests.java @@ -115,9 +115,9 @@ public class ResourceUrlProviderJavaConfigTests { @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { Map versionStrategyMap = new HashMap<>(); - versionStrategyMap.put("/**", new ContentBasedVersionStrategy()); + versionStrategyMap.put("/**", new ContentVersionStrategy()); VersionResourceResolver versionResolver = new VersionResourceResolver(); - versionResolver.setVersionStrategyMap(versionStrategyMap); + versionResolver.setStrategyMap(versionStrategyMap); registry.addResourceHandler("/resources/**") .addResourceLocations("classpath:org/springframework/web/servlet/resource/test/") diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/resource/ResourceUrlProviderTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/resource/ResourceUrlProviderTests.java index 12e4ced623..870b305574 100644 --- a/spring-webmvc/src/test/java/org/springframework/web/servlet/resource/ResourceUrlProviderTests.java +++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/resource/ResourceUrlProviderTests.java @@ -68,9 +68,9 @@ public class ResourceUrlProviderTests { @Test public void getFingerprintedResourceUrl() { Map versionStrategyMap = new HashMap<>(); - versionStrategyMap.put("/**", new ContentBasedVersionStrategy()); + versionStrategyMap.put("/**", new ContentVersionStrategy()); VersionResourceResolver versionResolver = new VersionResourceResolver(); - versionResolver.setVersionStrategyMap(versionStrategyMap); + versionResolver.setStrategyMap(versionStrategyMap); List resolvers = new ArrayList(); resolvers.add(versionResolver); diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/resource/VersionResourceResolverTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/resource/VersionResourceResolverTests.java index cbeddb0e0f..61d80000da 100644 --- a/spring-webmvc/src/test/java/org/springframework/web/servlet/resource/VersionResourceResolverTests.java +++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/resource/VersionResourceResolverTests.java @@ -40,7 +40,7 @@ public class VersionResourceResolverTests { private List locations; - private VersionResourceResolver versionResourceResolver; + private VersionResourceResolver resolver; private ResourceResolverChain chain; @@ -49,126 +49,118 @@ public class VersionResourceResolverTests { @Before public void setup() { - this.locations = new ArrayList(); + this.locations = new ArrayList<>(); this.locations.add(new ClassPathResource("test/", getClass())); this.locations.add(new ClassPathResource("testalternatepath/", getClass())); - this.versionResourceResolver = new VersionResourceResolver(); + this.resolver = new VersionResourceResolver(); this.chain = mock(ResourceResolverChain.class); this.versionStrategy = mock(VersionStrategy.class); } @Test - public void resolveResourceInternalExisting() throws Exception { + public void resolveResourceExisting() throws Exception { String file = "bar.css"; Resource expected = new ClassPathResource("test/" + file, getClass()); when(this.chain.resolveResource(null, file, this.locations)).thenReturn(expected); - this.versionResourceResolver - .setVersionStrategyMap(Collections.singletonMap("/**", this.versionStrategy)); - Resource actual = this.versionResourceResolver.resolveResourceInternal(null, file, this.locations, this.chain); + this.resolver.setStrategyMap(Collections.singletonMap("/**", this.versionStrategy)); + Resource actual = this.resolver.resolveResourceInternal(null, file, this.locations, this.chain); assertEquals(expected, actual); verify(this.chain, times(1)).resolveResource(null, file, this.locations); - verify(this.versionStrategy, never()).extractVersionFromPath(file); + verify(this.versionStrategy, never()).extractVersion(file); } @Test - public void resolveResourceInternalNoStrategy() throws Exception { + public void resolveResourceNoVersionStrategy() throws Exception { String file = "missing.css"; when(this.chain.resolveResource(null, file, this.locations)).thenReturn(null); - this.versionResourceResolver.setVersionStrategyMap(Collections.emptyMap()); - Resource actual = this.versionResourceResolver.resolveResourceInternal(null, file, this.locations, this.chain); + this.resolver.setStrategyMap(Collections.emptyMap()); + Resource actual = this.resolver.resolveResourceInternal(null, file, this.locations, this.chain); assertNull(actual); verify(this.chain, times(1)).resolveResource(null, file, this.locations); } @Test - public void resolveResourceInternalNoCandidateVersion() throws Exception { - + public void resolveResourceNoVersionInPath() throws Exception { String file = "bar.css"; when(this.chain.resolveResource(null, file, this.locations)).thenReturn(null); - when(this.versionStrategy.extractVersionFromPath(file)).thenReturn(""); + when(this.versionStrategy.extractVersion(file)).thenReturn(""); - this.versionResourceResolver - .setVersionStrategyMap(Collections.singletonMap("/**", this.versionStrategy)); - Resource actual = this.versionResourceResolver.resolveResourceInternal(null, file, this.locations, this.chain); + this.resolver.setStrategyMap(Collections.singletonMap("/**", this.versionStrategy)); + Resource actual = this.resolver.resolveResourceInternal(null, file, this.locations, this.chain); assertNull(actual); verify(this.chain, times(1)).resolveResource(null, file, this.locations); - verify(this.versionStrategy, times(1)).extractVersionFromPath(file); + verify(this.versionStrategy, times(1)).extractVersion(file); } @Test - public void resolveResourceInternalNoBaseResource() throws Exception { - + public void resolveResourceNoResourceAfterVersionRemoved() throws Exception { String versionFile = "bar-version.css"; String version = "version"; String file = "bar.css"; when(this.chain.resolveResource(null, versionFile, this.locations)).thenReturn(null); when(this.chain.resolveResource(null, file, this.locations)).thenReturn(null); - when(this.versionStrategy.extractVersionFromPath(versionFile)).thenReturn(version); - when(this.versionStrategy.deleteVersionFromPath(versionFile, version)).thenReturn(file); + when(this.versionStrategy.extractVersion(versionFile)).thenReturn(version); + when(this.versionStrategy.removeVersion(versionFile, version)).thenReturn(file); - this.versionResourceResolver - .setVersionStrategyMap(Collections.singletonMap("/**", this.versionStrategy)); - Resource actual = this.versionResourceResolver.resolveResourceInternal(null, versionFile, this.locations, this.chain); + this.resolver.setStrategyMap(Collections.singletonMap("/**", this.versionStrategy)); + Resource actual = this.resolver.resolveResourceInternal(null, versionFile, this.locations, this.chain); assertNull(actual); - verify(this.versionStrategy, times(1)).deleteVersionFromPath(versionFile, version); + verify(this.versionStrategy, times(1)).removeVersion(versionFile, version); } @Test - public void resolveResourceInternalNoMatch() throws Exception { - + public void resolveResourceVersionDoesNotMatch() throws Exception { String versionFile = "bar-version.css"; String version = "version"; String file = "bar.css"; Resource expected = new ClassPathResource("test/" + file, getClass()); when(this.chain.resolveResource(null, versionFile, this.locations)).thenReturn(null); when(this.chain.resolveResource(null, file, this.locations)).thenReturn(expected); - when(this.versionStrategy.extractVersionFromPath(versionFile)).thenReturn(version); - when(this.versionStrategy.deleteVersionFromPath(versionFile, version)).thenReturn(file); - when(this.versionStrategy.resourceVersionMatches(expected, version)).thenReturn(false); + when(this.versionStrategy.extractVersion(versionFile)).thenReturn(version); + when(this.versionStrategy.removeVersion(versionFile, version)).thenReturn(file); + when(this.versionStrategy.getResourceVersion(expected)).thenReturn("newer-version"); - this.versionResourceResolver - .setVersionStrategyMap(Collections.singletonMap("/**", this.versionStrategy)); - Resource actual = this.versionResourceResolver.resolveResourceInternal(null, versionFile, this.locations, this.chain); + this.resolver.setStrategyMap(Collections.singletonMap("/**", this.versionStrategy)); + Resource actual = this.resolver.resolveResourceInternal(null, versionFile, this.locations, this.chain); assertNull(actual); - verify(this.versionStrategy, times(1)).resourceVersionMatches(expected, version); + verify(this.versionStrategy, times(1)).getResourceVersion(expected); } @Test - public void resolveResourceInternalMatch() throws Exception { - + public void resolveResourceSuccess() throws Exception { String versionFile = "bar-version.css"; String version = "version"; String file = "bar.css"; Resource expected = new ClassPathResource("test/" + file, getClass()); when(this.chain.resolveResource(null, versionFile, this.locations)).thenReturn(null); when(this.chain.resolveResource(null, file, this.locations)).thenReturn(expected); - when(this.versionStrategy.extractVersionFromPath(versionFile)).thenReturn(version); - when(this.versionStrategy.deleteVersionFromPath(versionFile, version)).thenReturn(file); - when(this.versionStrategy.resourceVersionMatches(expected, version)).thenReturn(true); + when(this.versionStrategy.extractVersion(versionFile)).thenReturn(version); + when(this.versionStrategy.removeVersion(versionFile, version)).thenReturn(file); + when(this.versionStrategy.getResourceVersion(expected)).thenReturn(version); - this.versionResourceResolver - .setVersionStrategyMap(Collections.singletonMap("/**", this.versionStrategy)); - Resource actual = this.versionResourceResolver.resolveResourceInternal(null, versionFile, this.locations, this.chain); + this.resolver + .setStrategyMap(Collections.singletonMap("/**", this.versionStrategy)); + Resource actual = this.resolver.resolveResourceInternal(null, versionFile, this.locations, this.chain); assertEquals(expected, actual); - verify(this.versionStrategy, times(1)).resourceVersionMatches(expected, version); + verify(this.versionStrategy, times(1)).getResourceVersion(expected); } @Test - public void findStrategy() throws Exception { + public void getStrategyForPath() throws Exception { Map strategies = new HashMap<>(); VersionStrategy jsStrategy = mock(VersionStrategy.class); VersionStrategy catchAllStrategy = mock(VersionStrategy.class); strategies.put("/**", catchAllStrategy); strategies.put("/**/*.js", jsStrategy); - this.versionResourceResolver.setVersionStrategyMap(strategies); + this.resolver.setStrategyMap(strategies); - assertEquals(catchAllStrategy, this.versionResourceResolver.findStrategy("foo.css")); - assertEquals(catchAllStrategy, this.versionResourceResolver.findStrategy("foo-js.css")); - assertEquals(jsStrategy, this.versionResourceResolver.findStrategy("foo.js")); - assertEquals(jsStrategy, this.versionResourceResolver.findStrategy("bar/foo.js")); + assertEquals(catchAllStrategy, this.resolver.getStrategyForPath("foo.css")); + assertEquals(catchAllStrategy, this.resolver.getStrategyForPath("foo-js.css")); + assertEquals(jsStrategy, this.resolver.getStrategyForPath("foo.js")); + assertEquals(jsStrategy, this.resolver.getStrategyForPath("bar/foo.js")); } }