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