001/*
002 * Copyright 2002-2017 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.beans.factory.xml;
018
019import java.util.HashMap;
020import java.util.Map;
021
022import org.w3c.dom.Attr;
023import org.w3c.dom.Element;
024import org.w3c.dom.Node;
025
026import org.springframework.beans.factory.config.BeanDefinition;
027import org.springframework.beans.factory.config.BeanDefinitionHolder;
028import org.springframework.lang.Nullable;
029
030/**
031 * Support class for implementing custom {@link NamespaceHandler NamespaceHandlers}.
032 * Parsing and decorating of individual {@link Node Nodes} is done via {@link BeanDefinitionParser}
033 * and {@link BeanDefinitionDecorator} strategy interfaces, respectively.
034 *
035 * <p>Provides the {@link #registerBeanDefinitionParser} and {@link #registerBeanDefinitionDecorator}
036 * methods for registering a {@link BeanDefinitionParser} or {@link BeanDefinitionDecorator}
037 * to handle a specific element.
038 *
039 * @author Rob Harrop
040 * @author Juergen Hoeller
041 * @since 2.0
042 * @see #registerBeanDefinitionParser(String, BeanDefinitionParser)
043 * @see #registerBeanDefinitionDecorator(String, BeanDefinitionDecorator)
044 */
045public abstract class NamespaceHandlerSupport implements NamespaceHandler {
046
047        /**
048         * Stores the {@link BeanDefinitionParser} implementations keyed by the
049         * local name of the {@link Element Elements} they handle.
050         */
051        private final Map<String, BeanDefinitionParser> parsers = new HashMap<>();
052
053        /**
054         * Stores the {@link BeanDefinitionDecorator} implementations keyed by the
055         * local name of the {@link Element Elements} they handle.
056         */
057        private final Map<String, BeanDefinitionDecorator> decorators = new HashMap<>();
058
059        /**
060         * Stores the {@link BeanDefinitionDecorator} implementations keyed by the local
061         * name of the {@link Attr Attrs} they handle.
062         */
063        private final Map<String, BeanDefinitionDecorator> attributeDecorators = new HashMap<>();
064
065
066        /**
067         * Parses the supplied {@link Element} by delegating to the {@link BeanDefinitionParser} that is
068         * registered for that {@link Element}.
069         */
070        @Override
071        @Nullable
072        public BeanDefinition parse(Element element, ParserContext parserContext) {
073                BeanDefinitionParser parser = findParserForElement(element, parserContext);
074                return (parser != null ? parser.parse(element, parserContext) : null);
075        }
076
077        /**
078         * Locates the {@link BeanDefinitionParser} from the register implementations using
079         * the local name of the supplied {@link Element}.
080         */
081        @Nullable
082        private BeanDefinitionParser findParserForElement(Element element, ParserContext parserContext) {
083                String localName = parserContext.getDelegate().getLocalName(element);
084                BeanDefinitionParser parser = this.parsers.get(localName);
085                if (parser == null) {
086                        parserContext.getReaderContext().fatal(
087                                        "Cannot locate BeanDefinitionParser for element [" + localName + "]", element);
088                }
089                return parser;
090        }
091
092        /**
093         * Decorates the supplied {@link Node} by delegating to the {@link BeanDefinitionDecorator} that
094         * is registered to handle that {@link Node}.
095         */
096        @Override
097        @Nullable
098        public BeanDefinitionHolder decorate(
099                        Node node, BeanDefinitionHolder definition, ParserContext parserContext) {
100
101                BeanDefinitionDecorator decorator = findDecoratorForNode(node, parserContext);
102                return (decorator != null ? decorator.decorate(node, definition, parserContext) : null);
103        }
104
105        /**
106         * Locates the {@link BeanDefinitionParser} from the register implementations using
107         * the local name of the supplied {@link Node}. Supports both {@link Element Elements}
108         * and {@link Attr Attrs}.
109         */
110        @Nullable
111        private BeanDefinitionDecorator findDecoratorForNode(Node node, ParserContext parserContext) {
112                BeanDefinitionDecorator decorator = null;
113                String localName = parserContext.getDelegate().getLocalName(node);
114                if (node instanceof Element) {
115                        decorator = this.decorators.get(localName);
116                }
117                else if (node instanceof Attr) {
118                        decorator = this.attributeDecorators.get(localName);
119                }
120                else {
121                        parserContext.getReaderContext().fatal(
122                                        "Cannot decorate based on Nodes of type [" + node.getClass().getName() + "]", node);
123                }
124                if (decorator == null) {
125                        parserContext.getReaderContext().fatal("Cannot locate BeanDefinitionDecorator for " +
126                                        (node instanceof Element ? "element" : "attribute") + " [" + localName + "]", node);
127                }
128                return decorator;
129        }
130
131
132        /**
133         * Subclasses can call this to register the supplied {@link BeanDefinitionParser} to
134         * handle the specified element. The element name is the local (non-namespace qualified)
135         * name.
136         */
137        protected final void registerBeanDefinitionParser(String elementName, BeanDefinitionParser parser) {
138                this.parsers.put(elementName, parser);
139        }
140
141        /**
142         * Subclasses can call this to register the supplied {@link BeanDefinitionDecorator} to
143         * handle the specified element. The element name is the local (non-namespace qualified)
144         * name.
145         */
146        protected final void registerBeanDefinitionDecorator(String elementName, BeanDefinitionDecorator dec) {
147                this.decorators.put(elementName, dec);
148        }
149
150        /**
151         * Subclasses can call this to register the supplied {@link BeanDefinitionDecorator} to
152         * handle the specified attribute. The attribute name is the local (non-namespace qualified)
153         * name.
154         */
155        protected final void registerBeanDefinitionDecoratorForAttribute(String attrName, BeanDefinitionDecorator dec) {
156                this.attributeDecorators.put(attrName, dec);
157        }
158
159}