001: /*
002: * Copyright 2002-2007 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.Map;
020:
021: import javax.servlet.http.HttpServletRequest;
022:
023: import org.springframework.core.CollectionFactory;
024: import org.springframework.util.StringUtils;
025: import org.springframework.web.servlet.HandlerMapping;
026:
027: /**
028: * Simple <code>Controller</code> implementation that transforms the virtual
029: * path of a URL into a view name and returns that view.
030: *
031: * <p>Can optionally prepend a {@link #setPrefix prefix} and/or append a
032: * {@link #setSuffix suffix} to build the viewname from the URL filename.
033: *
034: * <p>Find below some examples:
035: *
036: * <ol>
037: * <li><code>"/index" -> "index"</code></li>
038: * <li><code>"/index.html" -> "index"</code></li>
039: * <li><code>"/index.html"</code> + prefix <code>"pre_"</code> and suffix <code>"_suf" -> "pre_index_suf"</code></li>
040: * <li><code>"/products/view.html" -> "products/view"</code></li>
041: * </ol>
042: *
043: * <p>Thanks to David Barri for suggesting prefix/suffix support!
044: *
045: * @author Alef Arendsen
046: * @author Juergen Hoeller
047: * @author Rob Harrop
048: * @see #setPrefix
049: * @see #setSuffix
050: */
051: public class UrlFilenameViewController extends
052: AbstractUrlViewController {
053:
054: private String prefix = "";
055:
056: private String suffix = "";
057:
058: /** Request URL path String --> view name String */
059: private final Map viewNameCache = CollectionFactory
060: .createConcurrentMapIfPossible(16);
061:
062: /**
063: * Set the prefix to prepend to the request URL filename
064: * to build a view name.
065: */
066: public void setPrefix(String prefix) {
067: this .prefix = (prefix != null ? prefix : "");
068: }
069:
070: /**
071: * Return the prefix to prepend to the request URL filename.
072: */
073: protected String getPrefix() {
074: return this .prefix;
075: }
076:
077: /**
078: * Set the suffix to append to the request URL filename
079: * to build a view name.
080: */
081: public void setSuffix(String suffix) {
082: this .suffix = (suffix != null ? suffix : "");
083: }
084:
085: /**
086: * Return the suffix to append to the request URL filename.
087: */
088: protected String getSuffix() {
089: return this .suffix;
090: }
091:
092: /**
093: * Returns view name based on the URL filename,
094: * with prefix/suffix applied when appropriate.
095: * @see #extractViewNameFromUrlPath
096: * @see #setPrefix
097: * @see #setSuffix
098: */
099: protected String getViewNameForRequest(HttpServletRequest request) {
100: String uri = extractOperableUrl(request);
101: return getViewNameForUrlPath(uri);
102: }
103:
104: /**
105: * Extract a URL path from the given request,
106: * suitable for view name extraction.
107: * @param request current HTTP request
108: * @return the URL to use for view name extraction
109: */
110: protected String extractOperableUrl(HttpServletRequest request) {
111: String urlPath = (String) request
112: .getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE);
113: if (!StringUtils.hasText(urlPath)) {
114: urlPath = getUrlPathHelper().getLookupPathForRequest(
115: request);
116: }
117: return urlPath;
118: }
119:
120: /**
121: * Returns view name based on the URL filename,
122: * with prefix/suffix applied when appropriate.
123: * @param uri the request URI; for example <code>"/index.html"</code>
124: * @return the extracted URI filename; for example <code>"index"</code>
125: * @see #extractViewNameFromUrlPath
126: * @see #postProcessViewName
127: */
128: protected String getViewNameForUrlPath(String uri) {
129: String viewName = (String) this .viewNameCache.get(uri);
130: if (viewName == null) {
131: viewName = extractViewNameFromUrlPath(uri);
132: viewName = postProcessViewName(viewName);
133: this .viewNameCache.put(uri, viewName);
134: }
135: return viewName;
136: }
137:
138: /**
139: * Extract the URL filename from the given request URI.
140: * @param uri the request URI; for example <code>"/index.html"</code>
141: * @return the extracted URI filename; for example <code>"index"</code>
142: */
143: protected String extractViewNameFromUrlPath(String uri) {
144: int start = (uri.charAt(0) == '/' ? 1 : 0);
145: int lastIndex = uri.lastIndexOf(".");
146: int end = (lastIndex < 0 ? uri.length() : lastIndex);
147: return uri.substring(start, end);
148: }
149:
150: /**
151: * Build the full view name based on the given view name
152: * as indicated by the URL path.
153: * <p>The default implementation simply applies prefix and suffix.
154: * This can be overridden, for example, to manipulate upper case
155: * / lower case, etc.
156: * @param viewName the original view name, as indicated by the URL path
157: * @return the full view name to use
158: * @see #getPrefix()
159: * @see #getSuffix()
160: */
161: protected String postProcessViewName(String viewName) {
162: return getPrefix() + viewName + getSuffix();
163: }
164:
165: }
|