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}