001/*
002 * Copyright 2002-2012 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 *      https://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
017package org.springframework.web.servlet.handler;
018
019import org.springframework.beans.BeansException;
020import org.springframework.beans.factory.BeanFactoryUtils;
021import org.springframework.context.ApplicationContext;
022import org.springframework.context.ApplicationContextException;
023import org.springframework.util.ObjectUtils;
024
025/**
026 * Abstract implementation of the {@link org.springframework.web.servlet.HandlerMapping}
027 * interface, detecting URL mappings for handler beans through introspection of all
028 * defined beans in the application context.
029 *
030 * @author Juergen Hoeller
031 * @since 2.5
032 * @see #determineUrlsForHandler
033 */
034public abstract class AbstractDetectingUrlHandlerMapping extends AbstractUrlHandlerMapping {
035
036        private boolean detectHandlersInAncestorContexts = false;
037
038
039        /**
040         * Set whether to detect handler beans in ancestor ApplicationContexts.
041         * <p>Default is "false": Only handler beans in the current ApplicationContext
042         * will be detected, i.e. only in the context that this HandlerMapping itself
043         * is defined in (typically the current DispatcherServlet's context).
044         * <p>Switch this flag on to detect handler beans in ancestor contexts
045         * (typically the Spring root WebApplicationContext) as well.
046         */
047        public void setDetectHandlersInAncestorContexts(boolean detectHandlersInAncestorContexts) {
048                this.detectHandlersInAncestorContexts = detectHandlersInAncestorContexts;
049        }
050
051
052        /**
053         * Calls the {@link #detectHandlers()} method in addition to the
054         * superclass's initialization.
055         */
056        @Override
057        public void initApplicationContext() throws ApplicationContextException {
058                super.initApplicationContext();
059                detectHandlers();
060        }
061
062        /**
063         * Register all handlers found in the current ApplicationContext.
064         * <p>The actual URL determination for a handler is up to the concrete
065         * {@link #determineUrlsForHandler(String)} implementation. A bean for
066         * which no such URLs could be determined is simply not considered a handler.
067         * @throws org.springframework.beans.BeansException if the handler couldn't be registered
068         * @see #determineUrlsForHandler(String)
069         */
070        protected void detectHandlers() throws BeansException {
071                ApplicationContext applicationContext = obtainApplicationContext();
072                String[] beanNames = (this.detectHandlersInAncestorContexts ?
073                                BeanFactoryUtils.beanNamesForTypeIncludingAncestors(applicationContext, Object.class) :
074                                applicationContext.getBeanNamesForType(Object.class));
075
076                // Take any bean name that we can determine URLs for.
077                for (String beanName : beanNames) {
078                        String[] urls = determineUrlsForHandler(beanName);
079                        if (!ObjectUtils.isEmpty(urls)) {
080                                // URL paths found: Let's consider it a handler.
081                                registerHandler(urls, beanName);
082                        }
083                }
084
085                if ((logger.isDebugEnabled() && !getHandlerMap().isEmpty()) || logger.isTraceEnabled()) {
086                        logger.debug("Detected " + getHandlerMap().size() + " mappings in " + formatMappingName());
087                }
088        }
089
090
091        /**
092         * Determine the URLs for the given handler bean.
093         * @param beanName the name of the candidate bean
094         * @return the URLs determined for the bean, or an empty array if none
095         */
096        protected abstract String[] determineUrlsForHandler(String beanName);
097
098}