KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > riotfamily > common > web > mapping > AdvancedBeanNameHandlerMapping


1 /* ***** BEGIN LICENSE BLOCK *****
2  * Version: MPL 1.1
3  * The contents of this file are subject to the Mozilla Public License Version
4  * 1.1 (the "License"); you may not use this file except in compliance with
5  * the License. You may obtain a copy of the License at
6  * http://www.mozilla.org/MPL/
7  *
8  * Software distributed under the License is distributed on an "AS IS" basis,
9  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
10  * for the specific language governing rights and limitations under the
11  * License.
12  *
13  * The Original Code is Riot.
14  *
15  * The Initial Developer of the Original Code is
16  * Neteye GmbH.
17  * Portions created by the Initial Developer are Copyright (C) 2006
18  * the Initial Developer. All Rights Reserved.
19  *
20  * Contributor(s):
21  * Felix Gnass [fgnass at neteye dot de]
22  *
23  * ***** END LICENSE BLOCK ***** */

24 package org.riotfamily.common.web.mapping;
25
26 import java.util.ArrayList JavaDoc;
27 import java.util.HashMap JavaDoc;
28 import java.util.Iterator JavaDoc;
29 import java.util.List JavaDoc;
30 import java.util.Map JavaDoc;
31
32 import javax.servlet.http.HttpServletRequest JavaDoc;
33
34 import org.riotfamily.common.web.util.ServletUtils;
35 import org.springframework.beans.BeansException;
36 import org.springframework.context.ApplicationContextException;
37 import org.springframework.util.AntPathMatcher;
38 import org.springframework.util.PathMatcher;
39 import org.springframework.util.StringUtils;
40 import org.springframework.web.servlet.HandlerMapping;
41
42 /**
43  * HandlerMapping that works like Spring's BeanNameUrlHandlerMapping and
44  * can expose parts of the matched URL as request attributes.
45  * <p>The handler name <code>/foo/bar/@{some}/@{value}</code> would be
46  * equivalent to <code>/foo/bar/&#42;/&#42;</code>, the last two wildcards
47  * would be exposed as attributes "some" and "value".
48  */

