001/*
002 * Copyright 2002-2015 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 java.util.LinkedHashMap;
020import java.util.Map;
021import java.util.Properties;
022
023import org.springframework.beans.BeansException;
024import org.springframework.util.CollectionUtils;
025
026/**
027 * Implementation of the {@link org.springframework.web.servlet.HandlerMapping}
028 * interface to map from URLs to request handler beans. Supports both mapping to bean
029 * instances and mapping to bean names; the latter is required for non-singleton handlers.
030 *
031 * <p>The "urlMap" property is suitable for populating the handler map with
032 * bean references, e.g. via the map element in XML bean definitions.
033 *
034 * <p>Mappings to bean names can be set via the "mappings" property, in a form
035 * accepted by the {@code java.util.Properties} class, like as follows:<br>
036 * {@code
037 * /welcome.html=ticketController
038 * /show.html=ticketController
039 * }<br>
040 * The syntax is {@code PATH=HANDLER_BEAN_NAME}.
041 * If the path doesn't begin with a slash, one is prepended.
042 *
043 * <p>Supports direct matches (given "/test" -> registered "/test") and "*"
044 * pattern matches (given "/test" -> registered "/t*"). Note that the default
045 * is to map within the current servlet mapping if applicable; see the
046 * {@link #setAlwaysUseFullPath "alwaysUseFullPath"} property. For details on the
047 * pattern options, see the {@link org.springframework.util.AntPathMatcher} javadoc.
048
049 * @author Rod Johnson
050 * @author Juergen Hoeller
051 * @see #setMappings
052 * @see #setUrlMap
053 * @see BeanNameUrlHandlerMapping
054 */
055public class SimpleUrlHandlerMapping extends AbstractUrlHandlerMapping {
056
057        private final Map<String, Object> urlMap = new LinkedHashMap<String, Object>();
058
059
060        /**
061         * Map URL paths to handler bean names.
062         * This is the typical way of configuring this HandlerMapping.
063         * <p>Supports direct URL matches and Ant-style pattern matches. For syntax
064         * details, see the {@link org.springframework.util.AntPathMatcher} javadoc.
065         * @param mappings properties with URLs as keys and bean names as values
066         * @see #setUrlMap
067         */
068        public void setMappings(Properties mappings) {
069                CollectionUtils.mergePropertiesIntoMap(mappings, this.urlMap);
070        }
071
072        /**
073         * Set a Map with URL paths as keys and handler beans (or handler bean names)
074         * as values. Convenient for population with bean references.
075         * <p>Supports direct URL matches and Ant-style pattern matches. For syntax
076         * details, see the {@link org.springframework.util.AntPathMatcher} javadoc.
077         * @param urlMap map with URLs as keys and beans as values
078         * @see #setMappings
079         */
080        public void setUrlMap(Map<String, ?> urlMap) {
081                this.urlMap.putAll(urlMap);
082        }
083
084        /**
085         * Allow Map access to the URL path mappings, with the option to add or
086         * override specific entries.
087         * <p>Useful for specifying entries directly, for example via "urlMap[myKey]".
088         * This is particularly useful for adding or overriding entries in child
089         * bean definitions.
090         */
091        public Map<String, ?> getUrlMap() {
092                return this.urlMap;
093        }
094
095
096        /**
097         * Calls the {@link #registerHandlers} method in addition to the
098         * superclass's initialization.
099         */
100        @Override
101        public void initApplicationContext() throws BeansException {
102                super.initApplicationContext();
103                registerHandlers(this.urlMap);
104        }
105
106        /**
107         * Register all handlers specified in the URL map for the corresponding paths.
108         * @param urlMap Map with URL paths as keys and handler beans or bean names as values
109         * @throws BeansException if a handler couldn't be registered
110         * @throws IllegalStateException if there is a conflicting handler registered
111         */
112        protected void registerHandlers(Map<String, Object> urlMap) throws BeansException {
113                if (urlMap.isEmpty()) {
114                        logger.warn("Neither 'urlMap' nor 'mappings' set on SimpleUrlHandlerMapping");
115                }
116                else {
117                        for (Map.Entry<String, Object> entry : urlMap.entrySet()) {
118                                String url = entry.getKey();
119                                Object handler = entry.getValue();
120                                // Prepend with slash if not already present.
121                                if (!url.startsWith("/")) {
122                                        url = "/" + url;
123                                }
124                                // Remove whitespace from handler bean name.
125                                if (handler instanceof String) {
126                                        handler = ((String) handler).trim();
127                                }
128                                registerHandler(url, handler);
129                        }
130                }
131        }
132
133}