KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > springframework > web > servlet > mvc > support > ControllerClassNameHandlerMapping


1 /*
2  * Copyright 2002-2007 the original author or authors.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16
17 package org.springframework.web.servlet.mvc.support;
18
19 import java.util.Arrays JavaDoc;
20 import java.util.Collections JavaDoc;
21 import java.util.HashSet JavaDoc;
22 import java.util.Iterator JavaDoc;
23 import java.util.Set JavaDoc;
24
25 import org.springframework.beans.BeansException;
26 import org.springframework.util.ClassUtils;
27 import org.springframework.web.servlet.HandlerMapping;
28 import org.springframework.web.servlet.handler.AbstractUrlHandlerMapping;
29 import org.springframework.web.servlet.mvc.Controller;
30 import org.springframework.web.servlet.mvc.multiaction.MultiActionController;
31 import org.springframework.web.servlet.mvc.throwaway.ThrowawayController;
32
33 /**
34  * Implementation of {@link HandlerMapping} that follows a simple convention for
35  * generating URL path mappings from the class names of registered
36  * {@link org.springframework.web.servlet.mvc.Controller} and
37  * {@link org.springframework.web.servlet.mvc.throwaway.ThrowawayController} beans.
38  *
39  * <p>For simple {@link org.springframework.web.servlet.mvc.Controller} implementations
40  * (those that handle a single request type), the convention is to take the
41  * {@link ClassUtils#getShortName short name} of the <code>Class</code>,
42  * remove the 'Controller' suffix if it exists and return the remaining text, lowercased,
43  * as the mapping, with a leading <code>/</code>. For example:
44  * <ul>
45  * <li><code>WelcomeController</code> -> <code>/welcome*</code></li>
46  * <li><code>HomeController</code> -> <code>/home*</code></li>
47  * </ul>
48  *
49  * <p>For {@link MultiActionController MultiActionControllers} then a similar mapping is registered,
50  * except that all sub-paths are registed using the trailing wildcard pattern <code>/*</code>.
51  * For example:
52  * <ul>
53  * <li><code>WelcomeController</code> -> <code>/welcome/*</code></li>
54  * <li><code>CatalogController</code> -> <code>/catalog/*</code></li>
55  * </ul>
56  *
57  * <p>For {@link MultiActionController} it is often useful to use
58  * this mapping strategy in conjunction with the
59  * {@link org.springframework.web.servlet.mvc.multiaction.InternalPathMethodNameResolver}.
60  *
61  * @author Rob Harrop
62  * @author Juergen Hoeller
63  * @since 2.0
64  * @see org.springframework.web.servlet.mvc.Controller
65  * @see org.springframework.web.servlet.mvc.throwaway.ThrowawayController
66  * @see org.springframework.web.servlet.mvc.multiaction.MultiActionController
67  */

