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