0001: package org.caramba.spring;
0002:
0003: import org.springframework.beans.factory.xml.XmlBeanDefinitionParser;
0004: import org.springframework.beans.factory.xml.NamespaceHandlerResolver;
0005: import org.springframework.beans.factory.xml.DefaultNamespaceHandlerResolver;
0006: import org.springframework.beans.factory.xml.NamespaceHandler;
0007: import org.springframework.beans.factory.xml.BeanDefinitionParser;
0008: import org.springframework.beans.factory.xml.BeanDefinitionDecorator;
0009: import org.springframework.beans.factory.support.BeanDefinitionReader;
0010: import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
0011: import org.springframework.beans.factory.support.AbstractBeanDefinition;
0012: import org.springframework.beans.factory.support.MethodOverrides;
0013: import org.springframework.beans.factory.support.LookupOverride;
0014: import org.springframework.beans.factory.support.ReplaceOverride;
0015: import org.springframework.beans.factory.support.ManagedList;
0016: import org.springframework.beans.factory.support.ManagedSet;
0017: import org.springframework.beans.factory.support.ManagedMap;
0018: import org.springframework.beans.factory.support.ReaderContext;
0019: import org.springframework.beans.factory.BeanDefinitionStoreException;
0020: import org.springframework.beans.factory.config.BeanDefinitionHolder;
0021: import org.springframework.beans.factory.config.BeanDefinition;
0022: import org.springframework.beans.factory.config.ConstructorArgumentValues;
0023: import org.springframework.beans.factory.config.RuntimeBeanReference;
0024: import org.springframework.beans.factory.config.TypedStringValue;
0025: import org.springframework.beans.MutablePropertyValues;
0026: import org.springframework.core.io.Resource;
0027: import org.springframework.core.io.support.ResourcePatternUtils;
0028: import org.springframework.util.SystemPropertyUtils;
0029: import org.springframework.util.StringUtils;
0030: import org.springframework.util.ClassUtils;
0031: import org.springframework.util.xml.DomUtils;
0032: import org.apache.commons.logging.Log;
0033: import org.apache.commons.logging.LogFactory;
0034: import org.w3c.dom.Document;
0035: import org.w3c.dom.Element;
0036: import org.w3c.dom.NodeList;
0037: import org.w3c.dom.Node;
0038:
0039: import java.io.IOException;
0040: import java.util.List;
0041: import java.util.ArrayList;
0042: import java.util.Arrays;
0043: import java.util.Iterator;
0044: import java.util.Set;
0045: import java.util.Map;
0046: import java.util.Properties;
0047:
0048: /*
0049: * Copyright 2002-2005 the original author or authors.
0050: *
0051: * Licensed under the Apache License, Version 2.0 (the "License");
0052: * you may not use this file except in compliance with the License.
0053: * You may obtain a copy of the License at
0054: *
0055: * http://www.apache.org/licenses/LICENSE-2.0
0056: *
0057: * Unless required by applicable law or agreed to in writing, software
0058: * distributed under the License is distributed on an "AS IS" BASIS,
0059: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0060: * See the License for the specific language governing permissions and
0061: * limitations under the License.
0062: */
0063:
0064: /**
0065: * Default implementation of the XmlBeanDefinitionParser interface.
0066: * Parses bean definitions according to the "spring-beans" DTD,
0067: * that is, Spring's default XML bean definition format.
0068: * <p/>
0069: * <p>The structure, elements and attribute names of the required XML document
0070: * are hard-coded in this class. (Of course a transform could be run if necessary
0071: * to produce this format). <code><beans></code> doesn't need to be the root
0072: * element of the XML document: This class will parse all bean definition elements
0073: * in the XML file, not regarding the actual root element.
0074: *
0075: * @author Rod Johnson
0076: * @author Juergen Hoeller
0077: * @author Rob Harrop
0078: * @author Erik Wiersma
0079: * @since 18.12.2003
0080: */
0081: public class SpringNamespaceHelper implements XmlBeanDefinitionParser {
0082:
0083: public static final String BEANS_NAMESPACE_URI = "http://www.springframework.org/schema/beans";
0084:
0085: public static final String BEAN_NAME_DELIMITERS = ",; ";
0086:
0087: /**
0088: * Value of a T/F attribute that represents true.
0089: * Anything else represents false. Case seNsItive.
0090: */
0091: public static final String TRUE_VALUE = "true";
0092: public static final String DEFAULT_VALUE = "default";
0093: public static final String DESCRIPTION_ELEMENT = "description";
0094:
0095: public static final String AUTOWIRE_BY_NAME_VALUE = "byName";
0096: public static final String AUTOWIRE_BY_TYPE_VALUE = "byType";
0097: public static final String AUTOWIRE_CONSTRUCTOR_VALUE = "constructor";
0098: public static final String AUTOWIRE_AUTODETECT_VALUE = "autodetect";
0099:
0100: public static final String DEPENDENCY_CHECK_ALL_ATTRIBUTE_VALUE = "all";
0101: public static final String DEPENDENCY_CHECK_SIMPLE_ATTRIBUTE_VALUE = "simple";
0102: public static final String DEPENDENCY_CHECK_OBJECTS_ATTRIBUTE_VALUE = "objects";
0103:
0104: public static final String DEFAULT_LAZY_INIT_ATTRIBUTE = "default-lazy-init";
0105: public static final String DEFAULT_AUTOWIRE_ATTRIBUTE = "default-autowire";
0106: public static final String DEFAULT_DEPENDENCY_CHECK_ATTRIBUTE = "default-dependency-check";
0107: public static final String DEFAULT_INIT_METHOD_ATTRIBUTE = "default-init-method";
0108: public static final String DEFAULT_DESTROY_METHOD_ATTRIBUTE = "default-destroy-method";
0109:
0110: public static final String IMPORT_ELEMENT = "import";
0111: public static final String RESOURCE_ATTRIBUTE = "resource";
0112:
0113: public static final String ALIAS_ELEMENT = "alias";
0114: public static final String NAME_ATTRIBUTE = "name";
0115: public static final String ALIAS_ATTRIBUTE = "alias";
0116:
0117: public static final String BEAN_ELEMENT = "bean";
0118: public static final String ID_ATTRIBUTE = "id";
0119: public static final String PARENT_ATTRIBUTE = "parent";
0120:
0121: public static final String CLASS_ATTRIBUTE = "class";
0122: public static final String ABSTRACT_ATTRIBUTE = "abstract";
0123: public static final String SINGLETON_ATTRIBUTE = "singleton";
0124: public static final String LAZY_INIT_ATTRIBUTE = "lazy-init";
0125: public static final String AUTOWIRE_ATTRIBUTE = "autowire";
0126: public static final String DEPENDENCY_CHECK_ATTRIBUTE = "dependency-check";
0127: public static final String DEPENDS_ON_ATTRIBUTE = "depends-on";
0128: public static final String INIT_METHOD_ATTRIBUTE = "init-method";
0129: public static final String DESTROY_METHOD_ATTRIBUTE = "destroy-method";
0130: public static final String FACTORY_METHOD_ATTRIBUTE = "factory-method";
0131: public static final String FACTORY_BEAN_ATTRIBUTE = "factory-bean";
0132:
0133: public static final String CONSTRUCTOR_ARG_ELEMENT = "constructor-arg";
0134: public static final String INDEX_ATTRIBUTE = "index";
0135: public static final String TYPE_ATTRIBUTE = "type";
0136: public static final String PROPERTY_ELEMENT = "property";
0137: public static final String REF_ATTRIBUTE = "ref";
0138: public static final String VALUE_ATTRIBUTE = "value";
0139: public static final String LOOKUP_METHOD_ELEMENT = "lookup-method";
0140:
0141: public static final String REPLACED_METHOD_ELEMENT = "replaced-method";
0142: public static final String REPLACER_ATTRIBUTE = "replacer";
0143: public static final String ARG_TYPE_ELEMENT = "arg-type";
0144: public static final String ARG_TYPE_MATCH_ATTRIBUTE = "match";
0145:
0146: public static final String REF_ELEMENT = "ref";
0147: public static final String IDREF_ELEMENT = "idref";
0148: public static final String BEAN_REF_ATTRIBUTE = "bean";
0149: public static final String LOCAL_REF_ATTRIBUTE = "local";
0150: public static final String PARENT_REF_ATTRIBUTE = "parent";
0151:
0152: public static final String VALUE_ELEMENT = "value";
0153: public static final String NULL_ELEMENT = "null";
0154: public static final String LIST_ELEMENT = "list";
0155: public static final String SET_ELEMENT = "set";
0156: public static final String MAP_ELEMENT = "map";
0157: public static final String ENTRY_ELEMENT = "entry";
0158: public static final String KEY_ELEMENT = "key";
0159: public static final String KEY_ATTRIBUTE = "key";
0160: public static final String KEY_REF_ATTRIBUTE = "key-ref";
0161: public static final String VALUE_REF_ATTRIBUTE = "value-ref";
0162: public static final String PROPS_ELEMENT = "props";
0163: public static final String PROP_ELEMENT = "prop";
0164:
0165: protected final Log logger = LogFactory.getLog(getClass());
0166:
0167: private BeanDefinitionReader beanDefinitionReader;
0168:
0169: private NamespaceHandlerResolver namespaceHandlerResolver;
0170:
0171: private Resource resource;
0172:
0173: private String defaultLazyInit;
0174:
0175: private String defaultAutowire;
0176:
0177: private String defaultDependencyCheck;
0178:
0179: private String defaultInitMethod;
0180:
0181: private String defaultDestroyMethod;
0182:
0183: /**
0184: * Parses bean definitions according to the "spring-beans" DTD.
0185: * <p>Opens a DOM Document; then initializes the default settings
0186: * specified at <code><beans></code> level; then parses
0187: * the contained bean definitions.
0188: */
0189: public int registerBeanDefinitions(BeanDefinitionReader reader,
0190: Document doc, Resource resource)
0191: throws BeanDefinitionStoreException {
0192:
0193: this .beanDefinitionReader = reader;
0194: this .resource = resource;
0195:
0196: logger.debug("Loading bean definitions");
0197: Element root = doc.getDocumentElement();
0198:
0199: initDefaults(root);
0200: if (logger.isDebugEnabled()) {
0201: logger.debug("Default lazy init '" + getDefaultLazyInit()
0202: + "'");
0203: logger.debug("Default autowire '" + getDefaultAutowire()
0204: + "'");
0205: logger.debug("Default dependency check '"
0206: + getDefaultDependencyCheck() + "'");
0207: }
0208:
0209: preProcessXml(root);
0210: int beanDefinitionCount = parseBeanDefinitions(root);
0211: if (logger.isDebugEnabled()) {
0212: logger.debug("Found " + beanDefinitionCount
0213: + " <bean> elements in " + resource);
0214: }
0215: postProcessXml(root);
0216:
0217: return beanDefinitionCount;
0218: }
0219:
0220: /**
0221: * Return the BeanDefinitionReader that this parser has been called from.
0222: */
0223: protected final BeanDefinitionReader getBeanDefinitionReader() {
0224: return beanDefinitionReader;
0225: }
0226:
0227: /**
0228: * Return the descriptor for the XML resource that this parser works on.
0229: */
0230: protected final Resource getResource() {
0231: return resource;
0232: }
0233:
0234: /**
0235: * Initialize the default lazy-init, autowire and dependency check settings.
0236: *
0237: * @see #setDefaultLazyInit
0238: * @see #setDefaultAutowire
0239: * @see #setDefaultDependencyCheck
0240: */
0241: protected void initDefaults(Element root) {
0242: setDefaultLazyInit(root
0243: .getAttribute(DEFAULT_LAZY_INIT_ATTRIBUTE));
0244: setDefaultAutowire(root
0245: .getAttribute(DEFAULT_AUTOWIRE_ATTRIBUTE));
0246: setDefaultDependencyCheck(root
0247: .getAttribute(DEFAULT_DEPENDENCY_CHECK_ATTRIBUTE));
0248: if (root.hasAttribute(DEFAULT_INIT_METHOD_ATTRIBUTE)) {
0249: setDefaultInitMethod(root
0250: .getAttribute(DEFAULT_INIT_METHOD_ATTRIBUTE));
0251: }
0252: if (root.hasAttribute(DEFAULT_DESTROY_METHOD_ATTRIBUTE)) {
0253: setDefaultDestroyMethod(root
0254: .getAttribute(DEFAULT_DESTROY_METHOD_ATTRIBUTE));
0255: }
0256: }
0257:
0258: /**
0259: * Set the default lazy-init flag for the document that's currently parsed.
0260: */
0261: protected final void setDefaultLazyInit(String defaultLazyInit) {
0262: this .defaultLazyInit = defaultLazyInit;
0263: }
0264:
0265: /**
0266: * Return the default lazy-init flag for the document that's currently parsed.
0267: */
0268: protected final String getDefaultLazyInit() {
0269: return defaultLazyInit;
0270: }
0271:
0272: /**
0273: * Set the default autowire setting for the document that's currently parsed.
0274: */
0275: protected final void setDefaultAutowire(String defaultAutowire) {
0276: this .defaultAutowire = defaultAutowire;
0277: }
0278:
0279: /**
0280: * Return the default autowire setting for the document that's currently parsed.
0281: */
0282: protected final String getDefaultAutowire() {
0283: return defaultAutowire;
0284: }
0285:
0286: /**
0287: * Set the default dependency-check setting for the document that's currently parsed.
0288: */
0289: protected final void setDefaultDependencyCheck(
0290: String defaultDependencyCheck) {
0291: this .defaultDependencyCheck = defaultDependencyCheck;
0292: }
0293:
0294: /**
0295: * Return the default dependency-check setting for the document that's currently parsed.
0296: */
0297: protected final String getDefaultDependencyCheck() {
0298: return defaultDependencyCheck;
0299: }
0300:
0301: /**
0302: * Set the default dependency-init-method setting for the document that's currently parsed.
0303: */
0304: protected final void setDefaultInitMethod(String defaultInitMethod) {
0305: this .defaultInitMethod = defaultInitMethod;
0306: }
0307:
0308: /**
0309: * Return the default dependency-init-method setting for the document that's currently parsed.
0310: */
0311: protected final String getDefaultInitMethod() {
0312: return defaultInitMethod;
0313: }
0314:
0315: /**
0316: * Set the default dependency-destroy-method setting for the document that's currently parsed.
0317: */
0318: protected final void setDefaultDestroyMethod(
0319: String defaultDestroyMethod) {
0320: this .defaultDestroyMethod = defaultDestroyMethod;
0321: }
0322:
0323: /**
0324: * Return the default dependency-destroy-method setting for the document that's currently parsed.
0325: */
0326: protected final String getDefaultDestroyMethod() {
0327: return defaultDestroyMethod;
0328: }
0329:
0330: /**
0331: * Allow the XML to be extensible by processing any custom element types first,
0332: * before we start to process the bean definitions. This method is a natural
0333: * extension point for any other custom pre-processing of the XML.
0334: * <p>Default implementation is empty. Subclasses can override this method to
0335: * convert custom elements into standard Spring bean definitions, for example.
0336: * Implementors have access to the parser's bean definition reader and the
0337: * underlying XML resource, through the corresponding accessors.
0338: *
0339: * @see #getBeanDefinitionReader()
0340: * @see #getResource()
0341: */
0342: protected void preProcessXml(Element root)
0343: throws BeanDefinitionStoreException {
0344: }
0345:
0346: protected NamespaceHandlerResolver createNamespaceHandlerResolver() {
0347: ClassLoader classLoader = this .beanDefinitionReader
0348: .getBeanClassLoader();
0349: if (classLoader == null) {
0350: classLoader = Thread.currentThread()
0351: .getContextClassLoader();
0352: }
0353: return new DefaultNamespaceHandlerResolver(classLoader);
0354: }
0355:
0356: /**
0357: * Parse the elements at the root level in the document:
0358: * "import", "alias", "bean".
0359: *
0360: * @param root the DOM root element of the document
0361: * @return the number of bean definitions found
0362: */
0363: protected int parseBeanDefinitions(Element root)
0364: throws BeanDefinitionStoreException {
0365: NodeList nl = root.getChildNodes();
0366: int beanDefinitionCount = 0;
0367: for (int i = 0; i < nl.getLength(); i++) {
0368: Node node = nl.item(i);
0369: if (node instanceof Element) {
0370: Element ele = (Element) node;
0371: String namespaceUri = ele.getNamespaceURI();
0372:
0373: if (isDefaultNamespace(namespaceUri)) {
0374: beanDefinitionCount += parseDefaultElement(ele);
0375: } else {
0376: beanDefinitionCount += parseCustomElement(ele);
0377: }
0378: }
0379: }
0380: return beanDefinitionCount;
0381: }
0382:
0383: private boolean isDefaultNamespace(String namespaceUri) {
0384: return namespaceUri == null
0385: || BEANS_NAMESPACE_URI.equals(namespaceUri);
0386: }
0387:
0388: private int parseDefaultElement(Element ele) {
0389: if (IMPORT_ELEMENT.equals(ele.getNodeName())) {
0390: importBeanDefinitionResource(ele);
0391: return 0;
0392: } else if (ALIAS_ELEMENT.equals(ele.getNodeName())) {
0393: String name = ele.getAttribute(NAME_ATTRIBUTE);
0394: String alias = ele.getAttribute(ALIAS_ATTRIBUTE);
0395: this .beanDefinitionReader.getBeanFactory().registerAlias(
0396: name, alias);
0397: return 0;
0398: } else if (BEAN_ELEMENT.equals(ele.getNodeName())) {
0399: BeanDefinitionHolder bdHolder = parseBeanDefinitionElement(
0400: ele, false);
0401: return decorateAndRegisterBeanDefinition(ele, bdHolder);
0402: } else {
0403: // non-important element
0404: return 0;
0405: }
0406: }
0407:
0408: protected int parseCustomElement(Element ele) {
0409: String namespaceUri = ele.getNamespaceURI();
0410: NamespaceHandler handler = getNamespaceHandlerResolver()
0411: .resolve(namespaceUri);
0412:
0413: if (handler == null) {
0414: throw new BeanDefinitionStoreException(
0415: "Unable to locate NamespaceHandler for namespace ["
0416: + namespaceUri + "].");
0417: }
0418: int countBefore = getBeanDefinitionCount();
0419: BeanDefinitionParser parser = handler.findParserForElement(ele);
0420: // PDG parser.parse(ele, this.beanDefinitionReader.getBeanFactory());
0421: return (getBeanDefinitionCount() - countBefore);
0422: }
0423:
0424: private NamespaceHandlerResolver getNamespaceHandlerResolver() {
0425: if (this .namespaceHandlerResolver == null) {
0426: this .namespaceHandlerResolver = createNamespaceHandlerResolver();
0427: }
0428: return this .namespaceHandlerResolver;
0429: }
0430:
0431: private int decorateAndRegisterBeanDefinition(Element element,
0432: BeanDefinitionHolder definitionHolder) {
0433: int registeredCount = 1;
0434: BeanDefinitionHolder rootDefinition = definitionHolder;
0435:
0436: NodeList children = element.getChildNodes();
0437: for (int i = 0; i < children.getLength(); i++) {
0438: Node node = children.item(i);
0439: String uri = node.getNamespaceURI();
0440: if (node.getNodeType() == Node.ELEMENT_NODE
0441: && !isDefaultNamespace(uri)) {
0442: Element childElement = (Element) node;
0443: // a node from a namespace outside of the standard - should map to a decorator
0444: NamespaceHandler handler = getNamespaceHandlerResolver()
0445: .resolve(uri);
0446: BeanDefinitionDecorator decorator = handler
0447: .findDecoratorForElement(childElement);
0448: int countBefore = getBeanDefinitionCount();
0449: // PDG rootDefinition = decorator.decorate(childElement, rootDefinition, this.beanDefinitionReader.getBeanFactory());
0450: registeredCount += (getBeanDefinitionCount() - countBefore);
0451: }
0452: }
0453: // register the final decorated instance
0454: BeanDefinitionReaderUtils.registerBeanDefinition(
0455: rootDefinition, this .beanDefinitionReader
0456: .getBeanFactory());
0457: return registeredCount;
0458: }
0459:
0460: private int getBeanDefinitionCount() {
0461: return this .beanDefinitionReader.getBeanFactory()
0462: .getBeanDefinitionCount();
0463: }
0464:
0465: /**
0466: * Parse an "import" element and load the bean definitions
0467: * from the given resource into the bean factory.
0468: */
0469: protected void importBeanDefinitionResource(Element ele)
0470: throws BeanDefinitionStoreException {
0471: String location = ele.getAttribute(RESOURCE_ATTRIBUTE);
0472: // Resolve system properties: e.g. "${user.dir}"
0473: location = SystemPropertyUtils.resolvePlaceholders(location);
0474:
0475: if (ResourcePatternUtils.isUrl(location)) {
0476: int importCount = getBeanDefinitionReader()
0477: .loadBeanDefinitions(location);
0478: if (logger.isDebugEnabled()) {
0479: logger.debug("Imported " + importCount
0480: + " bean definitions from URL location ["
0481: + location + "]");
0482: }
0483: } else {
0484: // No URL -> considering resource location as relative to the current file.
0485: try {
0486: Resource relativeResource = getResource()
0487: .createRelative(location);
0488: int importCount = getBeanDefinitionReader()
0489: .loadBeanDefinitions(relativeResource);
0490: if (logger.isDebugEnabled()) {
0491: logger
0492: .debug("Imported "
0493: + importCount
0494: + " bean definitions from relative location ["
0495: + location + "]");
0496: }
0497: } catch (IOException ex) {
0498: throw new BeanDefinitionStoreException(
0499: "Invalid relative resource location ["
0500: + location
0501: + "] to import bean definitions from",
0502: ex);
0503: }
0504: }
0505: }
0506:
0507: /**
0508: * Allow the XML to be extensible by processing any custom element types last,
0509: * after we finished processing the bean definitions. This method is a natural
0510: * extension point for any other custom post-processing of the XML.
0511: * <p>Default implementation is empty. Subclasses can override this method to
0512: * convert custom elements into standard Spring bean definitions, for example.
0513: * Implementors have access to the parser's bean definition reader and the
0514: * underlying XML resource, through the corresponding accessors.
0515: *
0516: * @see #getBeanDefinitionReader()
0517: * @see #getResource()
0518: */
0519: protected void postProcessXml(Element root)
0520: throws BeanDefinitionStoreException {
0521: }
0522:
0523: /**
0524: * Parse a standard bean definition into a BeanDefinitionHolder,
0525: * including bean name and aliases.
0526: * <p>Bean elements specify their canonical name as "id" attribute
0527: * and their aliases as a delimited "name" attribute.
0528: * <p>If no "id" specified, uses the first name in the "name" attribute
0529: * as canonical name, registering all others as aliases.
0530: * <p>Callers should specify whether this element represents an inner bean
0531: * definition or not by setting the <code>isInnerBean</code> argument appropriately
0532: */
0533: protected BeanDefinitionHolder parseBeanDefinitionElement(
0534: Element ele, boolean isInnerBean)
0535: throws BeanDefinitionStoreException {
0536:
0537: String id = ele.getAttribute(ID_ATTRIBUTE);
0538: String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
0539:
0540: List aliases = new ArrayList();
0541: if (StringUtils.hasLength(nameAttr)) {
0542: String[] nameArr = StringUtils.tokenizeToStringArray(
0543: nameAttr, BEAN_NAME_DELIMITERS);
0544: aliases.addAll(Arrays.asList(nameArr));
0545: }
0546:
0547: String beanName = id;
0548: if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
0549: beanName = (String) aliases.remove(0);
0550: if (logger.isDebugEnabled()) {
0551: logger.debug("No XML 'id' specified - using '"
0552: + beanName + "' as bean name and " + aliases
0553: + " as aliases");
0554: }
0555: }
0556:
0557: BeanDefinition beanDefinition = parseBeanDefinitionElement(ele,
0558: beanName);
0559:
0560: if (!StringUtils.hasText(beanName)
0561: && beanDefinition instanceof AbstractBeanDefinition) {
0562: beanName = BeanDefinitionReaderUtils.generateBeanName(
0563: (AbstractBeanDefinition) beanDefinition,
0564: this .beanDefinitionReader.getBeanFactory(),
0565: isInnerBean);
0566: if (logger.isDebugEnabled()) {
0567: logger.debug("Neither XML 'id' nor 'name' specified - "
0568: + "using generated bean name [" + beanName
0569: + "]");
0570: }
0571: }
0572:
0573: String[] aliasesArray = (String[]) aliases
0574: .toArray(new String[aliases.size()]);
0575: return new BeanDefinitionHolder(beanDefinition, beanName,
0576: aliasesArray);
0577: }
0578:
0579: /**
0580: * Parse the BeanDefinition itself, without regard to name or aliases.
0581: */
0582: protected BeanDefinition parseBeanDefinitionElement(Element ele,
0583: String beanName) throws BeanDefinitionStoreException {
0584:
0585: String className = null;
0586: if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
0587: className = ele.getAttribute(CLASS_ATTRIBUTE);
0588: }
0589: String parent = null;
0590: if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
0591: parent = ele.getAttribute(PARENT_ATTRIBUTE);
0592: }
0593:
0594: try {
0595: ConstructorArgumentValues cargs = parseConstructorArgElements(
0596: ele, beanName);
0597: MutablePropertyValues pvs = parsePropertyElements(ele,
0598: beanName);
0599:
0600: AbstractBeanDefinition bd = BeanDefinitionReaderUtils
0601: .createBeanDefinition(className, parent, cargs,
0602: pvs, getBeanDefinitionReader()
0603: .getBeanClassLoader());
0604:
0605: if (ele.hasAttribute(DEPENDS_ON_ATTRIBUTE)) {
0606: String dependsOn = ele
0607: .getAttribute(DEPENDS_ON_ATTRIBUTE);
0608: bd.setDependsOn(StringUtils.tokenizeToStringArray(
0609: dependsOn, BEAN_NAME_DELIMITERS));
0610: }
0611:
0612: if (ele.hasAttribute(FACTORY_METHOD_ATTRIBUTE)) {
0613: bd.setFactoryMethodName(ele
0614: .getAttribute(FACTORY_METHOD_ATTRIBUTE));
0615: }
0616: if (ele.hasAttribute(FACTORY_BEAN_ATTRIBUTE)) {
0617: bd.setFactoryBeanName(ele
0618: .getAttribute(FACTORY_BEAN_ATTRIBUTE));
0619: }
0620:
0621: String dependencyCheck = ele
0622: .getAttribute(DEPENDENCY_CHECK_ATTRIBUTE);
0623: if (DEFAULT_VALUE.equals(dependencyCheck)) {
0624: dependencyCheck = getDefaultDependencyCheck();
0625: }
0626: bd.setDependencyCheck(getDependencyCheck(dependencyCheck));
0627:
0628: String autowire = ele.getAttribute(AUTOWIRE_ATTRIBUTE);
0629: if (DEFAULT_VALUE.equals(autowire)) {
0630: autowire = getDefaultAutowire();
0631: }
0632: bd.setAutowireMode(getAutowireMode(autowire));
0633:
0634: if (ele.hasAttribute(INIT_METHOD_ATTRIBUTE)) {
0635: String initMethodName = ele
0636: .getAttribute(INIT_METHOD_ATTRIBUTE);
0637: if (!"".equals(initMethodName)) {
0638: bd.setInitMethodName(initMethodName);
0639: }
0640: } else {
0641: if (getDefaultInitMethod() != null) {
0642: bd.setInitMethodName(getDefaultInitMethod());
0643: bd.setEnforceInitMethod(false);
0644: }
0645: }
0646:
0647: if (ele.hasAttribute(DESTROY_METHOD_ATTRIBUTE)) {
0648: String destroyMethodName = ele
0649: .getAttribute(DESTROY_METHOD_ATTRIBUTE);
0650: if (!"".equals(destroyMethodName)) {
0651: bd.setDestroyMethodName(destroyMethodName);
0652: }
0653: } else {
0654: if (getDefaultDestroyMethod() != null) {
0655: bd.setDestroyMethodName(getDefaultDestroyMethod());
0656: bd.setEnforceDestroyMethod(false);
0657: }
0658: }
0659:
0660: parseLookupOverrideSubElements(ele, beanName, bd
0661: .getMethodOverrides());
0662: parseReplacedMethodSubElements(ele, beanName, bd
0663: .getMethodOverrides());
0664:
0665: bd.setResourceDescription(getResource().getDescription());
0666:
0667: if (ele.hasAttribute(ABSTRACT_ATTRIBUTE)) {
0668: bd.setAbstract(TRUE_VALUE.equals(ele
0669: .getAttribute(ABSTRACT_ATTRIBUTE)));
0670: }
0671:
0672: if (ele.hasAttribute(SINGLETON_ATTRIBUTE)) {
0673: bd.setSingleton(TRUE_VALUE.equals(ele
0674: .getAttribute(SINGLETON_ATTRIBUTE)));
0675: }
0676:
0677: String lazyInit = ele.getAttribute(LAZY_INIT_ATTRIBUTE);
0678: if (DEFAULT_VALUE.equals(lazyInit) && bd.isSingleton()) {
0679: // Just apply default to singletons, as lazy-init has no meaning for prototypes.
0680: lazyInit = getDefaultLazyInit();
0681: }
0682: bd.setLazyInit(TRUE_VALUE.equals(lazyInit));
0683:
0684: return bd;
0685: } catch (ClassNotFoundException ex) {
0686: throw new BeanDefinitionStoreException(getResource(),
0687: beanName, "Bean class [" + className
0688: + "] not found", ex);
0689: } catch (NoClassDefFoundError err) {
0690: throw new BeanDefinitionStoreException(getResource(),
0691: beanName, "Class that bean class [" + className
0692: + "] depends on not found", err);
0693: }
0694: }
0695:
0696: protected int getDependencyCheck(String att) {
0697: int dependencyCheckCode = AbstractBeanDefinition.DEPENDENCY_CHECK_NONE;
0698: if (DEPENDENCY_CHECK_ALL_ATTRIBUTE_VALUE.equals(att)) {
0699: dependencyCheckCode = AbstractBeanDefinition.DEPENDENCY_CHECK_ALL;
0700: } else if (DEPENDENCY_CHECK_SIMPLE_ATTRIBUTE_VALUE.equals(att)) {
0701: dependencyCheckCode = AbstractBeanDefinition.DEPENDENCY_CHECK_SIMPLE;
0702: } else if (DEPENDENCY_CHECK_OBJECTS_ATTRIBUTE_VALUE.equals(att)) {
0703: dependencyCheckCode = AbstractBeanDefinition.DEPENDENCY_CHECK_OBJECTS;
0704: }
0705: // Else leave default value.
0706: return dependencyCheckCode;
0707: }
0708:
0709: protected int getAutowireMode(String att) {
0710: int autowire = AbstractBeanDefinition.AUTOWIRE_NO;
0711: if (AUTOWIRE_BY_NAME_VALUE.equals(att)) {
0712: autowire = AbstractBeanDefinition.AUTOWIRE_BY_NAME;
0713: } else if (AUTOWIRE_BY_TYPE_VALUE.equals(att)) {
0714: autowire = AbstractBeanDefinition.AUTOWIRE_BY_TYPE;
0715: } else if (AUTOWIRE_CONSTRUCTOR_VALUE.equals(att)) {
0716: autowire = AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR;
0717: } else if (AUTOWIRE_AUTODETECT_VALUE.equals(att)) {
0718: autowire = AbstractBeanDefinition.AUTOWIRE_AUTODETECT;
0719: }
0720: // Else leave default value.
0721: return autowire;
0722: }
0723:
0724: /**
0725: * Parse constructor-arg sub-elements of the given bean element.
0726: */
0727: protected ConstructorArgumentValues parseConstructorArgElements(
0728: Element beanEle, String beanName)
0729: throws BeanDefinitionStoreException {
0730:
0731: NodeList nl = beanEle.getChildNodes();
0732: ConstructorArgumentValues cargs = new ConstructorArgumentValues();
0733: for (int i = 0; i < nl.getLength(); i++) {
0734: Node node = nl.item(i);
0735: if (node instanceof Element
0736: && CONSTRUCTOR_ARG_ELEMENT.equals(node
0737: .getNodeName())) {
0738: parseConstructorArgElement((Element) node, beanName,
0739: cargs);
0740: }
0741: }
0742: return cargs;
0743: }
0744:
0745: /**
0746: * Parse property sub-elements of the given bean element.
0747: */
0748: public MutablePropertyValues parsePropertyElements(Element beanEle,
0749: String beanName) throws BeanDefinitionStoreException {
0750:
0751: NodeList nl = beanEle.getChildNodes();
0752: MutablePropertyValues pvs = new MutablePropertyValues();
0753: for (int i = 0; i < nl.getLength(); i++) {
0754: Node node = nl.item(i);
0755: if (node instanceof Element
0756: && PROPERTY_ELEMENT.equals(node.getNodeName())) {
0757: parsePropertyElement((Element) node, beanName, pvs);
0758: }
0759: }
0760: return pvs;
0761: }
0762:
0763: /**
0764: * Parse lookup-override sub-elements of the given bean element.
0765: */
0766: protected void parseLookupOverrideSubElements(Element beanEle,
0767: String beanName, MethodOverrides overrides)
0768: throws BeanDefinitionStoreException {
0769:
0770: NodeList nl = beanEle.getChildNodes();
0771: for (int i = 0; i < nl.getLength(); i++) {
0772: Node node = nl.item(i);
0773: if (node instanceof Element
0774: && LOOKUP_METHOD_ELEMENT.equals(node.getNodeName())) {
0775: Element ele = (Element) node;
0776: String methodName = ele.getAttribute(NAME_ATTRIBUTE);
0777: String beanRef = ele.getAttribute(BEAN_ELEMENT);
0778: overrides.addOverride(new LookupOverride(methodName,
0779: beanRef));
0780: }
0781: }
0782: }
0783:
0784: /**
0785: * Parse replaced-method sub-elements of the given bean element.
0786: */
0787: protected void parseReplacedMethodSubElements(Element beanEle,
0788: String beanName, MethodOverrides overrides)
0789: throws BeanDefinitionStoreException {
0790:
0791: NodeList nl = beanEle.getChildNodes();
0792: for (int i = 0; i < nl.getLength(); i++) {
0793: Node node = nl.item(i);
0794: if (node instanceof Element
0795: && REPLACED_METHOD_ELEMENT.equals(node
0796: .getNodeName())) {
0797: Element replacedMethodEle = (Element) node;
0798: String name = replacedMethodEle
0799: .getAttribute(NAME_ATTRIBUTE);
0800: String callback = replacedMethodEle
0801: .getAttribute(REPLACER_ATTRIBUTE);
0802: ReplaceOverride replaceOverride = new ReplaceOverride(
0803: name, callback);
0804: // Look for arg-type match elements.
0805: List argTypeEles = DomUtils.getChildElementsByTagName(
0806: replacedMethodEle, ARG_TYPE_ELEMENT);
0807: for (Iterator it = argTypeEles.iterator(); it.hasNext();) {
0808: Element argTypeEle = (Element) it.next();
0809: replaceOverride.addTypeIdentifier(argTypeEle
0810: .getAttribute(ARG_TYPE_MATCH_ATTRIBUTE));
0811: }
0812: overrides.addOverride(replaceOverride);
0813: }
0814: }
0815: }
0816:
0817: /**
0818: * Parse a constructor-arg element.
0819: */
0820: protected void parseConstructorArgElement(Element ele,
0821: String beanName, ConstructorArgumentValues cargs)
0822: throws BeanDefinitionStoreException {
0823:
0824: Object val = parsePropertyValue(ele, beanName, null);
0825: String indexAttr = ele.getAttribute(INDEX_ATTRIBUTE);
0826: String typeAttr = ele.getAttribute(TYPE_ATTRIBUTE);
0827: if (StringUtils.hasLength(indexAttr)) {
0828: try {
0829: int index = Integer.parseInt(indexAttr);
0830: if (index < 0) {
0831: throw new BeanDefinitionStoreException(
0832: getResource(), beanName,
0833: "'index' cannot be lower than 0");
0834: }
0835: if (StringUtils.hasLength(typeAttr)) {
0836: cargs.addIndexedArgumentValue(index, val, typeAttr);
0837: } else {
0838: cargs.addIndexedArgumentValue(index, val);
0839: }
0840: } catch (NumberFormatException ex) {
0841: throw new BeanDefinitionStoreException(getResource(),
0842: beanName,
0843: "Attribute 'index' of tag 'constructor-arg' must be an integer");
0844: }
0845: } else {
0846: if (StringUtils.hasLength(typeAttr)) {
0847: cargs.addGenericArgumentValue(val, typeAttr);
0848: } else {
0849: cargs.addGenericArgumentValue(val);
0850: }
0851: }
0852: }
0853:
0854: /**
0855: * Parse a property element.
0856: */
0857: protected void parsePropertyElement(Element ele, String beanName,
0858: MutablePropertyValues pvs)
0859: throws BeanDefinitionStoreException {
0860:
0861: String propertyName = ele.getAttribute(NAME_ATTRIBUTE);
0862: if (!StringUtils.hasLength(propertyName)) {
0863: throw new BeanDefinitionStoreException(getResource(),
0864: beanName,
0865: "Tag 'property' must have a 'name' attribute");
0866: }
0867: if (pvs.contains(propertyName)) {
0868: throw new BeanDefinitionStoreException(getResource(),
0869: beanName,
0870: "Multiple 'property' definitions for property '"
0871: + propertyName + "'");
0872: }
0873: Object val = parsePropertyValue(ele, beanName, propertyName);
0874: pvs.addPropertyValue(propertyName, val);
0875: }
0876:
0877: /**
0878: * Get the value of a property element. May be a list etc.
0879: * Also used for constructor arguments, "propertyName" being null in this case.
0880: */
0881: protected Object parsePropertyValue(Element ele, String beanName,
0882: String propertyName) throws BeanDefinitionStoreException {
0883:
0884: String elementName = (propertyName != null) ? "<property> element for property '"
0885: + propertyName + "'"
0886: : "<constructor-arg> element";
0887:
0888: // Should only have one child element: ref, value, list, etc.
0889: NodeList nl = ele.getChildNodes();
0890: Element subElement = null;
0891: for (int i = 0; i < nl.getLength(); i++) {
0892: if (nl.item(i) instanceof Element) {
0893: Element candidateEle = (Element) nl.item(i);
0894: if (DESCRIPTION_ELEMENT.equals(candidateEle
0895: .getTagName())) {
0896: // Keep going: we don't use this value for now.
0897: } else {
0898: // Child element is what we're looking for.
0899: if (subElement != null) {
0900: throw new BeanDefinitionStoreException(
0901: getResource(),
0902: beanName,
0903: elementName
0904: + " must not contain more than one sub-element");
0905: }
0906: subElement = candidateEle;
0907: }
0908: }
0909: }
0910:
0911: boolean hasRefAttribute = ele.hasAttribute(REF_ATTRIBUTE);
0912: boolean hasValueAttribute = ele.hasAttribute(VALUE_ATTRIBUTE);
0913: if ((hasRefAttribute && hasValueAttribute)
0914: || ((hasRefAttribute || hasValueAttribute))
0915: && subElement != null) {
0916: throw new BeanDefinitionStoreException(
0917: getResource(),
0918: beanName,
0919: elementName
0920: + " is only allowed to contain either a 'ref' attribute OR a 'value' attribute OR a sub-element");
0921: }
0922: if (hasRefAttribute) {
0923: return new RuntimeBeanReference(ele
0924: .getAttribute(REF_ATTRIBUTE));
0925: } else if (hasValueAttribute) {
0926: return ele.getAttribute(VALUE_ATTRIBUTE);
0927: }
0928:
0929: if (subElement == null) {
0930: // Neither child element nor "ref" or "value" attribute found.
0931: throw new BeanDefinitionStoreException(getResource(),
0932: beanName, elementName
0933: + " must specify a ref or value");
0934: }
0935:
0936: return parsePropertySubElement(subElement, beanName);
0937: }
0938:
0939: /**
0940: * Parse a value, ref or collection sub-element of a property or
0941: * constructor-arg element.
0942: *
0943: * @param ele subelement of property element; we don't know which yet
0944: */
0945: public Object parsePropertySubElement(Element ele, String beanName)
0946: throws BeanDefinitionStoreException {
0947: if (ele.getTagName().equals(BEAN_ELEMENT)) {
0948: return parseBeanDefinitionElement(ele, true);
0949: } else if (ele.getTagName().equals(REF_ELEMENT)) {
0950: // A generic reference to any name of any bean.
0951: String beanRef = ele.getAttribute(BEAN_REF_ATTRIBUTE);
0952: if (!StringUtils.hasLength(beanRef)) {
0953: // A reference to the id of another bean in the same XML file.
0954: beanRef = ele.getAttribute(LOCAL_REF_ATTRIBUTE);
0955: if (!StringUtils.hasLength(beanRef)) {
0956: // A reference to the id of another bean in a parent context.
0957: beanRef = ele.getAttribute(PARENT_REF_ATTRIBUTE);
0958: if (!StringUtils.hasLength(beanRef)) {
0959: throw new BeanDefinitionStoreException(
0960: getResource(), beanName,
0961: "'bean', 'local' or 'parent' is required for a reference");
0962: }
0963: return new RuntimeBeanReference(beanRef, true);
0964: }
0965: }
0966: return new RuntimeBeanReference(beanRef);
0967: } else if (ele.getTagName().equals(IDREF_ELEMENT)) {
0968: // A generic reference to any name of any bean.
0969: String beanRef = ele.getAttribute(BEAN_REF_ATTRIBUTE);
0970: if (!StringUtils.hasLength(beanRef)) {
0971: // A reference to the id of another bean in the same XML file.
0972: beanRef = ele.getAttribute(LOCAL_REF_ATTRIBUTE);
0973: if (!StringUtils.hasLength(beanRef)) {
0974: throw new BeanDefinitionStoreException(
0975: getResource(), beanName,
0976: "Either 'bean' or 'local' is required for an idref");
0977: }
0978: }
0979: return beanRef;
0980: } else if (ele.getTagName().equals(VALUE_ELEMENT)) {
0981: // It's a literal value.
0982: String value = DomUtils.getTextValue(ele);
0983: if (ele.hasAttribute(TYPE_ATTRIBUTE)) {
0984: String typeClassName = ele.getAttribute(TYPE_ATTRIBUTE);
0985: try {
0986: Class typeClass = ClassUtils.forName(typeClassName,
0987: this .beanDefinitionReader
0988: .getBeanClassLoader());
0989: return new TypedStringValue(value, typeClass);
0990: } catch (ClassNotFoundException ex) {
0991: throw new BeanDefinitionStoreException(
0992: getResource(), beanName,
0993: "Value type class [" + typeClassName
0994: + "] not found", ex);
0995: }
0996: }
0997: return value;
0998: } else if (ele.getTagName().equals(NULL_ELEMENT)) {
0999: // It's a distinguished null value.
1000: return null;
1001: } else if (ele.getTagName().equals(LIST_ELEMENT)) {
1002: return parseListElement(ele, beanName);
1003: } else if (ele.getTagName().equals(SET_ELEMENT)) {
1004: return parseSetElement(ele, beanName);
1005: } else if (ele.getTagName().equals(MAP_ELEMENT)) {
1006: return parseMapElement(ele, beanName);
1007: } else if (ele.getTagName().equals(PROPS_ELEMENT)) {
1008: return parsePropsElement(ele, beanName);
1009: }
1010: throw new BeanDefinitionStoreException(getResource(), beanName,
1011: "Unknown property sub-element: <" + ele.getTagName()
1012: + ">");
1013: }
1014:
1015: /**
1016: * Parse a list element.
1017: */
1018: protected List parseListElement(Element collectionEle,
1019: String beanName) throws BeanDefinitionStoreException {
1020: NodeList nl = collectionEle.getChildNodes();
1021: ManagedList list = new ManagedList(nl.getLength());
1022: for (int i = 0; i < nl.getLength(); i++) {
1023: if (nl.item(i) instanceof Element) {
1024: Element ele = (Element) nl.item(i);
1025: list.add(parsePropertySubElement(ele, beanName));
1026: }
1027: }
1028: return list;
1029: }
1030:
1031: /**
1032: * Parse a set element.
1033: */
1034: protected Set parseSetElement(Element collectionEle, String beanName)
1035: throws BeanDefinitionStoreException {
1036: NodeList nl = collectionEle.getChildNodes();
1037: ManagedSet set = new ManagedSet(nl.getLength());
1038: for (int i = 0; i < nl.getLength(); i++) {
1039: if (nl.item(i) instanceof Element) {
1040: Element ele = (Element) nl.item(i);
1041: set.add(parsePropertySubElement(ele, beanName));
1042: }
1043: }
1044: return set;
1045: }
1046:
1047: /**
1048: * Parse a map element.
1049: */
1050: protected Map parseMapElement(Element mapEle, String beanName)
1051: throws BeanDefinitionStoreException {
1052: List entryEles = DomUtils.getChildElementsByTagName(mapEle,
1053: ENTRY_ELEMENT);
1054: Map map = new ManagedMap(entryEles.size());
1055:
1056: for (Iterator it = entryEles.iterator(); it.hasNext();) {
1057: Element entryEle = (Element) it.next();
1058: // Should only have one value child element: ref, value, list, etc.
1059: // Optionally, there might be a key child element.
1060: NodeList entrySubNodes = entryEle.getChildNodes();
1061:
1062: Element keyEle = null;
1063: Element valueEle = null;
1064: for (int j = 0; j < entrySubNodes.getLength(); j++) {
1065: if (entrySubNodes.item(j) instanceof Element) {
1066: Element candidateEle = (Element) entrySubNodes
1067: .item(j);
1068: if (candidateEle.getTagName().equals(KEY_ELEMENT)) {
1069: if (keyEle != null) {
1070: throw new BeanDefinitionStoreException(
1071: getResource(), beanName,
1072: "<entry> is only allowed to contain one <key> sub-element");
1073: }
1074: keyEle = candidateEle;
1075: } else {
1076: // Child element is what we're looking for.
1077: if (valueEle != null) {
1078: throw new BeanDefinitionStoreException(
1079: getResource(), beanName,
1080: "<entry> must not contain more than one value sub-element");
1081: }
1082: valueEle = candidateEle;
1083: }
1084: }
1085: }
1086:
1087: // Extract key from attribute or sub-element.
1088: Object key = null;
1089: boolean hasKeyAttribute = entryEle
1090: .hasAttribute(KEY_ATTRIBUTE);
1091: boolean hasKeyRefAttribute = entryEle
1092: .hasAttribute(KEY_REF_ATTRIBUTE);
1093: if ((hasKeyAttribute && hasKeyRefAttribute)
1094: || ((hasKeyAttribute || hasKeyRefAttribute))
1095: && keyEle != null) {
1096: throw new BeanDefinitionStoreException(
1097: getResource(),
1098: beanName,
1099: "<entry> is only allowed to contain either "
1100: + "a 'key' attribute OR a 'key-ref' attribute OR a <key> sub-element");
1101: }
1102: if (hasKeyAttribute) {
1103: key = entryEle.getAttribute(KEY_ATTRIBUTE);
1104: } else if (hasKeyRefAttribute) {
1105: key = new RuntimeBeanReference(entryEle
1106: .getAttribute(KEY_REF_ATTRIBUTE));
1107: } else if (keyEle != null) {
1108: key = parseKeyElement(keyEle, beanName);
1109: } else {
1110: throw new BeanDefinitionStoreException(getResource(),
1111: beanName, "<entry> must specify a key");
1112: }
1113:
1114: // Extract value from attribute or sub-element.
1115: Object value = null;
1116: boolean hasValueAttribute = entryEle
1117: .hasAttribute(VALUE_ATTRIBUTE);
1118: boolean hasValueRefAttribute = entryEle
1119: .hasAttribute(VALUE_REF_ATTRIBUTE);
1120: if ((hasValueAttribute && hasValueRefAttribute)
1121: || ((hasValueAttribute || hasValueRefAttribute))
1122: && valueEle != null) {
1123: throw new BeanDefinitionStoreException(
1124: getResource(),
1125: beanName,
1126: "<entry> is only allowed to contain either "
1127: + "a 'value' attribute OR a 'value-ref' attribute OR a value sub-element");
1128: }
1129: if (hasValueAttribute) {
1130: value = entryEle.getAttribute(VALUE_ATTRIBUTE);
1131: } else if (hasValueRefAttribute) {
1132: value = new RuntimeBeanReference(entryEle
1133: .getAttribute(VALUE_REF_ATTRIBUTE));
1134: } else if (valueEle != null) {
1135: value = parsePropertySubElement(valueEle, beanName);
1136: } else {
1137: throw new BeanDefinitionStoreException(getResource(),
1138: beanName, "<entry> must specify a value");
1139: }
1140:
1141: // Add final key and value to the Map.
1142: map.put(key, value);
1143: }
1144:
1145: return map;
1146: }
1147:
1148: /**
1149: * Parse a key sub-element of a map element.
1150: */
1151: protected Object parseKeyElement(Element keyEle, String beanName)
1152: throws BeanDefinitionStoreException {
1153: NodeList nl = keyEle.getChildNodes();
1154: Element subElement = null;
1155: for (int i = 0; i < nl.getLength(); i++) {
1156: if (nl.item(i) instanceof Element) {
1157: Element candidateEle = (Element) nl.item(i);
1158: // Child element is what we're looking for.
1159: if (subElement != null) {
1160: throw new BeanDefinitionStoreException(
1161: getResource(), beanName,
1162: "<key> must not contain more than one value sub-element");
1163: }
1164: subElement = candidateEle;
1165: }
1166: }
1167: return parsePropertySubElement(subElement, beanName);
1168: }
1169:
1170: /**
1171: * Parse a props element.
1172: */
1173: protected Properties parsePropsElement(Element propsEle,
1174: String beanName) throws BeanDefinitionStoreException {
1175: Properties props = new Properties();
1176: List propEles = DomUtils.getChildElementsByTagName(propsEle,
1177: PROP_ELEMENT);
1178: for (Iterator it = propEles.iterator(); it.hasNext();) {
1179: Element propEle = (Element) it.next();
1180: String key = propEle.getAttribute(KEY_ATTRIBUTE);
1181: // Trim the text value to avoid unwanted whitespace
1182: // caused by typical XML formatting.
1183: String value = DomUtils.getTextValue(propEle).trim();
1184: props.setProperty(key, value);
1185: }
1186: return props;
1187: }
1188:
1189: public void registerBeanDefinitions(Document pDocument,
1190: ReaderContext pReaderContext)
1191: throws BeanDefinitionStoreException {
1192: }
1193: }
|