0001: /*
0002: * Copyright 2002-2007 the original author or authors.
0003: *
0004: * Licensed under the Apache License, Version 2.0 (the "License");
0005: * you may not use this file except in compliance with the License.
0006: * You may obtain a copy of the License at
0007: *
0008: * http://www.apache.org/licenses/LICENSE-2.0
0009: *
0010: * Unless required by applicable law or agreed to in writing, software
0011: * distributed under the License is distributed on an "AS IS" BASIS,
0012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0013: * See the License for the specific language governing permissions and
0014: * limitations under the License.
0015: */
0016:
0017: package org.springframework.beans.factory.xml;
0018:
0019: import java.util.ArrayList;
0020: import java.util.Arrays;
0021: import java.util.HashSet;
0022: import java.util.Iterator;
0023: import java.util.List;
0024: import java.util.Map;
0025: import java.util.Properties;
0026: import java.util.Set;
0027:
0028: import org.apache.commons.logging.Log;
0029: import org.apache.commons.logging.LogFactory;
0030: import org.w3c.dom.Element;
0031: import org.w3c.dom.NamedNodeMap;
0032: import org.w3c.dom.Node;
0033: import org.w3c.dom.NodeList;
0034:
0035: import org.springframework.beans.PropertyValue;
0036: import org.springframework.beans.factory.BeanDefinitionStoreException;
0037: import org.springframework.beans.factory.config.BeanDefinition;
0038: import org.springframework.beans.factory.config.BeanDefinitionHolder;
0039: import org.springframework.beans.factory.config.ConstructorArgumentValues;
0040: import org.springframework.beans.factory.config.RuntimeBeanNameReference;
0041: import org.springframework.beans.factory.config.RuntimeBeanReference;
0042: import org.springframework.beans.factory.config.TypedStringValue;
0043: import org.springframework.beans.factory.parsing.BeanEntry;
0044: import org.springframework.beans.factory.parsing.ConstructorArgumentEntry;
0045: import org.springframework.beans.factory.parsing.ParseState;
0046: import org.springframework.beans.factory.parsing.PropertyEntry;
0047: import org.springframework.beans.factory.support.AbstractBeanDefinition;
0048: import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
0049: import org.springframework.beans.factory.support.LookupOverride;
0050: import org.springframework.beans.factory.support.ManagedList;
0051: import org.springframework.beans.factory.support.ManagedMap;
0052: import org.springframework.beans.factory.support.ManagedProperties;
0053: import org.springframework.beans.factory.support.ManagedSet;
0054: import org.springframework.beans.factory.support.MethodOverrides;
0055: import org.springframework.beans.factory.support.ReplaceOverride;
0056: import org.springframework.core.AttributeAccessor;
0057: import org.springframework.util.Assert;
0058: import org.springframework.util.ClassUtils;
0059: import org.springframework.util.CollectionUtils;
0060: import org.springframework.util.ObjectUtils;
0061: import org.springframework.util.StringUtils;
0062: import org.springframework.util.xml.DomUtils;
0063:
0064: /**
0065: * Stateful delegate class used to parse XML bean definitions.
0066: * Intended for use by both the main parser and any extension
0067: * {@link BeanDefinitionParser BeanDefinitionParsers}
0068: * or {@link BeanDefinitionDecorator BeanDefinitionDecorators}.
0069: *
0070: * @author Rob Harrop
0071: * @author Juergen Hoeller
0072: * @author Rod Johnson
0073: * @since 2.0
0074: * @see ParserContext
0075: * @see DefaultBeanDefinitionDocumentReader
0076: */
0077: public class BeanDefinitionParserDelegate {
0078:
0079: public static final String BEANS_NAMESPACE_URI = "http://www.springframework.org/schema/beans";
0080:
0081: public static final String BEAN_NAME_DELIMITERS = ",; ";
0082:
0083: /**
0084: * Value of a T/F attribute that represents true.
0085: * Anything else represents false. Case seNsItive.
0086: */
0087: public static final String TRUE_VALUE = "true";
0088:
0089: public static final String DEFAULT_VALUE = "default";
0090:
0091: public static final String DESCRIPTION_ELEMENT = "description";
0092:
0093: public static final String AUTOWIRE_BY_NAME_VALUE = "byName";
0094:
0095: public static final String AUTOWIRE_BY_TYPE_VALUE = "byType";
0096:
0097: public static final String AUTOWIRE_CONSTRUCTOR_VALUE = "constructor";
0098:
0099: public static final String AUTOWIRE_AUTODETECT_VALUE = "autodetect";
0100:
0101: public static final String DEPENDENCY_CHECK_ALL_ATTRIBUTE_VALUE = "all";
0102:
0103: public static final String DEPENDENCY_CHECK_SIMPLE_ATTRIBUTE_VALUE = "simple";
0104:
0105: public static final String DEPENDENCY_CHECK_OBJECTS_ATTRIBUTE_VALUE = "objects";
0106:
0107: public static final String NAME_ATTRIBUTE = "name";
0108:
0109: public static final String BEAN_ELEMENT = "bean";
0110:
0111: public static final String META_ELEMENT = "meta";
0112:
0113: public static final String ID_ATTRIBUTE = "id";
0114:
0115: public static final String PARENT_ATTRIBUTE = "parent";
0116:
0117: public static final String CLASS_ATTRIBUTE = "class";
0118:
0119: public static final String ABSTRACT_ATTRIBUTE = "abstract";
0120:
0121: public static final String SCOPE_ATTRIBUTE = "scope";
0122:
0123: public static final String SINGLETON_ATTRIBUTE = "singleton";
0124:
0125: public static final String LAZY_INIT_ATTRIBUTE = "lazy-init";
0126:
0127: public static final String AUTOWIRE_ATTRIBUTE = "autowire";
0128:
0129: public static final String AUTOWIRE_CANDIDATE_ATTRIBUTE = "autowire-candidate";
0130:
0131: public static final String DEPENDENCY_CHECK_ATTRIBUTE = "dependency-check";
0132:
0133: public static final String DEPENDS_ON_ATTRIBUTE = "depends-on";
0134:
0135: public static final String INIT_METHOD_ATTRIBUTE = "init-method";
0136:
0137: public static final String DESTROY_METHOD_ATTRIBUTE = "destroy-method";
0138:
0139: public static final String FACTORY_METHOD_ATTRIBUTE = "factory-method";
0140:
0141: public static final String FACTORY_BEAN_ATTRIBUTE = "factory-bean";
0142:
0143: public static final String CONSTRUCTOR_ARG_ELEMENT = "constructor-arg";
0144:
0145: public static final String INDEX_ATTRIBUTE = "index";
0146:
0147: public static final String TYPE_ATTRIBUTE = "type";
0148:
0149: public static final String VALUE_TYPE_ATTRIBUTE = "value-type";
0150:
0151: public static final String KEY_TYPE_ATTRIBUTE = "key-type";
0152:
0153: public static final String PROPERTY_ELEMENT = "property";
0154:
0155: public static final String REF_ATTRIBUTE = "ref";
0156:
0157: public static final String VALUE_ATTRIBUTE = "value";
0158:
0159: public static final String LOOKUP_METHOD_ELEMENT = "lookup-method";
0160:
0161: public static final String REPLACED_METHOD_ELEMENT = "replaced-method";
0162:
0163: public static final String REPLACER_ATTRIBUTE = "replacer";
0164:
0165: public static final String ARG_TYPE_ELEMENT = "arg-type";
0166:
0167: public static final String ARG_TYPE_MATCH_ATTRIBUTE = "match";
0168:
0169: public static final String REF_ELEMENT = "ref";
0170:
0171: public static final String IDREF_ELEMENT = "idref";
0172:
0173: public static final String BEAN_REF_ATTRIBUTE = "bean";
0174:
0175: public static final String LOCAL_REF_ATTRIBUTE = "local";
0176:
0177: public static final String PARENT_REF_ATTRIBUTE = "parent";
0178:
0179: public static final String VALUE_ELEMENT = "value";
0180:
0181: public static final String NULL_ELEMENT = "null";
0182:
0183: public static final String LIST_ELEMENT = "list";
0184:
0185: public static final String SET_ELEMENT = "set";
0186:
0187: public static final String MAP_ELEMENT = "map";
0188:
0189: public static final String ENTRY_ELEMENT = "entry";
0190:
0191: public static final String KEY_ELEMENT = "key";
0192:
0193: public static final String KEY_ATTRIBUTE = "key";
0194:
0195: public static final String KEY_REF_ATTRIBUTE = "key-ref";
0196:
0197: public static final String VALUE_REF_ATTRIBUTE = "value-ref";
0198:
0199: public static final String PROPS_ELEMENT = "props";
0200:
0201: public static final String PROP_ELEMENT = "prop";
0202:
0203: public static final String MERGE_ATTRIBUTE = "merge";
0204:
0205: public static final String DEFAULT_LAZY_INIT_ATTRIBUTE = "default-lazy-init";
0206:
0207: public static final String DEFAULT_AUTOWIRE_ATTRIBUTE = "default-autowire";
0208:
0209: public static final String DEFAULT_DEPENDENCY_CHECK_ATTRIBUTE = "default-dependency-check";
0210:
0211: public static final String DEFAULT_INIT_METHOD_ATTRIBUTE = "default-init-method";
0212:
0213: public static final String DEFAULT_DESTROY_METHOD_ATTRIBUTE = "default-destroy-method";
0214:
0215: public static final String DEFAULT_MERGE_ATTRIBUTE = "default-merge";
0216:
0217: protected final Log logger = LogFactory.getLog(getClass());
0218:
0219: private final XmlReaderContext readerContext;
0220:
0221: private DocumentDefaultsDefinition defaults;
0222:
0223: private ParseState parseState = new ParseState();
0224:
0225: /**
0226: * Stores all used bean names so we can enforce uniqueness on a per file basis.
0227: */
0228: private final Set usedNames = new HashSet();
0229:
0230: /**
0231: * Create a new BeanDefinitionParserDelegate associated with the
0232: * supplied {@link XmlReaderContext}.
0233: */
0234: public BeanDefinitionParserDelegate(XmlReaderContext readerContext) {
0235: Assert.notNull(readerContext,
0236: "XmlReaderContext must not be null");
0237: this .readerContext = readerContext;
0238: }
0239:
0240: /**
0241: * Get the {@link XmlReaderContext} associated with this helper instance.
0242: */
0243: public final XmlReaderContext getReaderContext() {
0244: return this .readerContext;
0245: }
0246:
0247: /**
0248: * Invoke the {@link org.springframework.beans.factory.parsing.SourceExtractor} to pull the
0249: * source metadata from the supplied {@link Element}.
0250: */
0251: protected Object extractSource(Element ele) {
0252: return this .readerContext.extractSource(ele);
0253: }
0254:
0255: /**
0256: * Report an error with the given message for the given source element.
0257: */
0258: protected void error(String message, Element source) {
0259: this .readerContext.error(message, source, this .parseState
0260: .snapshot());
0261: }
0262:
0263: /**
0264: * Report an error with the given message for the given source element.
0265: */
0266: protected void error(String message, Element source, Throwable cause) {
0267: this .readerContext.error(message, source, this .parseState
0268: .snapshot(), cause);
0269: }
0270:
0271: /**
0272: * Initialize the default lazy-init, autowire, dependency check settings,
0273: * init-method, destroy-method and merge settings.
0274: * @see #getDefaults()
0275: */
0276: public void initDefaults(Element root) {
0277: DocumentDefaultsDefinition defaults = new DocumentDefaultsDefinition();
0278: defaults.setLazyInit(root
0279: .getAttribute(DEFAULT_LAZY_INIT_ATTRIBUTE));
0280: defaults.setAutowire(root
0281: .getAttribute(DEFAULT_AUTOWIRE_ATTRIBUTE));
0282: defaults.setDependencyCheck(root
0283: .getAttribute(DEFAULT_DEPENDENCY_CHECK_ATTRIBUTE));
0284: if (root.hasAttribute(DEFAULT_INIT_METHOD_ATTRIBUTE)) {
0285: defaults.setInitMethod(root
0286: .getAttribute(DEFAULT_INIT_METHOD_ATTRIBUTE));
0287: }
0288: if (root.hasAttribute(DEFAULT_DESTROY_METHOD_ATTRIBUTE)) {
0289: defaults.setDestroyMethod(root
0290: .getAttribute(DEFAULT_DESTROY_METHOD_ATTRIBUTE));
0291: }
0292: defaults.setMerge(root.getAttribute(DEFAULT_MERGE_ATTRIBUTE));
0293: defaults.setSource(this .readerContext.extractSource(root));
0294:
0295: this .defaults = defaults;
0296: this .readerContext.fireDefaultsRegistered(defaults);
0297: }
0298:
0299: /**
0300: * Return the defaults definition object, or <code>null</code> if the
0301: * defaults have been initialized yet.
0302: */
0303: public DocumentDefaultsDefinition getDefaults() {
0304: return this .defaults;
0305: }
0306:
0307: /**
0308: * Parses the supplied <code><bean></code> element. May return <code>null</code>
0309: * if there were errors during parse. Errors are reported to the
0310: * {@link org.springframework.beans.factory.parsing.ProblemReporter}.
0311: */
0312: public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) {
0313: return parseBeanDefinitionElement(ele, null);
0314: }
0315:
0316: /**
0317: * Parses the supplied <code><bean></code> element. May return <code>null</code>
0318: * if there were errors during parse. Errors are reported to the
0319: * {@link org.springframework.beans.factory.parsing.ProblemReporter}.
0320: */
0321: public BeanDefinitionHolder parseBeanDefinitionElement(Element ele,
0322: BeanDefinition containingBean) {
0323: String id = ele.getAttribute(ID_ATTRIBUTE);
0324: String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
0325:
0326: List aliases = new ArrayList();
0327: if (StringUtils.hasLength(nameAttr)) {
0328: String[] nameArr = StringUtils.tokenizeToStringArray(
0329: nameAttr, BEAN_NAME_DELIMITERS);
0330: aliases.addAll(Arrays.asList(nameArr));
0331: }
0332:
0333: String beanName = id;
0334: if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
0335: beanName = (String) aliases.remove(0);
0336: if (logger.isDebugEnabled()) {
0337: logger.debug("No XML 'id' specified - using '"
0338: + beanName + "' as bean name and " + aliases
0339: + " as aliases");
0340: }
0341: }
0342:
0343: if (containingBean == null) {
0344: checkNameUniqueness(beanName, aliases, ele);
0345: }
0346:
0347: AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(
0348: ele, beanName, containingBean);
0349: if (beanDefinition != null) {
0350: if (!StringUtils.hasText(beanName)) {
0351: try {
0352: if (containingBean != null) {
0353: beanName = BeanDefinitionReaderUtils
0354: .generateBeanName(beanDefinition,
0355: this .readerContext
0356: .getRegistry(), true);
0357: } else {
0358: beanName = this .readerContext
0359: .generateBeanName(beanDefinition);
0360: }
0361: if (logger.isDebugEnabled()) {
0362: logger
0363: .debug("Neither XML 'id' nor 'name' specified - "
0364: + "using generated bean name ["
0365: + beanName + "]");
0366: }
0367: } catch (BeanDefinitionStoreException ex) {
0368: error(ex.getMessage(), ele);
0369: return null;
0370: }
0371: }
0372: String[] aliasesArray = StringUtils.toStringArray(aliases);
0373: return new BeanDefinitionHolder(beanDefinition, beanName,
0374: aliasesArray);
0375: }
0376:
0377: return null;
0378: }
0379:
0380: private void checkNameUniqueness(String beanName, List aliases,
0381: Element beanElement) {
0382: String foundName = null;
0383:
0384: if (StringUtils.hasText(beanName)
0385: && this .usedNames.contains(beanName)) {
0386: foundName = beanName;
0387: }
0388: if (foundName == null) {
0389: foundName = (String) CollectionUtils.findFirstMatch(
0390: this .usedNames, aliases);
0391: }
0392: if (foundName != null) {
0393: error("Bean name '" + foundName
0394: + "' is already used in this file.", beanElement);
0395: }
0396:
0397: this .usedNames.add(beanName);
0398: this .usedNames.addAll(aliases);
0399: }
0400:
0401: /**
0402: * Parse the bean definition itself, without regard to name or aliases. May return
0403: * <code>null</code> if problems occured during the parse of the bean definition.
0404: */
0405: public AbstractBeanDefinition parseBeanDefinitionElement(
0406: Element ele, String beanName, BeanDefinition containingBean) {
0407:
0408: String className = null;
0409: if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
0410: className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
0411: }
0412: String parent = null;
0413: if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
0414: parent = ele.getAttribute(PARENT_ATTRIBUTE);
0415: }
0416:
0417: try {
0418: this .parseState.push(new BeanEntry(beanName));
0419:
0420: AbstractBeanDefinition bd = BeanDefinitionReaderUtils
0421: .createBeanDefinition(parent, className,
0422: this .readerContext.getBeanClassLoader());
0423:
0424: if (ele.hasAttribute(SCOPE_ATTRIBUTE)) {
0425: // Spring 2.0 "scope" attribute
0426: bd.setScope(ele.getAttribute(SCOPE_ATTRIBUTE));
0427: if (ele.hasAttribute(SINGLETON_ATTRIBUTE)) {
0428: error(
0429: "Specify either 'scope' or 'singleton', not both",
0430: ele);
0431: }
0432: } else if (ele.hasAttribute(SINGLETON_ATTRIBUTE)) {
0433: // Spring 1.x "singleton" attribute
0434: bd.setSingleton(TRUE_VALUE.equals(ele
0435: .getAttribute(SINGLETON_ATTRIBUTE)));
0436: } else if (containingBean != null) {
0437: // Take default from containing bean in case of an inner bean definition.
0438: bd.setSingleton(containingBean.isSingleton());
0439: }
0440:
0441: if (ele.hasAttribute(ABSTRACT_ATTRIBUTE)) {
0442: bd.setAbstract(TRUE_VALUE.equals(ele
0443: .getAttribute(ABSTRACT_ATTRIBUTE)));
0444: }
0445:
0446: String lazyInit = ele.getAttribute(LAZY_INIT_ATTRIBUTE);
0447: if (DEFAULT_VALUE.equals(lazyInit) && bd.isSingleton()) {
0448: // Just apply default to singletons, as lazy-init has no meaning for prototypes.
0449: lazyInit = this .defaults.getLazyInit();
0450: }
0451: bd.setLazyInit(TRUE_VALUE.equals(lazyInit));
0452:
0453: if (ele.hasAttribute(AUTOWIRE_CANDIDATE_ATTRIBUTE)) {
0454: bd.setAutowireCandidate(TRUE_VALUE.equals(ele
0455: .getAttribute(AUTOWIRE_CANDIDATE_ATTRIBUTE)));
0456: }
0457:
0458: String autowire = ele.getAttribute(AUTOWIRE_ATTRIBUTE);
0459: if (DEFAULT_VALUE.equals(autowire)) {
0460: autowire = this .defaults.getAutowire();
0461: }
0462: bd.setAutowireMode(getAutowireMode(autowire));
0463:
0464: String dependencyCheck = ele
0465: .getAttribute(DEPENDENCY_CHECK_ATTRIBUTE);
0466: if (DEFAULT_VALUE.equals(dependencyCheck)) {
0467: dependencyCheck = this .defaults.getDependencyCheck();
0468: }
0469: bd.setDependencyCheck(getDependencyCheck(dependencyCheck));
0470:
0471: if (ele.hasAttribute(DEPENDS_ON_ATTRIBUTE)) {
0472: String dependsOn = ele
0473: .getAttribute(DEPENDS_ON_ATTRIBUTE);
0474: bd.setDependsOn(StringUtils.tokenizeToStringArray(
0475: dependsOn, BEAN_NAME_DELIMITERS));
0476: }
0477:
0478: if (ele.hasAttribute(FACTORY_METHOD_ATTRIBUTE)) {
0479: bd.setFactoryMethodName(ele
0480: .getAttribute(FACTORY_METHOD_ATTRIBUTE));
0481: }
0482: if (ele.hasAttribute(FACTORY_BEAN_ATTRIBUTE)) {
0483: bd.setFactoryBeanName(ele
0484: .getAttribute(FACTORY_BEAN_ATTRIBUTE));
0485: }
0486:
0487: if (ele.hasAttribute(INIT_METHOD_ATTRIBUTE)) {
0488: String initMethodName = ele
0489: .getAttribute(INIT_METHOD_ATTRIBUTE);
0490: if (!"".equals(initMethodName)) {
0491: bd.setInitMethodName(initMethodName);
0492: }
0493: } else {
0494: if (this .defaults.getInitMethod() != null) {
0495: bd.setInitMethodName(this .defaults.getInitMethod());
0496: bd.setEnforceInitMethod(false);
0497: }
0498: }
0499:
0500: if (ele.hasAttribute(DESTROY_METHOD_ATTRIBUTE)) {
0501: String destroyMethodName = ele
0502: .getAttribute(DESTROY_METHOD_ATTRIBUTE);
0503: if (!"".equals(destroyMethodName)) {
0504: bd.setDestroyMethodName(destroyMethodName);
0505: }
0506: } else {
0507: if (this .defaults.getDestroyMethod() != null) {
0508: bd.setDestroyMethodName(this .defaults
0509: .getDestroyMethod());
0510: bd.setEnforceDestroyMethod(false);
0511: }
0512: }
0513:
0514: parseMetaElements(ele, bd);
0515: parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
0516: parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
0517:
0518: parseConstructorArgElements(ele, bd);
0519: parsePropertyElements(ele, bd);
0520:
0521: bd.setResourceDescription(this .readerContext.getResource()
0522: .getDescription());
0523: bd.setSource(extractSource(ele));
0524:
0525: return bd;
0526: } catch (ClassNotFoundException ex) {
0527: error("Bean class [" + className + "] not found", ele, ex);
0528: } catch (NoClassDefFoundError err) {
0529: error("Class that bean class [" + className
0530: + "] depends on not found", ele, err);
0531: } catch (Throwable ex) {
0532: error("Unexpected failure during bean definition parsing",
0533: ele, ex);
0534: } finally {
0535: this .parseState.pop();
0536: }
0537:
0538: return null;
0539: }
0540:
0541: public void parseMetaElements(Element ele,
0542: AttributeAccessor attributeAccessor) {
0543: NodeList nl = ele.getChildNodes();
0544: for (int i = 0; i < nl.getLength(); i++) {
0545: Node node = nl.item(i);
0546: if (node instanceof Element
0547: && DomUtils.nodeNameEquals(node, META_ELEMENT)) {
0548: Element metaElement = (Element) node;
0549: String key = metaElement.getAttribute(KEY_ATTRIBUTE);
0550: String value = metaElement
0551: .getAttribute(VALUE_ATTRIBUTE);
0552: attributeAccessor.setAttribute(key, value);
0553: }
0554: }
0555: }
0556:
0557: public int getDependencyCheck(String att) {
0558: int dependencyCheckCode = AbstractBeanDefinition.DEPENDENCY_CHECK_NONE;
0559: if (DEPENDENCY_CHECK_ALL_ATTRIBUTE_VALUE.equals(att)) {
0560: dependencyCheckCode = AbstractBeanDefinition.DEPENDENCY_CHECK_ALL;
0561: } else if (DEPENDENCY_CHECK_SIMPLE_ATTRIBUTE_VALUE.equals(att)) {
0562: dependencyCheckCode = AbstractBeanDefinition.DEPENDENCY_CHECK_SIMPLE;
0563: } else if (DEPENDENCY_CHECK_OBJECTS_ATTRIBUTE_VALUE.equals(att)) {
0564: dependencyCheckCode = AbstractBeanDefinition.DEPENDENCY_CHECK_OBJECTS;
0565: }
0566: // Else leave default value.
0567: return dependencyCheckCode;
0568: }
0569:
0570: public int getAutowireMode(String att) {
0571: int autowire = AbstractBeanDefinition.AUTOWIRE_NO;
0572: if (AUTOWIRE_BY_NAME_VALUE.equals(att)) {
0573: autowire = AbstractBeanDefinition.AUTOWIRE_BY_NAME;
0574: } else if (AUTOWIRE_BY_TYPE_VALUE.equals(att)) {
0575: autowire = AbstractBeanDefinition.AUTOWIRE_BY_TYPE;
0576: } else if (AUTOWIRE_CONSTRUCTOR_VALUE.equals(att)) {
0577: autowire = AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR;
0578: } else if (AUTOWIRE_AUTODETECT_VALUE.equals(att)) {
0579: autowire = AbstractBeanDefinition.AUTOWIRE_AUTODETECT;
0580: }
0581: // Else leave default value.
0582: return autowire;
0583: }
0584:
0585: /**
0586: * Parse constructor-arg sub-elements of the given bean element.
0587: */
0588: public void parseConstructorArgElements(Element beanEle,
0589: BeanDefinition bd) {
0590: NodeList nl = beanEle.getChildNodes();
0591: for (int i = 0; i < nl.getLength(); i++) {
0592: Node node = nl.item(i);
0593: if (node instanceof Element
0594: && DomUtils.nodeNameEquals(node,
0595: CONSTRUCTOR_ARG_ELEMENT)) {
0596: parseConstructorArgElement((Element) node, bd);
0597: }
0598: }
0599: }
0600:
0601: /**
0602: * Parse property sub-elements of the given bean element.
0603: */
0604: public void parsePropertyElements(Element beanEle, BeanDefinition bd) {
0605: NodeList nl = beanEle.getChildNodes();
0606: for (int i = 0; i < nl.getLength(); i++) {
0607: Node node = nl.item(i);
0608: if (node instanceof Element
0609: && DomUtils.nodeNameEquals(node, PROPERTY_ELEMENT)) {
0610: parsePropertyElement((Element) node, bd);
0611: }
0612: }
0613: }
0614:
0615: /**
0616: * Parse lookup-override sub-elements of the given bean element.
0617: */
0618: public void parseLookupOverrideSubElements(Element beanEle,
0619: MethodOverrides overrides) {
0620: NodeList nl = beanEle.getChildNodes();
0621: for (int i = 0; i < nl.getLength(); i++) {
0622: Node node = nl.item(i);
0623: if (node instanceof Element
0624: && DomUtils.nodeNameEquals(node,
0625: LOOKUP_METHOD_ELEMENT)) {
0626: Element ele = (Element) node;
0627: String methodName = ele.getAttribute(NAME_ATTRIBUTE);
0628: String beanRef = ele.getAttribute(BEAN_ELEMENT);
0629: LookupOverride override = new LookupOverride(
0630: methodName, beanRef);
0631: override.setSource(extractSource(ele));
0632: overrides.addOverride(override);
0633: }
0634: }
0635: }
0636:
0637: /**
0638: * Parse replaced-method sub-elements of the given bean element.
0639: */
0640: public void parseReplacedMethodSubElements(Element beanEle,
0641: MethodOverrides overrides) {
0642: NodeList nl = beanEle.getChildNodes();
0643: for (int i = 0; i < nl.getLength(); i++) {
0644: Node node = nl.item(i);
0645: if (node instanceof Element
0646: && DomUtils.nodeNameEquals(node,
0647: REPLACED_METHOD_ELEMENT)) {
0648: Element replacedMethodEle = (Element) node;
0649: String name = replacedMethodEle
0650: .getAttribute(NAME_ATTRIBUTE);
0651: String callback = replacedMethodEle
0652: .getAttribute(REPLACER_ATTRIBUTE);
0653: ReplaceOverride replaceOverride = new ReplaceOverride(
0654: name, callback);
0655: // Look for arg-type match elements.
0656: List argTypeEles = DomUtils.getChildElementsByTagName(
0657: replacedMethodEle, ARG_TYPE_ELEMENT);
0658: for (Iterator it = argTypeEles.iterator(); it.hasNext();) {
0659: Element argTypeEle = (Element) it.next();
0660: replaceOverride.addTypeIdentifier(argTypeEle
0661: .getAttribute(ARG_TYPE_MATCH_ATTRIBUTE));
0662: }
0663: replaceOverride
0664: .setSource(extractSource(replacedMethodEle));
0665: overrides.addOverride(replaceOverride);
0666: }
0667: }
0668: }
0669:
0670: /**
0671: * Parse a constructor-arg element.
0672: */
0673: public void parseConstructorArgElement(Element ele,
0674: BeanDefinition bd) {
0675: String indexAttr = ele.getAttribute(INDEX_ATTRIBUTE);
0676: String typeAttr = ele.getAttribute(TYPE_ATTRIBUTE);
0677: if (StringUtils.hasLength(indexAttr)) {
0678: try {
0679: int index = Integer.parseInt(indexAttr);
0680: if (index < 0) {
0681: error("'index' cannot be lower than 0", ele);
0682: } else {
0683: try {
0684: this .parseState
0685: .push(new ConstructorArgumentEntry(
0686: index));
0687: Object value = parsePropertyValue(ele, bd, null);
0688: ConstructorArgumentValues.ValueHolder valueHolder = new ConstructorArgumentValues.ValueHolder(
0689: value);
0690: if (StringUtils.hasLength(typeAttr)) {
0691: valueHolder.setType(typeAttr);
0692: }
0693: valueHolder.setSource(extractSource(ele));
0694: bd.getConstructorArgumentValues()
0695: .addIndexedArgumentValue(index,
0696: valueHolder);
0697: } finally {
0698: this .parseState.pop();
0699: }
0700: }
0701: } catch (NumberFormatException ex) {
0702: error(
0703: "Attribute 'index' of tag 'constructor-arg' must be an integer",
0704: ele);
0705: }
0706: } else {
0707: try {
0708: this .parseState.push(new ConstructorArgumentEntry());
0709: Object value = parsePropertyValue(ele, bd, null);
0710: ConstructorArgumentValues.ValueHolder valueHolder = new ConstructorArgumentValues.ValueHolder(
0711: value);
0712: if (StringUtils.hasLength(typeAttr)) {
0713: valueHolder.setType(typeAttr);
0714: }
0715: valueHolder.setSource(extractSource(ele));
0716: bd.getConstructorArgumentValues()
0717: .addGenericArgumentValue(valueHolder);
0718: } finally {
0719: this .parseState.pop();
0720: }
0721: }
0722: }
0723:
0724: /**
0725: * Parse a property element.
0726: */
0727: public void parsePropertyElement(Element ele, BeanDefinition bd) {
0728: String propertyName = ele.getAttribute(NAME_ATTRIBUTE);
0729: if (!StringUtils.hasLength(propertyName)) {
0730: error("Tag 'property' must have a 'name' attribute", ele);
0731: return;
0732: }
0733: this .parseState.push(new PropertyEntry(propertyName));
0734: try {
0735: if (bd.getPropertyValues().contains(propertyName)) {
0736: error("Multiple 'property' definitions for property '"
0737: + propertyName + "'", ele);
0738: return;
0739: }
0740: Object val = parsePropertyValue(ele, bd, propertyName);
0741: PropertyValue pv = new PropertyValue(propertyName, val);
0742: parseMetaElements(ele, pv);
0743: pv.setSource(extractSource(ele));
0744: bd.getPropertyValues().addPropertyValue(pv);
0745: } finally {
0746: this .parseState.pop();
0747: }
0748: }
0749:
0750: /**
0751: * Get the value of a property element. May be a list etc.
0752: * Also used for constructor arguments, "propertyName" being null in this case.
0753: */
0754: public Object parsePropertyValue(Element ele, BeanDefinition bd,
0755: String propertyName) {
0756: String elementName = (propertyName != null) ? "<property> element for property '"
0757: + propertyName + "'"
0758: : "<constructor-arg> element";
0759:
0760: // Should only have one child element: ref, value, list, etc.
0761: NodeList nl = ele.getChildNodes();
0762: Element subElement = null;
0763: for (int i = 0; i < nl.getLength(); i++) {
0764: if (nl.item(i) instanceof Element) {
0765: Element candidateEle = (Element) nl.item(i);
0766: if (DESCRIPTION_ELEMENT.equals(candidateEle
0767: .getTagName())) {
0768: // Keep going: we don't use this value for now.
0769: } else {
0770: // Child element is what we're looking for.
0771: if (subElement != null
0772: && !META_ELEMENT.equals(subElement
0773: .getTagName())) {
0774: error(
0775: elementName
0776: + " must not contain more than one sub-element",
0777: ele);
0778: } else {
0779: subElement = candidateEle;
0780: }
0781: }
0782: }
0783: }
0784:
0785: boolean hasRefAttribute = ele.hasAttribute(REF_ATTRIBUTE);
0786: boolean hasValueAttribute = ele.hasAttribute(VALUE_ATTRIBUTE);
0787: if ((hasRefAttribute && hasValueAttribute)
0788: || ((hasRefAttribute || hasValueAttribute))
0789: && subElement != null) {
0790: error(
0791: elementName
0792: + " is only allowed to contain either 'ref' attribute OR 'value' attribute OR sub-element",
0793: ele);
0794: }
0795:
0796: if (hasRefAttribute) {
0797: String refName = ele.getAttribute(REF_ATTRIBUTE);
0798: if (!StringUtils.hasText(refName)) {
0799: error(elementName + " contains empty 'ref' attribute",
0800: ele);
0801: }
0802: RuntimeBeanReference ref = new RuntimeBeanReference(refName);
0803: ref.setSource(extractSource(ele));
0804: return ref;
0805: } else if (hasValueAttribute) {
0806: TypedStringValue valueHolder = new TypedStringValue(ele
0807: .getAttribute(VALUE_ATTRIBUTE));
0808: valueHolder.setSource(extractSource(ele));
0809: return valueHolder;
0810: } else if (subElement != null) {
0811: return parsePropertySubElement(subElement, bd);
0812: } else {
0813: // Neither child element nor "ref" or "value" attribute found.
0814: error(elementName + " must specify a ref or value", ele);
0815: return null;
0816: }
0817: }
0818:
0819: public Object parsePropertySubElement(Element ele, BeanDefinition bd) {
0820: return parsePropertySubElement(ele, bd, null);
0821: }
0822:
0823: /**
0824: * Parse a value, ref or collection sub-element of a property or
0825: * constructor-arg element.
0826: * @param ele subelement of property element; we don't know which yet
0827: * @param defaultTypeClassName the default type (class name) for any
0828: * <code><value></code> tag that might be created
0829: */
0830: public Object parsePropertySubElement(Element ele,
0831: BeanDefinition bd, String defaultTypeClassName) {
0832: if (!isDefaultNamespace(ele.getNamespaceURI())) {
0833: return parseNestedCustomElement(ele, bd);
0834: } else if (DomUtils.nodeNameEquals(ele, BEAN_ELEMENT)) {
0835: BeanDefinitionHolder bdHolder = parseBeanDefinitionElement(
0836: ele, bd);
0837: if (bdHolder != null) {
0838: bdHolder = decorateBeanDefinitionIfRequired(ele,
0839: bdHolder);
0840: }
0841: return bdHolder;
0842: } else if (DomUtils.nodeNameEquals(ele, REF_ELEMENT)) {
0843: // A generic reference to any name of any bean.
0844: String refName = ele.getAttribute(BEAN_REF_ATTRIBUTE);
0845: boolean toParent = false;
0846: if (!StringUtils.hasLength(refName)) {
0847: // A reference to the id of another bean in the same XML file.
0848: refName = ele.getAttribute(LOCAL_REF_ATTRIBUTE);
0849: if (!StringUtils.hasLength(refName)) {
0850: // A reference to the id of another bean in a parent context.
0851: refName = ele.getAttribute(PARENT_REF_ATTRIBUTE);
0852: toParent = true;
0853: if (!StringUtils.hasLength(refName)) {
0854: error(
0855: "'bean', 'local' or 'parent' is required for <ref> element",
0856: ele);
0857: return null;
0858: }
0859: }
0860: }
0861: if (!StringUtils.hasText(refName)) {
0862: error("<ref> element contains empty target attribute",
0863: ele);
0864: return null;
0865: }
0866: RuntimeBeanReference ref = new RuntimeBeanReference(
0867: refName, toParent);
0868: ref.setSource(extractSource(ele));
0869: return ref;
0870: } else if (DomUtils.nodeNameEquals(ele, IDREF_ELEMENT)) {
0871: // A generic reference to any name of any bean.
0872: String refName = ele.getAttribute(BEAN_REF_ATTRIBUTE);
0873: if (!StringUtils.hasLength(refName)) {
0874: // A reference to the id of another bean in the same XML file.
0875: refName = ele.getAttribute(LOCAL_REF_ATTRIBUTE);
0876: if (!StringUtils.hasLength(refName)) {
0877: error(
0878: "Either 'bean' or 'local' is required for <idref> element",
0879: ele);
0880: return null;
0881: }
0882: }
0883: if (!StringUtils.hasText(refName)) {
0884: error(
0885: "<idref> element contains empty target attribute",
0886: ele);
0887: return null;
0888: }
0889: RuntimeBeanNameReference ref = new RuntimeBeanNameReference(
0890: refName);
0891: ref.setSource(extractSource(ele));
0892: return ref;
0893: } else if (DomUtils.nodeNameEquals(ele, VALUE_ELEMENT)) {
0894: // It's a literal value.
0895: String value = DomUtils.getTextValue(ele);
0896: String typeClassName = ele.getAttribute(TYPE_ATTRIBUTE);
0897: if (!StringUtils.hasText(typeClassName)) {
0898: typeClassName = defaultTypeClassName;
0899: }
0900: try {
0901: return buildTypedStringValue(value, typeClassName, ele);
0902: } catch (ClassNotFoundException ex) {
0903: error("Type class [" + typeClassName
0904: + "] not found for <value> element", ele, ex);
0905: return value;
0906: }
0907: } else if (DomUtils.nodeNameEquals(ele, NULL_ELEMENT)) {
0908: // It's a distinguished null value. Let's wrap it in a TypedStringValue
0909: // object in order to preserve the source location.
0910: TypedStringValue nullHolder = new TypedStringValue(null);
0911: nullHolder.setSource(extractSource(ele));
0912: return nullHolder;
0913: } else if (DomUtils.nodeNameEquals(ele, LIST_ELEMENT)) {
0914: return parseListElement(ele, bd);
0915: } else if (DomUtils.nodeNameEquals(ele, SET_ELEMENT)) {
0916: return parseSetElement(ele, bd);
0917: } else if (DomUtils.nodeNameEquals(ele, MAP_ELEMENT)) {
0918: return parseMapElement(ele, bd);
0919: } else if (DomUtils.nodeNameEquals(ele, PROPS_ELEMENT)) {
0920: return parsePropsElement(ele);
0921: }
0922: error("Unknown property sub-element: [" + ele.getTagName()
0923: + "]", ele);
0924: return null;
0925: }
0926:
0927: private Object buildTypedStringValue(String value,
0928: String targetTypeName, Element ele)
0929: throws ClassNotFoundException {
0930:
0931: ClassLoader classLoader = this .readerContext
0932: .getBeanClassLoader();
0933: TypedStringValue typedValue = null;
0934: if (!StringUtils.hasText(targetTypeName)) {
0935: typedValue = new TypedStringValue(value);
0936: } else if (classLoader != null) {
0937: Class targetType = ClassUtils.forName(targetTypeName,
0938: classLoader);
0939: typedValue = new TypedStringValue(value, targetType);
0940: } else {
0941: typedValue = new TypedStringValue(value, targetTypeName);
0942: }
0943: typedValue.setSource(extractSource(ele));
0944: return typedValue;
0945: }
0946:
0947: /**
0948: * Parse a list element.
0949: */
0950: public List parseListElement(Element collectionEle,
0951: BeanDefinition bd) {
0952: String defaultTypeClassName = collectionEle
0953: .getAttribute(VALUE_TYPE_ATTRIBUTE);
0954: NodeList nl = collectionEle.getChildNodes();
0955: ManagedList list = new ManagedList(nl.getLength());
0956: list.setSource(extractSource(collectionEle));
0957: list.setMergeEnabled(parseMergeAttribute(collectionEle));
0958: for (int i = 0; i < nl.getLength(); i++) {
0959: if (nl.item(i) instanceof Element) {
0960: Element ele = (Element) nl.item(i);
0961: list.add(parsePropertySubElement(ele, bd,
0962: defaultTypeClassName));
0963: }
0964: }
0965: return list;
0966: }
0967:
0968: /**
0969: * Parse a set element.
0970: */
0971: public Set parseSetElement(Element collectionEle, BeanDefinition bd) {
0972: String defaultTypeClassName = collectionEle
0973: .getAttribute(VALUE_TYPE_ATTRIBUTE);
0974: NodeList nl = collectionEle.getChildNodes();
0975: ManagedSet set = new ManagedSet(nl.getLength());
0976: set.setSource(extractSource(collectionEle));
0977: set.setMergeEnabled(parseMergeAttribute(collectionEle));
0978: for (int i = 0; i < nl.getLength(); i++) {
0979: if (nl.item(i) instanceof Element) {
0980: Element ele = (Element) nl.item(i);
0981: set.add(parsePropertySubElement(ele, bd,
0982: defaultTypeClassName));
0983: }
0984: }
0985: return set;
0986: }
0987:
0988: /**
0989: * Parse a map element.
0990: */
0991: public Map parseMapElement(Element mapEle, BeanDefinition bd) {
0992: String defaultKeyTypeClassName = mapEle
0993: .getAttribute(KEY_TYPE_ATTRIBUTE);
0994: String defaultValueTypeClassName = mapEle
0995: .getAttribute(VALUE_TYPE_ATTRIBUTE);
0996:
0997: List entryEles = DomUtils.getChildElementsByTagName(mapEle,
0998: ENTRY_ELEMENT);
0999: ManagedMap map = new ManagedMap(entryEles.size());
1000: map.setMergeEnabled(parseMergeAttribute(mapEle));
1001: map.setSource(extractSource(mapEle));
1002:
1003: for (Iterator it = entryEles.iterator(); it.hasNext();) {
1004: Element entryEle = (Element) it.next();
1005: // Should only have one value child element: ref, value, list, etc.
1006: // Optionally, there might be a key child element.
1007: NodeList entrySubNodes = entryEle.getChildNodes();
1008:
1009: Element keyEle = null;
1010: Element valueEle = null;
1011: for (int j = 0; j < entrySubNodes.getLength(); j++) {
1012: if (entrySubNodes.item(j) instanceof Element) {
1013: Element candidateEle = (Element) entrySubNodes
1014: .item(j);
1015: if (DomUtils.nodeNameEquals(candidateEle,
1016: KEY_ELEMENT)) {
1017: if (keyEle != null) {
1018: error(
1019: "<entry> element is only allowed to contain one <key> sub-element",
1020: entryEle);
1021: } else {
1022: keyEle = candidateEle;
1023: }
1024: } else {
1025: // Child element is what we're looking for.
1026: if (valueEle != null) {
1027: error(
1028: "<entry> element must not contain more than one value sub-element",
1029: entryEle);
1030: } else {
1031: valueEle = candidateEle;
1032: }
1033: }
1034: }
1035: }
1036:
1037: // Extract key from attribute or sub-element.
1038: Object key = null;
1039: boolean hasKeyAttribute = entryEle
1040: .hasAttribute(KEY_ATTRIBUTE);
1041: boolean hasKeyRefAttribute = entryEle
1042: .hasAttribute(KEY_REF_ATTRIBUTE);
1043: if ((hasKeyAttribute && hasKeyRefAttribute)
1044: || ((hasKeyAttribute || hasKeyRefAttribute))
1045: && keyEle != null) {
1046: error(
1047: "<entry> element is only allowed to contain either "
1048: + "a 'key' attribute OR a 'key-ref' attribute OR a <key> sub-element",
1049: entryEle);
1050: }
1051: if (hasKeyAttribute) {
1052: key = buildTypedStringValueForMap(entryEle
1053: .getAttribute(KEY_ATTRIBUTE),
1054: defaultKeyTypeClassName, entryEle);
1055: } else if (hasKeyRefAttribute) {
1056: String refName = entryEle
1057: .getAttribute(KEY_REF_ATTRIBUTE);
1058: if (!StringUtils.hasText(refName)) {
1059: error(
1060: "<entry> element contains empty 'key-ref' attribute",
1061: entryEle);
1062: }
1063: RuntimeBeanReference ref = new RuntimeBeanReference(
1064: refName);
1065: ref.setSource(extractSource(entryEle));
1066: key = ref;
1067: } else if (keyEle != null) {
1068: key = parseKeyElement(keyEle, bd,
1069: defaultKeyTypeClassName);
1070: } else {
1071: error("<entry> element must specify a key", entryEle);
1072: }
1073:
1074: // Extract value from attribute or sub-element.
1075: Object value = null;
1076: boolean hasValueAttribute = entryEle
1077: .hasAttribute(VALUE_ATTRIBUTE);
1078: boolean hasValueRefAttribute = entryEle
1079: .hasAttribute(VALUE_REF_ATTRIBUTE);
1080: if ((hasValueAttribute && hasValueRefAttribute)
1081: || ((hasValueAttribute || hasValueRefAttribute))
1082: && valueEle != null) {
1083: error(
1084: "<entry> element is only allowed to contain either "
1085: + "'value' attribute OR 'value-ref' attribute OR <value> sub-element",
1086: entryEle);
1087: }
1088: if (hasValueAttribute) {
1089: value = buildTypedStringValueForMap(entryEle
1090: .getAttribute(VALUE_ATTRIBUTE),
1091: defaultValueTypeClassName, entryEle);
1092: } else if (hasValueRefAttribute) {
1093: String refName = entryEle
1094: .getAttribute(VALUE_REF_ATTRIBUTE);
1095: if (!StringUtils.hasText(refName)) {
1096: error(
1097: "<entry> element contains empty 'value-ref' attribute",
1098: entryEle);
1099: }
1100: RuntimeBeanReference ref = new RuntimeBeanReference(
1101: refName);
1102: ref.setSource(extractSource(entryEle));
1103: value = ref;
1104: } else if (valueEle != null) {
1105: value = parsePropertySubElement(valueEle, bd,
1106: defaultValueTypeClassName);
1107: } else {
1108: error("<entry> element must specify a value", entryEle);
1109: }
1110:
1111: // Add final key and value to the Map.
1112: map.put(key, value);
1113: }
1114:
1115: return map;
1116: }
1117:
1118: private Object buildTypedStringValueForMap(String value,
1119: String defaultTypeClassName, Element entryEle) {
1120: try {
1121: return buildTypedStringValue(value, defaultTypeClassName,
1122: entryEle);
1123: } catch (ClassNotFoundException ex) {
1124: error("Type class [" + defaultTypeClassName
1125: + "] not found for Map key/value type", entryEle,
1126: ex);
1127: return value;
1128: }
1129: }
1130:
1131: /**
1132: * Parse a key sub-element of a map element.
1133: */
1134: public Object parseKeyElement(Element keyEle, BeanDefinition bd,
1135: String defaultKeyTypeClassName) {
1136: NodeList nl = keyEle.getChildNodes();
1137: Element subElement = null;
1138: for (int i = 0; i < nl.getLength(); i++) {
1139: if (nl.item(i) instanceof Element) {
1140: Element candidateEle = (Element) nl.item(i);
1141: // Child element is what we're looking for.
1142: if (subElement != null) {
1143: error(
1144: "<key> element must not contain more than one value sub-element",
1145: keyEle);
1146: } else {
1147: subElement = candidateEle;
1148: }
1149: }
1150: }
1151: return parsePropertySubElement(subElement, bd,
1152: defaultKeyTypeClassName);
1153: }
1154:
1155: /**
1156: * Parse a props element.
1157: */
1158: public Properties parsePropsElement(Element propsEle) {
1159: ManagedProperties props = new ManagedProperties();
1160: props.setSource(extractSource(propsEle));
1161: props.setMergeEnabled(parseMergeAttribute(propsEle));
1162:
1163: List propEles = DomUtils.getChildElementsByTagName(propsEle,
1164: PROP_ELEMENT);
1165: for (Iterator it = propEles.iterator(); it.hasNext();) {
1166: Element propEle = (Element) it.next();
1167: String key = propEle.getAttribute(KEY_ATTRIBUTE);
1168: // Trim the text value to avoid unwanted whitespace
1169: // caused by typical XML formatting.
1170: String value = DomUtils.getTextValue(propEle).trim();
1171:
1172: TypedStringValue keyHolder = new TypedStringValue(key);
1173: keyHolder.setSource(extractSource(propEle));
1174: TypedStringValue valueHolder = new TypedStringValue(value);
1175: valueHolder.setSource(extractSource(propEle));
1176: props.put(keyHolder, valueHolder);
1177: }
1178:
1179: return props;
1180: }
1181:
1182: /**
1183: * Parse the merge attribute of a collection element, if any.
1184: */
1185: public boolean parseMergeAttribute(Element collectionElement) {
1186: String value = collectionElement.getAttribute(MERGE_ATTRIBUTE);
1187: if (DEFAULT_VALUE.equals(value)) {
1188: value = this .defaults.getMerge();
1189: }
1190: return TRUE_VALUE.equals(value);
1191: }
1192:
1193: public BeanDefinition parseCustomElement(Element ele) {
1194: return parseCustomElement(ele, null);
1195: }
1196:
1197: public BeanDefinition parseCustomElement(Element ele,
1198: BeanDefinition containingBd) {
1199: String namespaceUri = ele.getNamespaceURI();
1200: NamespaceHandler handler = this .readerContext
1201: .getNamespaceHandlerResolver().resolve(namespaceUri);
1202: if (handler == null) {
1203: error(
1204: "Unable to locate Spring NamespaceHandler for XML schema namespace ["
1205: + namespaceUri + "]", ele);
1206: return null;
1207: }
1208: return handler.parse(ele, new ParserContext(this .readerContext,
1209: this , containingBd));
1210: }
1211:
1212: public BeanDefinitionHolder decorateBeanDefinitionIfRequired(
1213: Element ele, BeanDefinitionHolder definitionHolder) {
1214: BeanDefinitionHolder finalDefinition = definitionHolder;
1215:
1216: // Decorate based on custom attributes first.
1217: NamedNodeMap attributes = ele.getAttributes();
1218: for (int i = 0; i < attributes.getLength(); i++) {
1219: Node node = attributes.item(i);
1220: finalDefinition = decorateIfRequired(node, finalDefinition);
1221: }
1222:
1223: // Decorate based on custom nested elements.
1224: NodeList children = ele.getChildNodes();
1225: for (int i = 0; i < children.getLength(); i++) {
1226: Node node = children.item(i);
1227: if (node.getNodeType() == Node.ELEMENT_NODE) {
1228: finalDefinition = decorateIfRequired(node,
1229: finalDefinition);
1230: }
1231: }
1232: return finalDefinition;
1233: }
1234:
1235: private BeanDefinitionHolder decorateIfRequired(Node node,
1236: BeanDefinitionHolder originalDefinition) {
1237: String namespaceUri = node.getNamespaceURI();
1238: if (!isDefaultNamespace(namespaceUri)) {
1239: NamespaceHandler handler = this .readerContext
1240: .getNamespaceHandlerResolver()
1241: .resolve(namespaceUri);
1242: if (handler != null) {
1243: return handler.decorate(node, originalDefinition,
1244: new ParserContext(this .readerContext, this ));
1245: } else {
1246: // A custom namespace, not to be handled by Spring - maybe "xml:...".
1247: if (logger.isDebugEnabled()) {
1248: logger
1249: .debug("No Spring NamespaceHandler found for XML schema namespace ["
1250: + namespaceUri + "]");
1251: }
1252: }
1253: }
1254: return originalDefinition;
1255: }
1256:
1257: public boolean isDefaultNamespace(String namespaceUri) {
1258: return (!StringUtils.hasLength(namespaceUri) || BEANS_NAMESPACE_URI
1259: .equals(namespaceUri));
1260: }
1261:
1262: private BeanDefinitionHolder parseNestedCustomElement(Element ele,
1263: BeanDefinition containingBd) {
1264: BeanDefinition innerDefinition = parseCustomElement(ele,
1265: containingBd);
1266: if (innerDefinition == null) {
1267: error(
1268: "Incorrect usage of element '"
1269: + ele.getNodeName()
1270: + "' in a nested manner. "
1271: + "This tag cannot be used nested inside <property>.",
1272: ele);
1273: return null;
1274: }
1275: String id = ele.getNodeName()
1276: + BeanDefinitionReaderUtils.GENERATED_BEAN_NAME_SEPARATOR
1277: + ObjectUtils.getIdentityHexString(innerDefinition);
1278: if (logger.isDebugEnabled()) {
1279: logger.debug("Using generated bean name [" + id
1280: + "] for nested custom element '"
1281: + ele.getNodeName() + "'");
1282: }
1283: return new BeanDefinitionHolder(innerDefinition, id);
1284: }
1285:
1286: }
|