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.reactive.config;
018
019import java.util.ArrayList;
020import java.util.Arrays;
021import java.util.List;
022
023import org.springframework.cache.Cache;
024import org.springframework.core.io.Resource;
025import org.springframework.core.io.ResourceLoader;
026import org.springframework.http.CacheControl;
027import org.springframework.lang.Nullable;
028import org.springframework.util.Assert;
029import org.springframework.web.reactive.resource.ResourceWebHandler;
030
031/**
032 * Assist with creating and configuring a static resources handler.
033 *
034 * @author Rossen Stoyanchev
035 * @since 5.0
036 */
037public class ResourceHandlerRegistration {
038
039        private final ResourceLoader resourceLoader;
040
041        private final String[] pathPatterns;
042
043        private final List<String> locationValues = new ArrayList<>();
044
045        @Nullable
046        private CacheControl cacheControl;
047
048        @Nullable
049        private ResourceChainRegistration resourceChainRegistration;
050
051
052        /**
053         * Create a {@link ResourceHandlerRegistration} instance.
054         * @param resourceLoader a resource loader for turning a String location
055         * into a {@link Resource}
056         * @param pathPatterns one or more resource URL path patterns
057         */
058        public ResourceHandlerRegistration(ResourceLoader resourceLoader, String... pathPatterns) {
059                Assert.notNull(resourceLoader, "ResourceLoader is required");
060                Assert.notEmpty(pathPatterns, "At least one path pattern is required for resource handling");
061                this.resourceLoader = resourceLoader;
062                this.pathPatterns = pathPatterns;
063        }
064
065
066        /**
067         * Add one or more resource locations from which to serve static content.
068         * Each location must point to a valid directory. Multiple locations may
069         * be specified as a comma-separated list, and the locations will be checked
070         * for a given resource in the order specified.
071         *
072         * <p>For example, {{@code "/"},
073         * {@code "classpath:/META-INF/public-web-resources/"}} allows resources to
074         * be served both from the web application root and from any JAR on the
075         * classpath that contains a {@code /META-INF/public-web-resources/} directory,
076         * with resources in the web application root taking precedence.
077         * @return the same {@link ResourceHandlerRegistration} instance, for
078         * chained method invocation
079         */
080        public ResourceHandlerRegistration addResourceLocations(String... resourceLocations) {
081                this.locationValues.addAll(Arrays.asList(resourceLocations));
082                return this;
083        }
084
085        /**
086         * Specify the {@link CacheControl} which should be used
087         * by the resource handler.
088         * @param cacheControl the CacheControl configuration to use
089         * @return the same {@link ResourceHandlerRegistration} instance, for
090         * chained method invocation
091         */
092        public ResourceHandlerRegistration setCacheControl(CacheControl cacheControl) {
093                this.cacheControl = cacheControl;
094                return this;
095        }
096
097        /**
098         * Configure a chain of resource resolvers and transformers to use. This
099         * can be useful, for example, to apply a version strategy to resource URLs.
100         * <p>If this method is not invoked, by default only a simple
101         * {@code PathResourceResolver} is used in order to match URL paths to
102         * resources under the configured locations.
103         * @param cacheResources whether to cache the result of resource resolution;
104         * setting this to "true" is recommended for production (and "false" for
105         * development, especially when applying a version strategy)
106         * @return the same {@link ResourceHandlerRegistration} instance, for
107         * chained method invocation
108         */
109        public ResourceChainRegistration resourceChain(boolean cacheResources) {
110                this.resourceChainRegistration = new ResourceChainRegistration(cacheResources);
111                return this.resourceChainRegistration;
112        }
113
114        /**
115         * Configure a chain of resource resolvers and transformers to use. This
116         * can be useful, for example, to apply a version strategy to resource URLs.
117         * <p>If this method is not invoked, by default only a simple
118         * {@code PathResourceResolver} is used in order to match URL paths to
119         * resources under the configured locations.
120         * @param cacheResources whether to cache the result of resource resolution;
121         * setting this to "true" is recommended for production (and "false" for
122         * development, especially when applying a version strategy
123         * @param cache the cache to use for storing resolved and transformed resources;
124         * by default a {@link org.springframework.cache.concurrent.ConcurrentMapCache}
125         * is used. Since Resources aren't serializable and can be dependent on the
126         * application host, one should not use a distributed cache but rather an
127         * in-memory cache.
128         * @return the same {@link ResourceHandlerRegistration} instance, for chained method invocation
129         */
130        public ResourceChainRegistration resourceChain(boolean cacheResources, Cache cache) {
131                this.resourceChainRegistration = new ResourceChainRegistration(cacheResources, cache);
132                return this.resourceChainRegistration;
133        }
134
135        /**
136         * Returns the URL path patterns for the resource handler.
137         */
138        protected String[] getPathPatterns() {
139                return this.pathPatterns;
140        }
141
142        /**
143         * Returns a {@link ResourceWebHandler} instance.
144         */
145        protected ResourceWebHandler getRequestHandler() {
146                ResourceWebHandler handler = new ResourceWebHandler();
147                handler.setLocationValues(this.locationValues);
148                handler.setResourceLoader(this.resourceLoader);
149                if (this.resourceChainRegistration != null) {
150                        handler.setResourceResolvers(this.resourceChainRegistration.getResourceResolvers());
151                        handler.setResourceTransformers(this.resourceChainRegistration.getResourceTransformers());
152                }
153                if (this.cacheControl != null) {
154                        handler.setCacheControl(this.cacheControl);
155                }
156                return handler;
157        }
158
159}