68 public class ControllerClassNameHandlerMapping extends AbstractUrlHandlerMapping implements HandlerMapping {
69
70     /**
71      * Common suffix at the end of controller implementation classes.
72      * Removed when generating the URL path.
73      */

74     private static final String JavaDoc CONTROLLER_SUFFIX = "Controller";
75
76
77     private Set JavaDoc excludedPackages = Collections.singleton("org.springframework.web.servlet.mvc");
78
79     private Set JavaDoc excludedClasses = Collections.EMPTY_SET;
80
81
82     /**
83      * Specify Java packages that should be excluded from this mapping.
84      * Any classes in such a package (or any of its subpackages) will be
85      * ignored by this HandlerMapping.
86      * <p>Default is to exclude the entire "org.springframework.web.servlet.mvc"
87      * package, including its subpackages, since none of Spring's out-of-the-box
88      * Controller implementations is a reasonable candidate for this mapping strategy.
89      * Such controllers are typically handled by a separate HandlerMapping,
90      * e.g. a {@link org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping},
91      * alongside this ControllerClassNameHandlerMapping for application controllers.
92      */

93     public void setExcludedPackages(String JavaDoc[] excludedPackages) {
94         this.excludedPackages =
95                 (excludedPackages != null ? new HashSet JavaDoc(Arrays.asList(excludedPackages)) : Collections.EMPTY_SET);
96     }
97
98     /**
99      * Specify controller classes that should be excluded from this mapping.
100      * Any such classes will simply be ignored by this HandlerMapping.
101      */

102     public void setExcludedClasses(Class JavaDoc[] excludedClasses) {
103         this.excludedClasses =
104                 (excludedClasses != null ? new HashSet JavaDoc(Arrays.asList(excludedClasses)) : Collections.EMPTY_SET);
105     }
106
107
108     /**
109      * Calls the {@link #detectControllers()} method in addition to the
110      * superclass's initialization.
111      */

112     protected void initApplicationContext() {
113         super.initApplicationContext();
114         detectControllers();
115     }
116
117     /**
118      * Detect all the {@link org.springframework.web.servlet.mvc.Controller} and
119      * {@link org.springframework.web.servlet.mvc.throwaway.ThrowawayController}
120      * beans registered in the {@link org.springframework.context.ApplicationContext}
121      * and register a URL path mapping for each one based on rules defined here.
122      * @throws BeansException if the controllers couldn't be obtained or registered
123      * @see #generatePathMapping(Class)
124      */

125     protected void detectControllers() throws BeansException {
126         registerControllers(Controller.class);
127         registerControllers(ThrowawayController.class);
128     }
129
130     /**
131      * Register all controllers of the given type, searching the current
132      * DispatcherServlet's ApplicationContext for matching beans.
133      * @param controllerType the type of controller to search for
134      * @throws BeansException if the controllers couldn't be obtained or registered
135      */

136     protected void registerControllers(Class JavaDoc controllerType) throws BeansException {
137         String JavaDoc[] beanNames = getApplicationContext().getBeanNamesForType(controllerType);
138         for (int i = 0; i < beanNames.length; i++) {
139             String JavaDoc beanName = beanNames[i];
140             Class JavaDoc beanClass = getApplicationContext().getType(beanName);
141             if (isEligibleForMapping(beanName, beanClass)) {
142                 registerController(beanName, beanClass);
143             }
144         }
145     }
146
147     /**
148      * Determine whether the specified controller is excluded from this mapping.
149      * @param beanName the name of the controller bean
150      * @param beanClass the concrete class of the controller bean
151      * @return whether the specified class is excluded
152      * @see #setExcludedPackages
153      * @see #setExcludedClasses
154      */

155     protected boolean isEligibleForMapping(String JavaDoc beanName, Class JavaDoc beanClass) {
156         if (beanClass == null) {
157             if (logger.isDebugEnabled()) {
158                 logger.debug("Excluding controller bean '" + beanName + "' from class name mapping " +
159                         "because its bean type could not be determined");
160             }
161             return false;
162         }
163         if (this.excludedClasses.contains(beanClass)) {
164             if (logger.isDebugEnabled()) {
165                 logger.debug("Excluding controller bean '" + beanName + "' from class name mapping " +
166                         "because its bean class is explicitly excluded: " + beanClass.getName());
167             }
168             return false;
169         }
170         String JavaDoc beanClassName = beanClass.getName();
171         for (Iterator JavaDoc it = this.excludedPackages.iterator(); it.hasNext();) {
172             String JavaDoc packageName = (String JavaDoc) it.next();
173             if (beanClassName.startsWith(packageName)) {
174                 if (logger.isDebugEnabled()) {
175                     logger.debug("Excluding controller bean '" + beanName + "' from class name mapping " +
176                             "because its bean class is defined in an excluded package: " + beanClass.getName());
177                 }
178                 return false;
179             }
180         }
181         return true;
182     }
183
184     /**
185      * Register the controller with the given name, as defined
186      * in the current application context.
187      * @param beanName the name of the controller bean
188      * @param beanClass the concrete class of the controller bean
189      * @throws BeansException if the controller couldn't be registered
190      * @throws IllegalStateException if there is a conflicting handler registered
191      * @see #getApplicationContext()
192      */

193     protected void registerController(String JavaDoc beanName, Class JavaDoc beanClass) throws BeansException, IllegalStateException JavaDoc {
194         String JavaDoc urlPath = generatePathMapping(beanClass);
195         if (logger.isDebugEnabled()) {
196             logger.debug("Registering Controller '" + beanName + "' as handler for URL path [" + urlPath + "]");
197         }
198         registerHandler(urlPath, beanName);
199     }
200
201     /**
202      * Generate the actual URL path for the given controller class.
203      * <p>Subclasses may choose to customize the paths that are generated
204      * by overriding this method.
205      * @param beanClass the controller bean class to generate a mapping for
206      * @return the URL path mapping for the given controller
207      */

208     protected String JavaDoc generatePathMapping(Class JavaDoc beanClass) {
209         StringBuffer JavaDoc pathMapping = new StringBuffer JavaDoc("/");
210         String JavaDoc className = ClassUtils.getShortName(beanClass.getName());
211         String JavaDoc path = (className.endsWith(CONTROLLER_SUFFIX) ?
212                 className.substring(0, className.indexOf(CONTROLLER_SUFFIX)) : className);
213         pathMapping.append(path.toLowerCase());
214         if (MultiActionController.class.isAssignableFrom(beanClass)) {
215             pathMapping.append("/*");
216         }
217         else {
218             pathMapping.append("*");
219         }
220         return pathMapping.toString();
221     }
222
223 }
224
Popular Tags