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.config.annotation; 018 019import java.util.ArrayList; 020import java.util.List; 021 022import org.springframework.cache.Cache; 023import org.springframework.cache.concurrent.ConcurrentMapCache; 024import org.springframework.util.Assert; 025import org.springframework.util.ClassUtils; 026import org.springframework.web.servlet.resource.CachingResourceResolver; 027import org.springframework.web.servlet.resource.CachingResourceTransformer; 028import org.springframework.web.servlet.resource.CssLinkResourceTransformer; 029import org.springframework.web.servlet.resource.PathResourceResolver; 030import org.springframework.web.servlet.resource.ResourceResolver; 031import org.springframework.web.servlet.resource.ResourceTransformer; 032import org.springframework.web.servlet.resource.VersionResourceResolver; 033import org.springframework.web.servlet.resource.WebJarsResourceResolver; 034 035/** 036 * Assists with the registration of resource resolvers and transformers. 037 * 038 * @author Rossen Stoyanchev 039 * @since 4.1 040 */ 041public class ResourceChainRegistration { 042 043 private static final String DEFAULT_CACHE_NAME = "spring-resource-chain-cache"; 044 045 private static final boolean isWebJarsAssetLocatorPresent = ClassUtils.isPresent( 046 "org.webjars.WebJarAssetLocator", ResourceChainRegistration.class.getClassLoader()); 047 048 049 private final List<ResourceResolver> resolvers = new ArrayList<ResourceResolver>(4); 050 051 private final List<ResourceTransformer> transformers = new ArrayList<ResourceTransformer>(4); 052 053 private boolean hasVersionResolver; 054 055 private boolean hasPathResolver; 056 057 private boolean hasCssLinkTransformer; 058 059 private boolean hasWebjarsResolver; 060 061 062 public ResourceChainRegistration(boolean cacheResources) { 063 this(cacheResources, cacheResources ? new ConcurrentMapCache(DEFAULT_CACHE_NAME) : null); 064 } 065 066 public ResourceChainRegistration(boolean cacheResources, Cache cache) { 067 Assert.isTrue(!cacheResources || cache != null, "'cache' is required when cacheResources=true"); 068 if (cacheResources) { 069 this.resolvers.add(new CachingResourceResolver(cache)); 070 this.transformers.add(new CachingResourceTransformer(cache)); 071 } 072 } 073 074 075 /** 076 * Add a resource resolver to the chain. 077 * @param resolver the resolver to add 078 * @return the current instance for chained method invocation 079 */ 080 public ResourceChainRegistration addResolver(ResourceResolver resolver) { 081 Assert.notNull(resolver, "The provided ResourceResolver should not be null"); 082 this.resolvers.add(resolver); 083 if (resolver instanceof VersionResourceResolver) { 084 this.hasVersionResolver = true; 085 } 086 else if (resolver instanceof PathResourceResolver) { 087 this.hasPathResolver = true; 088 } 089 else if (resolver instanceof WebJarsResourceResolver) { 090 this.hasWebjarsResolver = true; 091 } 092 return this; 093 } 094 095 /** 096 * Add a resource transformer to the chain. 097 * @param transformer the transformer to add 098 * @return the current instance for chained method invocation 099 */ 100 public ResourceChainRegistration addTransformer(ResourceTransformer transformer) { 101 Assert.notNull(transformer, "The provided ResourceTransformer should not be null"); 102 this.transformers.add(transformer); 103 if (transformer instanceof CssLinkResourceTransformer) { 104 this.hasCssLinkTransformer = true; 105 } 106 return this; 107 } 108 109 protected List<ResourceResolver> getResourceResolvers() { 110 if (!this.hasPathResolver) { 111 List<ResourceResolver> result = new ArrayList<ResourceResolver>(this.resolvers); 112 if (isWebJarsAssetLocatorPresent && !this.hasWebjarsResolver) { 113 result.add(new WebJarsResourceResolver()); 114 } 115 result.add(new PathResourceResolver()); 116 return result; 117 } 118 return this.resolvers; 119 } 120 121 protected List<ResourceTransformer> getResourceTransformers() { 122 if (this.hasVersionResolver && !this.hasCssLinkTransformer) { 123 List<ResourceTransformer> result = new ArrayList<ResourceTransformer>(this.transformers); 124 boolean hasTransformers = !this.transformers.isEmpty(); 125 boolean hasCaching = hasTransformers && this.transformers.get(0) instanceof CachingResourceTransformer; 126 result.add(hasCaching ? 1 : 0, new CssLinkResourceTransformer()); 127 return result; 128 } 129 return this.transformers; 130 } 131 132}