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