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