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.Arrays;
021import java.util.List;
022
023import org.springframework.cache.Cache;
024import org.springframework.http.CacheControl;
025import org.springframework.lang.Nullable;
026import org.springframework.util.Assert;
027import org.springframework.web.servlet.resource.PathResourceResolver;
028import org.springframework.web.servlet.resource.ResourceHttpRequestHandler;
029
030/**
031 * Encapsulates information required to create a resource handler.
032 *
033 * @author Rossen Stoyanchev
034 * @author Keith Donald
035 * @author Brian Clozel
036 * @since 3.1
037 */
038public class ResourceHandlerRegistration {
039
040        private final String[] pathPatterns;
041
042        private final List<String> locationValues = new ArrayList<>();
043
044        @Nullable
045        private Integer cachePeriod;
046
047        @Nullable
048        private CacheControl cacheControl;
049
050        @Nullable
051        private ResourceChainRegistration resourceChainRegistration;
052
053
054        /**
055         * Create a {@link ResourceHandlerRegistration} instance.
056         * @param pathPatterns one or more resource URL path patterns
057         */
058        public ResourceHandlerRegistration(String... pathPatterns) {
059                Assert.notEmpty(pathPatterns, "At least one path pattern is required for resource handling.");
060                this.pathPatterns = pathPatterns;
061        }
062
063
064        /**
065         * Add one or more resource locations from which to serve static content.
066         * Each location must point to a valid directory. Multiple locations may
067         * be specified as a comma-separated list, and the locations will be checked
068         * for a given resource in the order specified.
069         * <p>For example, {{@code "/"}, {@code "classpath:/META-INF/public-web-resources/"}}
070         * allows resources to be served both from the web application root and
071         * from any JAR on the classpath that contains a
072         * {@code /META-INF/public-web-resources/} directory, with resources in the
073         * web application root taking precedence.
074         * <p>For {@link org.springframework.core.io.UrlResource URL-based resources}
075         * (e.g. files, HTTP URLs, etc) this method supports a special prefix to
076         * indicate the charset associated with the URL so that relative paths
077         * appended to it can be encoded correctly, e.g.
078         * {@code [charset=Windows-31J]https://example.org/path}.
079         * @return the same {@link ResourceHandlerRegistration} instance, for
080         * chained method invocation
081         */
082        public ResourceHandlerRegistration addResourceLocations(String... resourceLocations) {
083                this.locationValues.addAll(Arrays.asList(resourceLocations));
084                return this;
085        }
086
087        /**
088         * Specify the cache period for the resources served by the resource handler, in seconds. The default is to not
089         * send any cache headers but to rely on last-modified timestamps only. Set to 0 in order to send cache headers
090         * that prevent caching, or to a positive number of seconds to send cache headers with the given max-age value.
091         * @param cachePeriod the time to cache resources in seconds
092         * @return the same {@link ResourceHandlerRegistration} instance, for chained method invocation
093         */
094        public ResourceHandlerRegistration setCachePeriod(Integer cachePeriod) {
095                this.cachePeriod = cachePeriod;
096                return this;
097        }
098
099        /**
100         * Specify the {@link org.springframework.http.CacheControl} which should be used
101         * by the resource handler.
102         * <p>Setting a custom value here will override the configuration set with {@link #setCachePeriod}.
103         * @param cacheControl the CacheControl configuration to use
104         * @return the same {@link ResourceHandlerRegistration} instance, for chained method invocation
105         * @since 4.2
106         */
107        public ResourceHandlerRegistration setCacheControl(CacheControl cacheControl) {
108                this.cacheControl = cacheControl;
109                return this;
110        }
111
112        /**
113         * Configure a chain of resource resolvers and transformers to use. This
114         * can be useful, for example, to apply a version strategy to resource URLs.
115         * <p>If this method is not invoked, by default only a simple
116         * {@link PathResourceResolver} is used in order to match URL paths to
117         * resources under the configured locations.
118         * @param cacheResources whether to cache the result of resource resolution;
119         * setting this to "true" is recommended for production (and "false" for
120         * development, especially when applying a version strategy)
121         * @return the same {@link ResourceHandlerRegistration} instance, for chained method invocation
122         * @since 4.1
123         */
124        public ResourceChainRegistration resourceChain(boolean cacheResources) {
125                this.resourceChainRegistration = new ResourceChainRegistration(cacheResources);
126                return this.resourceChainRegistration;
127        }
128
129        /**
130         * Configure a chain of resource resolvers and transformers to use. This
131         * can be useful, for example, to apply a version strategy to resource URLs.
132         * <p>If this method is not invoked, by default only a simple
133         * {@link PathResourceResolver} is used in order to match URL paths to
134         * resources under the configured locations.
135         * @param cacheResources whether to cache the result of resource resolution;
136         * setting this to "true" is recommended for production (and "false" for
137         * development, especially when applying a version strategy
138         * @param cache the cache to use for storing resolved and transformed resources;
139         * by default a {@link org.springframework.cache.concurrent.ConcurrentMapCache}
140         * is used. Since Resources aren't serializable and can be dependent on the
141         * application host, one should not use a distributed cache but rather an
142         * in-memory cache.
143         * @return the same {@link ResourceHandlerRegistration} instance, for chained method invocation
144         * @since 4.1
145         */
146        public ResourceChainRegistration resourceChain(boolean cacheResources, Cache cache) {
147                this.resourceChainRegistration = new ResourceChainRegistration(cacheResources, cache);
148                return this.resourceChainRegistration;
149        }
150
151
152        /**
153         * Return the URL path patterns for the resource handler.
154         */
155        protected String[] getPathPatterns() {
156                return this.pathPatterns;
157        }
158
159        /**
160         * Return a {@link ResourceHttpRequestHandler} instance.
161         */
162        protected ResourceHttpRequestHandler getRequestHandler() {
163                ResourceHttpRequestHandler handler = new ResourceHttpRequestHandler();
164                if (this.resourceChainRegistration != null) {
165                        handler.setResourceResolvers(this.resourceChainRegistration.getResourceResolvers());
166                        handler.setResourceTransformers(this.resourceChainRegistration.getResourceTransformers());
167                }
168                handler.setLocationValues(this.locationValues);
169                if (this.cacheControl != null) {
170                        handler.setCacheControl(this.cacheControl);
171                }
172                else if (this.cachePeriod != null) {
173                        handler.setCacheSeconds(this.cachePeriod);
174                }
175                return handler;
176        }
177
178}