001: /*
002: * Copyright 2002-2006 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: * http://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:
017: package org.springframework.web.servlet.mvc;
018:
019: import java.util.HashMap;
020: import java.util.Iterator;
021: import java.util.Map;
022: import java.util.Properties;
023:
024: import javax.servlet.ServletException;
025: import javax.servlet.http.HttpServletRequest;
026: import javax.servlet.http.HttpServletResponse;
027:
028: import org.springframework.util.AntPathMatcher;
029: import org.springframework.util.Assert;
030: import org.springframework.util.PathMatcher;
031: import org.springframework.web.servlet.HandlerInterceptor;
032: import org.springframework.web.servlet.ModelAndView;
033: import org.springframework.web.servlet.support.WebContentGenerator;
034: import org.springframework.web.util.UrlPathHelper;
035:
036: /**
037: * Interceptor that checks and prepares request and response. Checks for supported
038: * methods and a required session, and applies the specified number of cache seconds.
039: * See superclass bean properties for configuration options.
040: *
041: * <p>All the settings supported by this interceptor can also be set on AbstractController.
042: * This interceptor is mainly intended for applying checks and preparations to a set of
043: * controllers mapped by a HandlerMapping.
044: *
045: * @author Juergen Hoeller
046: * @since 27.11.2003
047: * @see AbstractController
048: */
049: public class WebContentInterceptor extends WebContentGenerator
050: implements HandlerInterceptor {
051:
052: private UrlPathHelper urlPathHelper = new UrlPathHelper();
053:
054: private Map cacheMappings = new HashMap();
055:
056: private PathMatcher pathMatcher = new AntPathMatcher();
057:
058: /**
059: * Set if URL lookup should always use full path within current servlet
060: * context. Else, the path within the current servlet mapping is used
061: * if applicable (i.e. in the case of a ".../*" servlet mapping in web.xml).
062: * Default is "false".
063: * <p>Only relevant for the "cacheMappings" setting.
064: * @see #setCacheMappings
065: * @see org.springframework.web.util.UrlPathHelper#setAlwaysUseFullPath
066: */
067: public void setAlwaysUseFullPath(boolean alwaysUseFullPath) {
068: this .urlPathHelper.setAlwaysUseFullPath(alwaysUseFullPath);
069: }
070:
071: /**
072: * Set if context path and request URI should be URL-decoded.
073: * Both are returned <i>undecoded</i> by the Servlet API,
074: * in contrast to the servlet path.
075: * <p>Uses either the request encoding or the default encoding according
076: * to the Servlet spec (ISO-8859-1).
077: * <p>Note: Setting this to "true" requires JDK 1.4 if the encoding differs
078: * from the VM's platform default encoding, as JDK 1.3's URLDecoder class
079: * does not offer a way to specify the encoding.
080: * <p>Only relevant for the "cacheMappings" setting.
081: * @see #setCacheMappings
082: * @see org.springframework.web.util.UrlPathHelper#setUrlDecode
083: */
084: public void setUrlDecode(boolean urlDecode) {
085: this .urlPathHelper.setUrlDecode(urlDecode);
086: }
087:
088: /**
089: * Set the UrlPathHelper to use for resolution of lookup paths.
090: * <p>Use this to override the default UrlPathHelper with a custom subclass,
091: * or to share common UrlPathHelper settings across multiple HandlerMappings
092: * and MethodNameResolvers.
093: * <p>Only relevant for the "cacheMappings" setting.
094: * @see #setCacheMappings
095: * @see org.springframework.web.servlet.handler.AbstractUrlHandlerMapping#setUrlPathHelper
096: * @see org.springframework.web.servlet.mvc.multiaction.AbstractUrlMethodNameResolver#setUrlPathHelper
097: */
098: public void setUrlPathHelper(UrlPathHelper urlPathHelper) {
099: this .urlPathHelper = urlPathHelper;
100: }
101:
102: /**
103: * Map specific URL paths to specific cache seconds.
104: * <p>Overrides the default cache seconds setting of this interceptor.
105: * Can specify "-1" to exclude a URL path from default caching.
106: * <p>Supports direct matches, e.g. a registered "/test" matches "/test",
107: * and a various Ant-style pattern matches, e.g. a registered "/t*" matches
108: * both "/test" and "/team". For details, see the AntPathMatcher javadoc.
109: * @param cacheMappings a mapping between URL paths (as keys) and
110: * cache seconds (as values, need to be integer-parsable)
111: * @see #setCacheSeconds
112: * @see org.springframework.util.AntPathMatcher
113: */
114: public void setCacheMappings(Properties cacheMappings) {
115: this .cacheMappings.clear();
116: for (Iterator it = cacheMappings.keySet().iterator(); it
117: .hasNext();) {
118: String path = (String) it.next();
119: this .cacheMappings.put(path, Integer.valueOf(cacheMappings
120: .getProperty(path)));
121: }
122: }
123:
124: /**
125: * Set the PathMatcher implementation to use for matching URL paths
126: * against registered URL patterns, for determining cache mappings.
127: * Default is AntPathMatcher.
128: * @see #setCacheMappings
129: * @see org.springframework.util.AntPathMatcher
130: */
131: public void setPathMatcher(PathMatcher pathMatcher) {
132: Assert.notNull(pathMatcher, "PathMatcher must not be null");
133: this .pathMatcher = pathMatcher;
134: }
135:
136: public boolean preHandle(HttpServletRequest request,
137: HttpServletResponse response, Object handler)
138: throws ServletException {
139:
140: String lookupPath = this .urlPathHelper
141: .getLookupPathForRequest(request);
142: if (logger.isDebugEnabled()) {
143: logger.debug("Looking up cache seconds for [" + lookupPath
144: + "]");
145: }
146:
147: Integer cacheSeconds = lookupCacheSeconds(lookupPath);
148: if (cacheSeconds != null) {
149: if (logger.isDebugEnabled()) {
150: logger.debug("Applying " + cacheSeconds
151: + " cache seconds to [" + lookupPath + "]");
152: }
153: checkAndPrepare(request, response, cacheSeconds.intValue(),
154: handler instanceof LastModified);
155: } else {
156: if (logger.isDebugEnabled()) {
157: logger.debug("Applying default cache seconds to ["
158: + lookupPath + "]");
159: }
160: checkAndPrepare(request, response,
161: handler instanceof LastModified);
162: }
163:
164: return true;
165: }
166:
167: /**
168: * Look up a cache seconds value for the given URL path.
169: * <p>Supports direct matches, e.g. a registered "/test" matches "/test",
170: * and various Ant-style pattern matches, e.g. a registered "/t*" matches
171: * both "/test" and "/team". For details, see the AntPathMatcher class.
172: * @param urlPath URL the bean is mapped to
173: * @return the associated cache seconds, or <code>null</code> if not found
174: * @see org.springframework.util.AntPathMatcher
175: */
176: protected Integer lookupCacheSeconds(String urlPath) {
177: // direct match?
178: Integer cacheSeconds = (Integer) this .cacheMappings
179: .get(urlPath);
180: if (cacheSeconds == null) {
181: // pattern match?
182: for (Iterator it = this .cacheMappings.keySet().iterator(); it
183: .hasNext();) {
184: String registeredPath = (String) it.next();
185: if (this .pathMatcher.match(registeredPath, urlPath)) {
186: cacheSeconds = (Integer) this .cacheMappings
187: .get(registeredPath);
188: }
189: }
190: }
191: return cacheSeconds;
192: }
193:
194: /**
195: * This implementation is empty.
196: */
197: public void postHandle(HttpServletRequest request,
198: HttpServletResponse response, Object handler,
199: ModelAndView modelAndView) throws Exception {
200: }
201:
202: /**
203: * This implementation is empty.
204: */
205: public void afterCompletion(HttpServletRequest request,
206: HttpServletResponse response, Object handler, Exception ex)
207: throws Exception {
208: }
209:
210: }
|