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.handler;
018:
019: import java.util.ArrayList;
020: import java.util.List;
021:
022: import org.springframework.beans.BeansException;
023: import org.springframework.beans.factory.BeanFactoryUtils;
024: import org.springframework.context.ApplicationContextException;
025: import org.springframework.util.StringUtils;
026:
027: /**
028: * Implementation of the {@link org.springframework.web.servlet.HandlerMapping}
029: * interface that map from URLs to beans with names that start with a slash ("/"),
030: * similar to how Struts maps URLs to action names.
031: *
032: * <p>This is the default implementation used by the
033: * {@link org.springframework.web.servlet.DispatcherServlet}, but it is somewhat naive.
034: * A {@link SimpleUrlHandlerMapping} or a custom handler mapping should be used
035: * by preference.
036: *
037: * <p>The mapping is from URL to bean name. Thus an incoming URL "/foo" would map
038: * to a handler named "/foo", or to "/foo /foo2" in case of multiple mappings to
039: * a single handler. Note: In XML definitions, you'll need to use an alias
040: * name="/foo" in the bean definition, as the XML id may not contain slashes.
041: *
042: * <p>Supports direct matches (given "/test" -> registered "/test") and "*"
043: * matches (given "/test" -> registered "/t*"). Note that the default is
044: * to map within the current servlet mapping if applicable; see the
045: * {@link #setAlwaysUseFullPath "alwaysUseFullPath"} property for details.
046: * For details on the pattern options, see the
047: * {@link org.springframework.util.AntPathMatcher} javadoc.
048: *
049: * @author Rod Johnson
050: * @author Juergen Hoeller
051: * @see SimpleUrlHandlerMapping
052: */
053: public class BeanNameUrlHandlerMapping extends
054: AbstractUrlHandlerMapping {
055:
056: private boolean detectHandlersInAncestorContexts = false;
057:
058: /**
059: * Set whether to detect handler beans in ancestor ApplicationContexts.
060: * <p>Default is "false": Only handler beans in the current
061: * ApplicationContext will be detected, that is, only in the context
062: * that this BeanNameUrlHandlerMapping itself is defined in (typically
063: * the current DispatcherServlet's context).
064: * <p>Switch this flag on to detect handler beans in ancestor contexts
065: * (typically the Spring root WebApplicationContext) as well.
066: */
067: public void setDetectHandlersInAncestorContexts(
068: boolean detectHandlersInAncestorContexts) {
069: this .detectHandlersInAncestorContexts = detectHandlersInAncestorContexts;
070: }
071:
072: /**
073: * Calls the {@link #detectHandlers()} method in addition to the
074: * superclass's initialization.
075: */
076: public void initApplicationContext()
077: throws ApplicationContextException {
078: super .initApplicationContext();
079: detectHandlers();
080: }
081:
082: /**
083: * Register all handlers found in the current ApplicationContext.
084: * Any bean whose name appears to be a URL is considered a handler.
085: * @throws BeansException if the handler couldn't be registered
086: * @see #determineUrlsForHandler
087: */
088: protected void detectHandlers() throws BeansException {
089: if (logger.isDebugEnabled()) {
090: logger
091: .debug("Looking for URL mappings in application context: "
092: + getApplicationContext());
093: }
094: String[] beanNames = (this .detectHandlersInAncestorContexts ? BeanFactoryUtils
095: .beanNamesForTypeIncludingAncestors(
096: getApplicationContext(), Object.class)
097: : getApplicationContext().getBeanNamesForType(
098: Object.class));
099:
100: // Take any bean name or alias that begins with a slash.
101: for (int i = 0; i < beanNames.length; i++) {
102: String beanName = beanNames[i];
103: String[] urls = determineUrlsForHandler(beanName);
104: if (urls.length > 0) {
105: // URL paths found: Let's consider it a handler.
106: registerHandler(urls, beanName);
107: } else {
108: if (logger.isDebugEnabled()) {
109: logger.debug("Rejected bean name '" + beanNames[i]
110: + "': no URL paths identified");
111: }
112: }
113: }
114: }
115:
116: /**
117: * Check name and aliases of the given bean for URLs,
118: * detected by starting with "/".
119: * @param beanName the name of the candidate bean
120: * @return the URLs determined for the bean, or an empty array if none
121: */
122: protected String[] determineUrlsForHandler(String beanName) {
123: List urls = new ArrayList();
124: if (beanName.startsWith("/")) {
125: urls.add(beanName);
126: }
127: String[] aliases = getApplicationContext().getAliases(beanName);
128: for (int j = 0; j < aliases.length; j++) {
129: if (aliases[j].startsWith("/")) {
130: urls.add(aliases[j]);
131: }
132: }
133: return StringUtils.toStringArray(urls);
134: }
135:
136: }
|