49 public class AdvancedBeanNameHandlerMapping
50         extends AbstractReverseHandlerMapping {
51
52     private final Map JavaDoc handlerMap = new HashMap JavaDoc();
53
54     private HashMap JavaDoc patternsByAntPath = new HashMap JavaDoc();
55
56     private HashMap JavaDoc patternsByBeanName = new HashMap JavaDoc();
57
58     private PathMatcher pathMatcher = new AntPathMatcher();
59     
60     private boolean stripServletMapping = true;
61     
62     private Object JavaDoc rootHandler;
63     
64     public void setStripServletMapping(boolean stripServletMapping) {
65         this.stripServletMapping = stripServletMapping;
66     }
67     
68     protected boolean isStripServletMapping() {
69         return this.stripServletMapping;
70     }
71     
72     /**
73      * Set the root handler for this handler mapping, that is,
74      * the handler to be registered for the root path ("/").
75      * <p>Default is <code>null</code>, indicating no root handler.
76      */

77     public void setRootHandler(Object JavaDoc rootHandler) {
78         this.rootHandler = rootHandler;
79     }
80     
81     /**
82      * Return the root handler for this handler mapping (registered for "/"),
83      * or <code>null</code> if none.
84      */

85     protected Object JavaDoc getRootHandler() {
86         return this.rootHandler;
87     }
88     
89     /**
90      * <strong>Copied from BeanNameUrlHandlerMapping</strong>
91      */

92     public void initApplicationContext() throws ApplicationContextException {
93         super.initApplicationContext();
94         String JavaDoc[] beanNames = getApplicationContext().getBeanDefinitionNames();
95
96         // Take any bean name or alias that begins with a slash.
97
for (int i = 0; i < beanNames.length; i++) {
98             String JavaDoc[] urls = checkForUrl(beanNames[i]);
99             if (urls.length > 0) {
100                 if (logger.isDebugEnabled()) {
101                     logger.debug("Found URL mapping [" + beanNames[i] + "]");
102                 }
103                 ArrayList JavaDoc patterns = new ArrayList JavaDoc();
104                 // Create a mapping to each part of the path.
105
for (int j = 0; j < urls.length; j++) {
106                     String JavaDoc attributePattern = urls[j];
107                     String JavaDoc antPattern = AttributePattern.convertToAntPattern(attributePattern);
108                     registerHandler(antPattern, beanNames[i]);
109                     AttributePattern p = new AttributePattern(attributePattern);
110                     patternsByAntPath.put(antPattern, p);
111                     patterns.add(p);
112                 }
113                 patternsByBeanName.put(beanNames[i], patterns);
114             }
115             else {
116                 if (logger.isDebugEnabled()) {
117                     logger.debug("Rejected bean name '" + beanNames[i] + "'");
118                 }
119             }
120         }
121     }
122     
123     /**
124      * Check name and aliases of the given bean for URLs,
125      * detected by starting with "/".
126      * <p><strong>Copied from BeanNameUrlHandlerMapping</strong>
127      */

128     private String JavaDoc[] checkForUrl(String JavaDoc beanName) {
129         List JavaDoc urls = new ArrayList JavaDoc();
130         if (beanName.startsWith("/")) {
131             urls.add(beanName);
132         }
133         String JavaDoc[] aliases = getApplicationContext().getAliases(beanName);
134         for (int j = 0; j < aliases.length; j++) {
135             if (aliases[j].startsWith("/")) {
136                 urls.add(aliases[j]);
137             }
138         }
139         return StringUtils.toStringArray(urls);
140     }
141         
142     /**
143      * Register the given handler instance for the given URL path.
144      * <p><strong>Copied from AbstractUrlHandlerMapping</strong>
145      * @param urlPath URL the bean is mapped to
146      * @param handler the handler instance
147      * @throws BeansException if the handler couldn't be registered
148      */

149     private void registerHandler(String JavaDoc urlPath, Object JavaDoc handler) throws BeansException {
150         Object JavaDoc mappedHandler = this.handlerMap.get(urlPath);
151         if (mappedHandler != null) {
152             throw new ApplicationContextException(
153                     "Cannot map handler [" + handler + "] to URL path [" + urlPath +
154                     "]: there's already handler [" + mappedHandler + "] mapped");
155         }
156
157         // Eagerly resolve handler if referencing singleton via name.
158
if (handler instanceof String JavaDoc) {
159             String JavaDoc handlerName = (String JavaDoc) handler;
160             if (getApplicationContext().isSingleton(handlerName)) {
161                 handler = getApplicationContext().getBean(handlerName);
162             }
163         }
164
165         if (urlPath.equals("/*")) {
166             setDefaultHandler(handler);
167         }
168         else {
169             this.handlerMap.put(urlPath, handler);
170             if (logger.isDebugEnabled()) {
171                 logger.debug("Mapped URL path [" + urlPath
172                         + "] onto handler [" + handler + "]");
173             }
174         }
175     }
176
177     protected String JavaDoc getLookupPath(HttpServletRequest JavaDoc request) {
178         if (stripServletMapping) {
179             return ServletUtils.getPathWithoutServletMapping(request);
180         }
181         else {
182             return ServletUtils.getPathWithinApplication(request);
183         }
184     }
185     
186     /**
187      * Look up a handler for the given request, falling back to the default
188      * handler if no specific one is found.
189      * @param request current HTTP request
190      * @return the looked up handler instance, or the default handler
191      */

192     public Object JavaDoc getHandlerInternal(HttpServletRequest JavaDoc request)
193             throws Exception JavaDoc {
194
195         String JavaDoc lookupPath = getLookupPath(request);
196         if (logger.isDebugEnabled()) {
197             logger.debug("Looking up handler for [" + lookupPath + "]");
198         }
199
200         return lookupHandler(lookupPath, request);
201     }
202
203     /**
204      * Look up a handler instance for the given URL path.
205      * <p>Supports direct matches, e.g. a registered "/test" matches "/test",
206      * and various Ant-style pattern matches, e.g. a registered "/t*" matches
207      * both "/test" and "/team". For details, see the AntPathMatcher class.
208      * <p>Looks for the most exact pattern, where most exact is defined as
209      * the longest path pattern.
210      * <p><strong>Copied from AbstractUrlHandlerMapping</strong>
211      * @param urlPath URL the bean is mapped to
212      * @return the associated handler instance, or <code>null</code> if not found
213      * @see org.springframework.util.AntPathMatcher
214      */

215     protected Object JavaDoc lookupHandler(String JavaDoc urlPath, HttpServletRequest JavaDoc request) {
216         // direct match?
217
Object JavaDoc handler = handlerMap.get(urlPath);
218         if (handler == null && "/".equals(urlPath)) {
219             handler = getRootHandler();
220         }
221         if (handler == null) {
222             // pattern match?
223
String JavaDoc bestMatch = null;
224             for (Iterator JavaDoc it = handlerMap.keySet().iterator(); it.hasNext();) {
225                 String JavaDoc path = (String JavaDoc) it.next();
226                 if (pathMatcher.match(path, urlPath) &&
227                         (bestMatch == null || bestMatch.length() <= path.length())) {
228
229                     bestMatch = path;
230                 }
231             }
232             if (bestMatch != null) {
233                 exposeAttributes(bestMatch, urlPath, request);
234                 exposePathWithinMapping(pathMatcher.extractPathWithinPattern(bestMatch, urlPath), request);
235                 handler = handlerMap.get(bestMatch);
236             }
237         }
238         else {
239             exposePathWithinMapping(urlPath, request);
240         }
241         return handler;
242     }
243     
244     
245     /**
246      * <strong>Copied from AbstractUrlHandlerMapping</strong>
247      */

248     protected void exposePathWithinMapping(String JavaDoc pathWithinMapping, HttpServletRequest JavaDoc request) {
249         request.setAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE, pathWithinMapping);
250     }
251     
252     protected void exposeAttributes(String JavaDoc antPattern, String JavaDoc urlPath,
253             HttpServletRequest JavaDoc request) {
254
255         AttributePattern pattern = (AttributePattern) patternsByAntPath.get(antPattern);
256         pattern.expose(urlPath, request);
257
258     }
259     
260     protected String JavaDoc addServletMappingIfNecessary(String JavaDoc path,
261             HttpServletRequest JavaDoc request) {
262         
263         if (path != null && isStripServletMapping()) {
264             return ServletUtils.addServletMapping(path, request);
265         }
266         return path;
267     }
268     
269     protected List JavaDoc getPatternsForHandler(String JavaDoc beanName,
270             HttpServletRequest JavaDoc request) {
271         
272         return (List JavaDoc) patternsByBeanName.get(beanName);
273     }
274     
275 }
276
Popular Tags