Update resource handler XML Namespace
This change introduces a new <mvc:resource-chain/> tag that mirrors
the ResourceChainRegistration java config counterpart.
Resolvers and Transformers can be registered with bean/ref tags, and
specific tags have been created for <mvc:version-resovlver> and
<mvc:resource-cache> in order to make common configurations easier.
Note that a specific "auto-configuration" attribute on the
resource-chain allows to completely disable default registration of
Resolvers and Transformers (sane defaults considered by the Framework).
<mvc:resources mapping="/resources/**" location="/, classpath:/META-INF/">
<mvc:resource-chain>
<mvc:resource-cache cache="resourceCache"/>
<mvc:resolvers>
<mvc:version-resolver>
<mvc:fixed-version-strategy version="abc" patterns="/**/*.js"/>
<mvc:content-version-strategy patterns="/**"/>
</mvc:version-resolver>
</mvc:resolvers>
<mvc:transformers>
<bean class="org.springframework.web.servlet.resource.AppCacheManifestTransformer"/>
</mvc:transformers>
</mvc:resource-chain>
</mvc:resources>
This also fixes a typo in the class name of
AppCacheManifestResourceTransfo*r*mer.
Issue: SPR-12129
This commit is contained in:
@@ -22,6 +22,7 @@ import java.util.Map;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.ConstructorArgumentValues;
|
||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
|
||||
import org.springframework.beans.factory.support.ManagedList;
|
||||
@@ -29,25 +30,43 @@ import org.springframework.beans.factory.support.ManagedMap;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.beans.factory.xml.BeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.cache.concurrent.ConcurrentMapCache;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.util.xml.DomUtils;
|
||||
import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping;
|
||||
import org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter;
|
||||
import org.springframework.web.servlet.resource.CachingResourceResolver;
|
||||
import org.springframework.web.servlet.resource.CachingResourceTransformer;
|
||||
import org.springframework.web.servlet.resource.ContentVersionStrategy;
|
||||
import org.springframework.web.servlet.resource.CssLinkResourceTransformer;
|
||||
import org.springframework.web.servlet.resource.FixedVersionStrategy;
|
||||
import org.springframework.web.servlet.resource.PathResourceResolver;
|
||||
import org.springframework.web.servlet.resource.ResourceHttpRequestHandler;
|
||||
import org.springframework.web.servlet.resource.ResourceResolver;
|
||||
import org.springframework.web.servlet.resource.ResourceTransformer;
|
||||
import org.springframework.web.servlet.resource.VersionResourceResolver;
|
||||
|
||||
/**
|
||||
* {@link org.springframework.beans.factory.xml.BeanDefinitionParser} that parses a
|
||||
* {@code resources} element to register a {@link ResourceHttpRequestHandler}.
|
||||
* Will also register a {@link SimpleUrlHandlerMapping} for mapping resource requests,
|
||||
* {@code resources} element to register a {@link ResourceHttpRequestHandler} and
|
||||
* register a {@link SimpleUrlHandlerMapping} for mapping resource requests,
|
||||
* and a {@link HttpRequestHandlerAdapter}.
|
||||
* Will also create a resource handling chain with {@link ResourceResolver}s and {@link ResourceTransformer}s.
|
||||
*
|
||||
* @author Keith Donald
|
||||
* @author Jeremy Grelle
|
||||
* @author Brian Clozel
|
||||
* @since 3.0.4
|
||||
*/
|
||||
class ResourcesBeanDefinitionParser implements BeanDefinitionParser {
|
||||
|
||||
private static final String RESOURCE_CHAIN_CACHE = "spring-resource-chain-cache";
|
||||
private static final String VERSION_RESOLVER_ELEMENT = "version-resolver";
|
||||
private static final String VERSION_STRATEGY_ELEMENT = "version-strategy";
|
||||
private static final String FIXED_VERSION_STRATEGY_ELEMENT = "fixed-version-strategy";
|
||||
private static final String CONTENT_VERSION_STRATEGY_ELEMENT = "content-version-strategy";
|
||||
|
||||
@Override
|
||||
public BeanDefinition parse(Element element, ParserContext parserContext) {
|
||||
Object source = parserContext.extractSource(element);
|
||||
@@ -109,14 +128,9 @@ class ResourcesBeanDefinitionParser implements BeanDefinitionParser {
|
||||
resourceHandlerDef.getPropertyValues().add("cacheSeconds", cacheSeconds);
|
||||
}
|
||||
|
||||
ManagedList<? super Object> resourceResolvers = parseResourceResolvers(parserContext, element, source);
|
||||
if (!resourceResolvers.isEmpty()) {
|
||||
resourceHandlerDef.getPropertyValues().add("resourceResolvers", resourceResolvers);
|
||||
}
|
||||
|
||||
ManagedList<? super Object> resourceTransformers = parseResourceTransformers(parserContext, element, source);
|
||||
if (!resourceTransformers.isEmpty()) {
|
||||
resourceHandlerDef.getPropertyValues().add("resourceTransformers", resourceTransformers);
|
||||
Element resourceChainElement = DomUtils.getChildElementByTagName(element, "resource-chain");
|
||||
if(resourceChainElement != null) {
|
||||
parseResourceChain(resourceHandlerDef, parserContext, resourceChainElement, source);
|
||||
}
|
||||
|
||||
String beanName = parserContext.getReaderContext().generateBeanName(resourceHandlerDef);
|
||||
@@ -125,30 +139,145 @@ class ResourcesBeanDefinitionParser implements BeanDefinitionParser {
|
||||
return beanName;
|
||||
}
|
||||
|
||||
private ManagedList<? super Object> parseResourceResolvers(ParserContext parserContext, Element element, Object source) {
|
||||
Element resolversElement = DomUtils.getChildElementByTagName(element, "resolvers");
|
||||
|
||||
private void parseResourceChain(RootBeanDefinition resourceHandlerDef, ParserContext parserContext,
|
||||
Element element, Object source) {
|
||||
|
||||
String autoRegistration = element.getAttribute("auto-registration");
|
||||
boolean isAutoRegistration = !(StringUtils.hasText(autoRegistration) && "false".equals(autoRegistration));
|
||||
|
||||
ManagedList<? super Object> resourceResolvers = new ManagedList<Object>();
|
||||
if (resolversElement != null) {
|
||||
resourceResolvers.setSource(source);
|
||||
for (Element beanElement : DomUtils.getChildElementsByTagName(resolversElement, "bean", "ref")) {
|
||||
Object object = parserContext.getDelegate().parsePropertySubElement(beanElement, null);
|
||||
resourceResolvers.add(object);
|
||||
}
|
||||
resourceResolvers.setSource(source);
|
||||
ManagedList<? super Object> resourceTransformers = new ManagedList<Object>();
|
||||
resourceTransformers.setSource(source);
|
||||
|
||||
parseResourceCache(resourceResolvers, resourceTransformers, element, source);
|
||||
parseResourceResolversTransformers(isAutoRegistration, resourceResolvers
|
||||
, resourceTransformers, parserContext, element, source);
|
||||
|
||||
if (!resourceResolvers.isEmpty()) {
|
||||
resourceHandlerDef.getPropertyValues().add("resourceResolvers", resourceResolvers);
|
||||
}
|
||||
if (!resourceTransformers.isEmpty()) {
|
||||
resourceHandlerDef.getPropertyValues().add("resourceTransformers", resourceTransformers);
|
||||
}
|
||||
return resourceResolvers;
|
||||
}
|
||||
|
||||
private ManagedList<? super Object> parseResourceTransformers(ParserContext parserContext, Element element, Object source) {
|
||||
private void parseResourceCache(ManagedList<? super Object> resourceResolvers,
|
||||
ManagedList<? super Object> resourceTransformers,
|
||||
Element element, Object source) {
|
||||
|
||||
Element resourceCacheElement = DomUtils.getChildElementByTagName(element, "resource-cache");
|
||||
if(resourceCacheElement != null) {
|
||||
ConstructorArgumentValues cavs = new ConstructorArgumentValues();
|
||||
|
||||
RootBeanDefinition cachingResolverDef = new RootBeanDefinition(CachingResourceResolver.class);
|
||||
cachingResolverDef.setSource(source);
|
||||
cachingResolverDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
cachingResolverDef.setConstructorArgumentValues(cavs);
|
||||
|
||||
RootBeanDefinition cachingTransformerDef = new RootBeanDefinition(CachingResourceTransformer.class);
|
||||
cachingTransformerDef.setSource(source);
|
||||
cachingTransformerDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
cachingTransformerDef.setConstructorArgumentValues(cavs);
|
||||
|
||||
String cacheBeanName = resourceCacheElement.getAttribute("cache");
|
||||
if (StringUtils.hasText(cacheBeanName)) {
|
||||
RuntimeBeanReference cacheRef = new RuntimeBeanReference(cacheBeanName);
|
||||
cavs.addIndexedArgumentValue(0, cacheRef);
|
||||
}
|
||||
else {
|
||||
ConstructorArgumentValues cacheCavs = new ConstructorArgumentValues();
|
||||
cacheCavs.addIndexedArgumentValue(0, RESOURCE_CHAIN_CACHE);
|
||||
|
||||
RootBeanDefinition cacheDef = new RootBeanDefinition(ConcurrentMapCache.class);
|
||||
cacheDef.setSource(source);
|
||||
cacheDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
cacheDef.setConstructorArgumentValues(cacheCavs);
|
||||
cavs.addIndexedArgumentValue(0, cacheDef);
|
||||
}
|
||||
resourceResolvers.add(cachingResolverDef);
|
||||
resourceTransformers.add(cachingTransformerDef);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void parseResourceResolversTransformers(boolean isAutoRegistration,
|
||||
ManagedList<? super Object> resourceResolvers, ManagedList<? super Object> resourceTransformers,
|
||||
ParserContext parserContext, Element element, Object source) {
|
||||
|
||||
Element resolversElement = DomUtils.getChildElementByTagName(element, "resolvers");
|
||||
if (resolversElement != null) {
|
||||
for (Element beanElement : DomUtils.getChildElements(resolversElement)) {
|
||||
if(VERSION_RESOLVER_ELEMENT.equals(beanElement.getLocalName())) {
|
||||
RootBeanDefinition versionResolverDef = parseVersionResolver(parserContext, beanElement, source);
|
||||
versionResolverDef.setSource(source);
|
||||
resourceResolvers.add(versionResolverDef);
|
||||
|
||||
if(isAutoRegistration) {
|
||||
RootBeanDefinition cssLinkTransformerDef = new RootBeanDefinition(CssLinkResourceTransformer.class);
|
||||
cssLinkTransformerDef.setSource(source);
|
||||
cssLinkTransformerDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
resourceTransformers.add(cssLinkTransformerDef);
|
||||
}
|
||||
} else {
|
||||
Object object = parserContext.getDelegate().parsePropertySubElement(beanElement, null);
|
||||
resourceResolvers.add(object);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(isAutoRegistration) {
|
||||
RootBeanDefinition pathResolverDef = new RootBeanDefinition(PathResourceResolver.class);
|
||||
pathResolverDef.setSource(source);
|
||||
pathResolverDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
resourceResolvers.add(pathResolverDef);
|
||||
}
|
||||
|
||||
Element transformersElement = DomUtils.getChildElementByTagName(element, "transformers");
|
||||
ManagedList<? super Object> resourceTransformers = new ManagedList<Object>();
|
||||
if (transformersElement != null) {
|
||||
resourceTransformers.setSource(source);
|
||||
for (Element beanElement : DomUtils.getChildElementsByTagName(transformersElement, "bean", "ref")) {
|
||||
Object object = parserContext.getDelegate().parsePropertySubElement(beanElement, null);
|
||||
resourceTransformers.add(object);
|
||||
}
|
||||
}
|
||||
return resourceTransformers;
|
||||
}
|
||||
|
||||
private RootBeanDefinition parseVersionResolver(ParserContext parserContext, Element element, Object source) {
|
||||
ManagedMap<String, ? super Object> strategyMap = new ManagedMap<String, Object>();
|
||||
strategyMap.setSource(source);
|
||||
RootBeanDefinition versionResolverDef = new RootBeanDefinition(VersionResourceResolver.class);
|
||||
versionResolverDef.setSource(source);
|
||||
versionResolverDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
versionResolverDef.getPropertyValues().addPropertyValue("strategyMap", strategyMap);
|
||||
|
||||
for (Element beanElement : DomUtils.getChildElements(element)) {
|
||||
String[] patterns = StringUtils.commaDelimitedListToStringArray(beanElement.getAttribute("patterns"));
|
||||
Object strategy = null;
|
||||
if(FIXED_VERSION_STRATEGY_ELEMENT.equals(beanElement.getLocalName())) {
|
||||
ConstructorArgumentValues cavs = new ConstructorArgumentValues();
|
||||
cavs.addIndexedArgumentValue(0, beanElement.getAttribute("version"));
|
||||
RootBeanDefinition strategyDef = new RootBeanDefinition(FixedVersionStrategy.class);
|
||||
strategyDef.setSource(source);
|
||||
strategyDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
strategyDef.setConstructorArgumentValues(cavs);
|
||||
strategy = strategyDef;
|
||||
}
|
||||
else if (CONTENT_VERSION_STRATEGY_ELEMENT.equals(beanElement.getLocalName())) {
|
||||
RootBeanDefinition strategyDef = new RootBeanDefinition(ContentVersionStrategy.class);
|
||||
strategyDef.setSource(source);
|
||||
strategyDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
strategy = strategyDef;
|
||||
}
|
||||
else if (VERSION_STRATEGY_ELEMENT.equals(beanElement.getLocalName())) {
|
||||
Element childElement = DomUtils.getChildElementsByTagName(beanElement, "bean", "ref").get(0);
|
||||
strategy = parserContext.getDelegate().parsePropertySubElement(childElement, null);
|
||||
}
|
||||
for(String pattern : patterns) {
|
||||
strategyMap.put(pattern, strategy);
|
||||
}
|
||||
}
|
||||
|
||||
return versionResolverDef;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,13 +58,13 @@ import org.springframework.util.StringUtils;
|
||||
* applications spec</a>
|
||||
* @since 4.1
|
||||
*/
|
||||
public class AppCacheManifestTransfomer implements ResourceTransformer {
|
||||
public class AppCacheManifestTransformer implements ResourceTransformer {
|
||||
|
||||
private static final String MANIFEST_HEADER = "CACHE MANIFEST";
|
||||
|
||||
private static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
|
||||
|
||||
private static final Log logger = LogFactory.getLog(AppCacheManifestTransfomer.class);
|
||||
private static final Log logger = LogFactory.getLog(AppCacheManifestTransformer.class);
|
||||
|
||||
private final Map<String, SectionTransformer> sectionTransformers = new HashMap<String, SectionTransformer>();
|
||||
|
||||
@@ -74,7 +74,7 @@ public class AppCacheManifestTransfomer implements ResourceTransformer {
|
||||
/**
|
||||
* Create an AppCacheResourceTransformer that transforms files with extension ".manifest"
|
||||
*/
|
||||
public AppCacheManifestTransfomer() {
|
||||
public AppCacheManifestTransformer() {
|
||||
this("manifest");
|
||||
}
|
||||
|
||||
@@ -82,7 +82,7 @@ public class AppCacheManifestTransfomer implements ResourceTransformer {
|
||||
* Create an AppCacheResourceTransformer that transforms files with the extension
|
||||
* given as a parameter.
|
||||
*/
|
||||
public AppCacheManifestTransfomer(String fileExtension) {
|
||||
public AppCacheManifestTransformer(String fileExtension) {
|
||||
this.fileExtension = fileExtension;
|
||||
|
||||
SectionTransformer noOpSection = new NoOpSection();
|
||||
Reference in New Issue
Block a user