Refactor VersionStrategy in WebFlux

Collapse the base interface VersionPathStrategy into its extension
VersionStrategy and then turn the prefix nad fliename based
implementations into abstract base classes (vs delegate strategies).

It is simpler to have one VersionStrategy hierarchy vs that plus a
separate VersionPathStrategy as a delegate. In practice each
VersionStrategy is suited to be prefix or filename based. Also none
of our code cares about the distinction between those two interfaces.
This commit is contained in:
Rossen Stoyanchev
2017-07-18 04:35:56 +02:00
parent 704d4c34be
commit efb5ba5a95
7 changed files with 173 additions and 217 deletions

View File

@@ -0,0 +1,66 @@
/*
* Copyright 2002-2016 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.reactive.resource;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.util.StringUtils;
/**
* Abstract base class for filename suffix based {@link VersionStrategy}
* implementations, e.g. "static/myresource-version.js"
*
* @author Rossen Stoyanchev
* @author Brian Clozel
* @since 5.0
*/
public abstract class AbstractFileNameVersionStrategy implements VersionStrategy {
protected final Log logger = LogFactory.getLog(getClass());
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);
}
}

View File

@@ -0,0 +1,74 @@
/*
* Copyright 2002-2016 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.reactive.resource;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.util.Assert;
/**
* Abstract base class for {@link VersionStrategy} implementations that insert
* a prefix into the URL path, e.g. "version/static/myresource.js".
*
* @author Rossen Stoyanchev
* @author Brian Clozel
* @since 5.0
*/
public abstract class AbstractPrefixVersionStrategy implements VersionStrategy {
protected final Log logger = LogFactory.getLog(getClass());
private final String prefix;
protected AbstractPrefixVersionStrategy(String version) {
Assert.hasText(version, "'version' must not be empty");
this.prefix = version;
}
public String getPrefix() {
return this.prefix;
}
@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) {
if (path.startsWith(".")) {
return path;
}
else if (this.prefix.endsWith("/") || path.startsWith("/")) {
return this.prefix + path;
}
else {
return this.prefix + '/' + path;
}
}
}

View File

@@ -1,147 +0,0 @@
/*
* Copyright 2002-2016 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.reactive.resource;
import java.util.regex.Matcher;
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;
/**
* Abstract base class for {@link VersionStrategy} implementations.
*
* <p>Supports versions as:
* <ul>
* <li>prefix in the request path, like "version/static/myresource.js"
* <li>file name suffix in the request path, like "static/myresource-version.js"
* </ul>
*
* <p>Note: This base class does <i>not</i> provide support for generating the
* version string.
*
* @author Rossen Stoyanchev
* @author Brian Clozel
* @since 5.0
*/
public abstract class AbstractVersionStrategy implements VersionStrategy {
protected final Log logger = LogFactory.getLog(getClass());
private final VersionPathStrategy pathStrategy;
protected AbstractVersionStrategy(VersionPathStrategy pathStrategy) {
Assert.notNull(pathStrategy, "VersionPathStrategy is required");
this.pathStrategy = pathStrategy;
}
public VersionPathStrategy getVersionPathStrategy() {
return this.pathStrategy;
}
@Override
public String extractVersion(String requestPath) {
return this.pathStrategy.extractVersion(requestPath);
}
@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);
}
/**
* A prefix-based {@code VersionPathStrategy},
* e.g. {@code "{version}/path/foo.js"}.
*/
protected static class PrefixVersionPathStrategy implements VersionPathStrategy {
private final String prefix;
public PrefixVersionPathStrategy(String version) {
Assert.hasText(version, "'version' 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) {
if (path.startsWith(".")) {
return path;
}
else {
return (this.prefix.endsWith("/") || path.startsWith("/") ?
this.prefix + path : this.prefix + '/' + path);
}
}
}
/**
* File name-based {@code VersionPathStrategy},
* e.g. {@code "path/foo-{version}.css"}.
*/
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);
}
}
}

View File

@@ -31,12 +31,7 @@ import org.springframework.util.DigestUtils;
* @since 5.0
* @see VersionResourceResolver
*/
public class ContentVersionStrategy extends AbstractVersionStrategy {
public ContentVersionStrategy() {
super(new FileNameVersionPathStrategy());
}
public class ContentVersionStrategy extends AbstractFileNameVersionStrategy {
@Override

View File

@@ -31,9 +31,7 @@ import org.springframework.core.io.Resource;
* @since 5.0
* @see VersionResourceResolver
*/
public class FixedVersionStrategy extends AbstractVersionStrategy {
private final String version;
public class FixedVersionStrategy extends AbstractPrefixVersionStrategy {
/**
@@ -41,14 +39,13 @@ public class FixedVersionStrategy extends AbstractVersionStrategy {
* @param version the fixed version string to use
*/
public FixedVersionStrategy(String version) {
super(new PrefixVersionPathStrategy(version));
this.version = version;
super(version);
}
@Override
public String getResourceVersion(Resource resource) {
return this.version;
return getPrefix();
}
}

View File

@@ -1,55 +0,0 @@
/*
* Copyright 2002-2016 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.reactive.resource;
import org.springframework.lang.Nullable;
/**
* A strategy for extracting and embedding a resource version in its URL path.
*
* @author Rossen Stoyanchev
* @author Brian Clozel
* @since 5.0
*/
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
*/
@Nullable
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);
}

View File

@@ -17,17 +17,43 @@
package org.springframework.web.reactive.resource;
import org.springframework.core.io.Resource;
import org.springframework.lang.Nullable;
/**
* An extension of {@link VersionPathStrategy} that adds a method
* to determine the actual version of a {@link Resource}.
* A strategy to determine the version of a static resource and to apply and/or
* extract it from the URL path.
*
* @author Rossen Stoyanchev
* @author Brian Clozel
* @since 5.0
* @see VersionResourceResolver
*/
public interface VersionStrategy extends VersionPathStrategy {
public interface VersionStrategy {
/**
* 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
*/
@Nullable
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);
/**
* Determine the version for the given resource.