001/* 002 * Copyright 2002-2016 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.web.servlet.resource; 018 019import java.util.regex.Matcher; 020import java.util.regex.Pattern; 021 022import org.apache.commons.logging.Log; 023import org.apache.commons.logging.LogFactory; 024 025import org.springframework.util.Assert; 026import org.springframework.util.StringUtils; 027 028/** 029 * Abstract base class for {@link VersionStrategy} implementations. 030 * 031 * <p>Supports versions as: 032 * <ul> 033 * <li>prefix in the request path, like "version/static/myresource.js" 034 * <li>file name suffix in the request path, like "static/myresource-version.js" 035 * </ul> 036 * 037 * <p>Note: This base class does <i>not</i> provide support for generating the 038 * version string. 039 * 040 * @author Brian Clozel 041 * @author Rossen Stoyanchev 042 * @since 4.1 043 */ 044public abstract class AbstractVersionStrategy implements VersionStrategy { 045 046 protected final Log logger = LogFactory.getLog(getClass()); 047 048 private final VersionPathStrategy pathStrategy; 049 050 051 protected AbstractVersionStrategy(VersionPathStrategy pathStrategy) { 052 Assert.notNull(pathStrategy, "VersionPathStrategy is required"); 053 this.pathStrategy = pathStrategy; 054 } 055 056 057 public VersionPathStrategy getVersionPathStrategy() { 058 return this.pathStrategy; 059 } 060 061 062 @Override 063 public String extractVersion(String requestPath) { 064 return this.pathStrategy.extractVersion(requestPath); 065 } 066 067 @Override 068 public String removeVersion(String requestPath, String version) { 069 return this.pathStrategy.removeVersion(requestPath, version); 070 } 071 072 @Override 073 public String addVersion(String requestPath, String version) { 074 return this.pathStrategy.addVersion(requestPath, version); 075 } 076 077 078 /** 079 * A prefix-based {@code VersionPathStrategy}, 080 * e.g. {@code "{version}/path/foo.js"}. 081 */ 082 protected static class PrefixVersionPathStrategy implements VersionPathStrategy { 083 084 private final String prefix; 085 086 public PrefixVersionPathStrategy(String version) { 087 Assert.hasText(version, "'version' must not be empty"); 088 this.prefix = version; 089 } 090 091 @Override 092 public String extractVersion(String requestPath) { 093 return (requestPath.startsWith(this.prefix) ? this.prefix : null); 094 } 095 096 @Override 097 public String removeVersion(String requestPath, String version) { 098 return requestPath.substring(this.prefix.length()); 099 } 100 101 @Override 102 public String addVersion(String path, String version) { 103 if (path.startsWith(".")) { 104 return path; 105 } 106 else { 107 return (this.prefix.endsWith("/") || path.startsWith("/") ? 108 this.prefix + path : this.prefix + '/' + path); 109 } 110 } 111 } 112 113 114 /** 115 * File name-based {@code VersionPathStrategy}, 116 * e.g. {@code "path/foo-{version}.css"}. 117 */ 118 protected static class FileNameVersionPathStrategy implements VersionPathStrategy { 119 120 private static final Pattern pattern = Pattern.compile("-(\\S*)\\."); 121 122 @Override 123 public String extractVersion(String requestPath) { 124 Matcher matcher = pattern.matcher(requestPath); 125 if (matcher.find()) { 126 String match = matcher.group(1); 127 return (match.contains("-") ? match.substring(match.lastIndexOf('-') + 1) : match); 128 } 129 else { 130 return null; 131 } 132 } 133 134 @Override 135 public String removeVersion(String requestPath, String version) { 136 return StringUtils.delete(requestPath, "-" + version); 137 } 138 139 @Override 140 public String addVersion(String requestPath, String version) { 141 String baseFilename = StringUtils.stripFilenameExtension(requestPath); 142 String extension = StringUtils.getFilenameExtension(requestPath); 143 return (baseFilename + '-' + version + '.' + extension); 144 } 145 } 146 147}