1 16 17 package org.springframework.beans.factory.xml; 18 19 import java.io.IOException ; 20 import java.util.ArrayList ; 21 import java.util.Arrays ; 22 import java.util.Iterator ; 23 import java.util.List ; 24 import java.util.Map ; 25 import java.util.Properties ; 26 import java.util.Set ; 27 28 import org.apache.commons.logging.Log; 29 import org.apache.commons.logging.LogFactory; 30 import org.w3c.dom.Document ; 31 import org.w3c.dom.Element ; 32 import org.w3c.dom.Node ; 33 import org.w3c.dom.NodeList ; 34 35 import org.springframework.beans.MutablePropertyValues; 36 import org.springframework.beans.factory.BeanDefinitionStoreException; 37 import org.springframework.beans.factory.config.BeanDefinition; 38 import org.springframework.beans.factory.config.BeanDefinitionHolder; 39 import org.springframework.beans.factory.config.ConstructorArgumentValues; 40 import org.springframework.beans.factory.config.RuntimeBeanReference; 41 import org.springframework.beans.factory.config.TypedStringValue; 42 import org.springframework.beans.factory.support.AbstractBeanDefinition; 43 import org.springframework.beans.factory.support.BeanDefinitionReader; 44 import org.springframework.beans.factory.support.BeanDefinitionReaderUtils; 45 import org.springframework.beans.factory.support.LookupOverride; 46 import org.springframework.beans.factory.support.ManagedList; 47 import org.springframework.beans.factory.support.ManagedMap; 48 import org.springframework.beans.factory.support.ManagedSet; 49 import org.springframework.beans.factory.support.MethodOverrides; 50 import org.springframework.beans.factory.support.ReplaceOverride; 51 import org.springframework.core.io.Resource; 52 import org.springframework.core.io.ResourceLoader; 53 import org.springframework.util.ClassUtils; 54 import org.springframework.util.ResourceUtils; 55 import org.springframework.util.StringUtils; 56 import org.springframework.util.xml.DomUtils; 57 58 72 public class DefaultXmlBeanDefinitionParser implements XmlBeanDefinitionParser { 73 74 public static final String BEAN_NAME_DELIMITERS = ",; "; 75 76 80 public static final String TRUE_VALUE = "true"; 81 public static final String DEFAULT_VALUE = "default"; 82 public static final String DESCRIPTION_ELEMENT = "description"; 83 84 public static final String AUTOWIRE_BY_NAME_VALUE = "byName"; 85 public static final String AUTOWIRE_BY_TYPE_VALUE = "byType"; 86 public static final String AUTOWIRE_CONSTRUCTOR_VALUE = "constructor"; 87 public static final String AUTOWIRE_AUTODETECT_VALUE = "autodetect"; 88 89 public static final String DEPENDENCY_CHECK_ALL_ATTRIBUTE_VALUE = "all"; 90 public static final String DEPENDENCY_CHECK_SIMPLE_ATTRIBUTE_VALUE = "simple"; 91 public static final String DEPENDENCY_CHECK_OBJECTS_ATTRIBUTE_VALUE = "objects"; 92 93 public static final String DEFAULT_LAZY_INIT_ATTRIBUTE = "default-lazy-init"; 94 public static final String DEFAULT_AUTOWIRE_ATTRIBUTE = "default-autowire"; 95 public static final String DEFAULT_DEPENDENCY_CHECK_ATTRIBUTE = "default-dependency-check"; 96 97 public static final String IMPORT_ELEMENT = "import"; 98 public static final String RESOURCE_ATTRIBUTE = "resource"; 99 100 public static final String ALIAS_ELEMENT = "alias"; 101 public static final String NAME_ATTRIBUTE = "name"; 102 public static final String ALIAS_ATTRIBUTE = "alias"; 103 104 public static final String BEAN_ELEMENT = "bean"; 105 public static final String ID_ATTRIBUTE = "id"; 106 public static final String PARENT_ATTRIBUTE = "parent"; 107 108 public static final String CLASS_ATTRIBUTE = "class"; 109 public static final String ABSTRACT_ATTRIBUTE = "abstract"; 110 public static final String SINGLETON_ATTRIBUTE = "singleton"; 111 public static final String LAZY_INIT_ATTRIBUTE = "lazy-init"; 112 public static final String AUTOWIRE_ATTRIBUTE = "autowire"; 113 public static final String DEPENDENCY_CHECK_ATTRIBUTE = "dependency-check"; 114 public static final String DEPENDS_ON_ATTRIBUTE = "depends-on"; 115 public static final String INIT_METHOD_ATTRIBUTE = "init-method"; 116 public static final String DESTROY_METHOD_ATTRIBUTE = "destroy-method"; 117 public static final String FACTORY_METHOD_ATTRIBUTE = "factory-method"; 118 public static final String FACTORY_BEAN_ATTRIBUTE = "factory-bean"; 119 120 public static final String CONSTRUCTOR_ARG_ELEMENT = "constructor-arg"; 121 public static final String INDEX_ATTRIBUTE = "index"; 122 public static final String TYPE_ATTRIBUTE = "type"; 123 public static final String PROPERTY_ELEMENT = "property"; 124 public static final String REF_ATTRIBUTE = "ref"; 125 public static final String VALUE_ATTRIBUTE = "value"; 126 public static final String LOOKUP_METHOD_ELEMENT = "lookup-method"; 127 128 public static final String REPLACED_METHOD_ELEMENT = "replaced-method"; 129 public static final String REPLACER_ATTRIBUTE = "replacer"; 130 public static final String ARG_TYPE_ELEMENT = "arg-type"; 131 public static final String ARG_TYPE_MATCH_ATTRIBUTE = "match"; 132 133 public static final String REF_ELEMENT = "ref"; 134 public static final String IDREF_ELEMENT = "idref"; 135 public static final String BEAN_REF_ATTRIBUTE = "bean"; 136 public static final String LOCAL_REF_ATTRIBUTE = "local"; 137 public static final String PARENT_REF_ATTRIBUTE = "parent"; 138 139 public static final String VALUE_ELEMENT = "value"; 140 public static final String NULL_ELEMENT = "null"; 141 public static final String LIST_ELEMENT = "list"; 142 public static final String SET_ELEMENT = "set"; 143 public static final String MAP_ELEMENT = "map"; 144 public static final String ENTRY_ELEMENT = "entry"; 145 public static final String KEY_ELEMENT = "key"; 146 public static final String KEY_ATTRIBUTE = "key"; 147 public static final String KEY_REF_ATTRIBUTE = "key-ref"; 148 public static final String VALUE_REF_ATTRIBUTE = "value-ref"; 149 public static final String PROPS_ELEMENT = "props"; 150 public static final String PROP_ELEMENT = "prop"; 151 152 153 protected final Log logger = LogFactory.getLog(getClass()); 154 155 private BeanDefinitionReader beanDefinitionReader; 156 157 private Resource resource; 158 159 private String defaultLazyInit; 160 161 private String defaultAutowire; 162 163 private String defaultDependencyCheck; 164 165 166 public int registerBeanDefinitions(BeanDefinitionReader reader, Document doc, Resource resource) 167 throws BeanDefinitionStoreException { 168 169 this.beanDefinitionReader = reader; 170 this.resource = resource; 171 172 logger.debug("Loading bean definitions"); 173 Element root = doc.getDocumentElement(); 174 preProcessXml(root); 175 176 this.defaultLazyInit = root.getAttribute(DEFAULT_LAZY_INIT_ATTRIBUTE); 177 this.defaultAutowire = root.getAttribute(DEFAULT_AUTOWIRE_ATTRIBUTE); 178 this.defaultDependencyCheck = root.getAttribute(DEFAULT_DEPENDENCY_CHECK_ATTRIBUTE); 179 if (logger.isDebugEnabled()) { 180 logger.debug("Default lazy init '" + this.defaultLazyInit + "'"); 181 logger.debug("Default autowire '" + this.defaultAutowire + "'"); 182 logger.debug("Default dependency check '" + this.defaultDependencyCheck + "'"); 183 } 184 185 int beanDefinitionCount = parseBeanDefinitions(root); 186 if (logger.isDebugEnabled()) { 187 logger.debug("Found " + beanDefinitionCount + " <bean> elements defining beans"); 188 } 189 return beanDefinitionCount; 190 } 191 192 195 protected final BeanDefinitionReader getBeanDefinitionReader() { 196 return beanDefinitionReader; 197 } 198 199 202 protected final Resource getResource() { 203 return resource; 204 } 205 206 209 protected final String getDefaultLazyInit() { 210 return defaultLazyInit; 211 } 212 213 216 protected final String getDefaultAutowire() { 217 return defaultAutowire; 218 } 219 220 223 protected final String getDefaultDependencyCheck() { 224 return defaultDependencyCheck; 225 } 226 227 228 239 protected void preProcessXml(Element root) throws BeanDefinitionStoreException { 240 } 241 242 248 protected int parseBeanDefinitions(Element root) throws BeanDefinitionStoreException { 249 NodeList nl = root.getChildNodes(); 250 int beanDefinitionCounter = 0; 251 for (int i = 0; i < nl.getLength(); i++) { 252 Node node = nl.item(i); 253 if (node instanceof Element ) { 254 Element ele = (Element ) node; 255 if (IMPORT_ELEMENT.equals(node.getNodeName())) { 256 importBeanDefinitionResource(ele); 257 } 258 else if (ALIAS_ELEMENT.equals(node.getNodeName())) { 259 String name = ele.getAttribute(NAME_ATTRIBUTE); 260 String alias = ele.getAttribute(ALIAS_ATTRIBUTE); 261 this.beanDefinitionReader.getBeanFactory().registerAlias(name, alias); 262 } 263 else if (BEAN_ELEMENT.equals(node.getNodeName())) { 264 beanDefinitionCounter++; 265 BeanDefinitionHolder bdHolder = parseBeanDefinitionElement(ele); 266 BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, this.beanDefinitionReader.getBeanFactory()); 267 } 268 } 269 } 270 return beanDefinitionCounter; 271 } 272 273 277 protected void importBeanDefinitionResource(Element ele) throws BeanDefinitionStoreException { 278 String location = ele.getAttribute(RESOURCE_ATTRIBUTE); 279 Resource relativeResource = null; 280 if (ResourceUtils.isUrl(location)) { 281 ResourceLoader resourceLoader = getBeanDefinitionReader().getResourceLoader(); 282 if (resourceLoader == null) { 283 throw new BeanDefinitionStoreException( 284 "Cannot import bean definitions from location [" + location + "]: no resource loader available"); 285 } 286 relativeResource = resourceLoader.getResource(location); 287 } 288 else { 289 try { 290 relativeResource = getResource().createRelative(location); 291 } 292 catch (IOException ex) { 293 throw new BeanDefinitionStoreException( 294 "Invalid relative resource location [" + location + "] to import bean definitions from", ex); 295 } 296 } 297 getBeanDefinitionReader().loadBeanDefinitions(relativeResource); 298 } 299 300 301 309 protected BeanDefinitionHolder parseBeanDefinitionElement(Element ele) throws BeanDefinitionStoreException { 310 String id = ele.getAttribute(ID_ATTRIBUTE); 311 String nameAttr = ele.getAttribute(NAME_ATTRIBUTE); 312 313 List aliases = new ArrayList (); 314 if (StringUtils.hasLength(nameAttr)) { 315 String [] nameArr = StringUtils.tokenizeToStringArray(nameAttr, BEAN_NAME_DELIMITERS); 316 aliases.addAll(Arrays.asList(nameArr)); 317 } 318 319 String beanName = id; 320 if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) { 321 beanName = (String ) aliases.remove(0); 322 if (logger.isDebugEnabled()) { 323 logger.debug("No XML 'id' specified - using '" + beanName + 324 "' as bean name and " + aliases + " as aliases"); 325 } 326 } 327 328 BeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName); 329 330 if (!StringUtils.hasText(beanName) && beanDefinition instanceof AbstractBeanDefinition) { 331 beanName = BeanDefinitionReaderUtils.generateBeanName( 332 (AbstractBeanDefinition) beanDefinition, this.beanDefinitionReader.getBeanFactory()); 333 if (logger.isDebugEnabled()) { 334 logger.debug("Neither XML 'id' nor 'name' specified - " + 335 "using generated bean name [" + beanName + "]"); 336 } 337 } 338 339 String [] aliasesArray = (String []) aliases.toArray(new String [aliases.size()]); 340 return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray); 341 } 342 343 346 protected BeanDefinition parseBeanDefinitionElement(Element ele, String beanName) 347 throws BeanDefinitionStoreException { 348 349 String className = null; 350 if (ele.hasAttribute(CLASS_ATTRIBUTE)) { 351 className = ele.getAttribute(CLASS_ATTRIBUTE); 352 } 353 String parent = null; 354 if (ele.hasAttribute(PARENT_ATTRIBUTE)) { 355 parent = ele.getAttribute(PARENT_ATTRIBUTE); 356 } 357 358 try { 359 ConstructorArgumentValues cargs = parseConstructorArgElements(ele, beanName); 360 MutablePropertyValues pvs = parsePropertyElements(ele, beanName); 361 362 AbstractBeanDefinition bd = BeanDefinitionReaderUtils.createBeanDefinition( 363 className, parent, cargs, pvs, getBeanDefinitionReader().getBeanClassLoader()); 364 365 if (ele.hasAttribute(DEPENDS_ON_ATTRIBUTE)) { 366 String dependsOn = ele.getAttribute(DEPENDS_ON_ATTRIBUTE); 367 bd.setDependsOn(StringUtils.tokenizeToStringArray(dependsOn, BEAN_NAME_DELIMITERS)); 368 } 369 370 if (ele.hasAttribute(FACTORY_METHOD_ATTRIBUTE)) { 371 bd.setFactoryMethodName(ele.getAttribute(FACTORY_METHOD_ATTRIBUTE)); 372 } 373 if (ele.hasAttribute(FACTORY_BEAN_ATTRIBUTE)) { 374 bd.setFactoryBeanName(ele.getAttribute(FACTORY_BEAN_ATTRIBUTE)); 375 } 376 377 String dependencyCheck = ele.getAttribute(DEPENDENCY_CHECK_ATTRIBUTE); 378 if (DEFAULT_VALUE.equals(dependencyCheck)) { 379 dependencyCheck = getDefaultDependencyCheck(); 380 } 381 bd.setDependencyCheck(getDependencyCheck(dependencyCheck)); 382 383 String autowire = ele.getAttribute(AUTOWIRE_ATTRIBUTE); 384 if (DEFAULT_VALUE.equals(autowire)) { 385 autowire = getDefaultAutowire(); 386 } 387 bd.setAutowireMode(getAutowireMode(autowire)); 388 389 String initMethodName = ele.getAttribute(INIT_METHOD_ATTRIBUTE); 390 if (!initMethodName.equals("")) { 391 bd.setInitMethodName(initMethodName); 392 } 393 String destroyMethodName = ele.getAttribute(DESTROY_METHOD_ATTRIBUTE); 394 if (!destroyMethodName.equals("")) { 395 bd.setDestroyMethodName(destroyMethodName); 396 } 397 398 parseLookupOverrideSubElements(ele, beanName, bd.getMethodOverrides()); 399 parseReplacedMethodSubElements(ele, beanName, bd.getMethodOverrides()); 400 401 bd.setResourceDescription(getResource().getDescription()); 402 403 if (ele.hasAttribute(ABSTRACT_ATTRIBUTE)) { 404 bd.setAbstract(TRUE_VALUE.equals(ele.getAttribute(ABSTRACT_ATTRIBUTE))); 405 } 406 407 if (ele.hasAttribute(SINGLETON_ATTRIBUTE)) { 408 bd.setSingleton(TRUE_VALUE.equals(ele.getAttribute(SINGLETON_ATTRIBUTE))); 409 } 410 411 String lazyInit = ele.getAttribute(LAZY_INIT_ATTRIBUTE); 412 if (DEFAULT_VALUE.equals(lazyInit) && bd.isSingleton()) { 413 lazyInit = this.defaultLazyInit; 415 } 416 bd.setLazyInit(TRUE_VALUE.equals(lazyInit)); 417 418 return bd; 419 } 420 catch (ClassNotFoundException ex) { 421 throw new BeanDefinitionStoreException( 422 this.resource, beanName, "Bean class [" + className + "] not found", ex); 423 } 424 catch (NoClassDefFoundError err) { 425 throw new BeanDefinitionStoreException( 426 this.resource, beanName, "Class that bean class [" + className + "] depends on not found", err); 427 } 428 } 429 430 protected int getDependencyCheck(String att) { 431 int dependencyCheckCode = AbstractBeanDefinition.DEPENDENCY_CHECK_NONE; 432 if (DEPENDENCY_CHECK_ALL_ATTRIBUTE_VALUE.equals(att)) { 433 dependencyCheckCode = AbstractBeanDefinition.DEPENDENCY_CHECK_ALL; 434 } 435 else if (DEPENDENCY_CHECK_SIMPLE_ATTRIBUTE_VALUE.equals(att)) { 436 dependencyCheckCode = AbstractBeanDefinition.DEPENDENCY_CHECK_SIMPLE; 437 } 438 else if (DEPENDENCY_CHECK_OBJECTS_ATTRIBUTE_VALUE.equals(att)) { 439 dependencyCheckCode = AbstractBeanDefinition.DEPENDENCY_CHECK_OBJECTS; 440 } 441 return dependencyCheckCode; 443 } 444 445 protected int getAutowireMode(String att) { 446 int autowire = AbstractBeanDefinition.AUTOWIRE_NO; 447 if (AUTOWIRE_BY_NAME_VALUE.equals(att)) { 448 autowire = AbstractBeanDefinition.AUTOWIRE_BY_NAME; 449 } 450 else if (AUTOWIRE_BY_TYPE_VALUE.equals(att)) { 451 autowire = AbstractBeanDefinition.AUTOWIRE_BY_TYPE; 452 } 453 else if (AUTOWIRE_CONSTRUCTOR_VALUE.equals(att)) { 454 autowire = AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR; 455 } 456 else if (AUTOWIRE_AUTODETECT_VALUE.equals(att)) { 457 autowire = AbstractBeanDefinition.AUTOWIRE_AUTODETECT; 458 } 459 return autowire; 461 } 462 463 464 467 protected ConstructorArgumentValues parseConstructorArgElements(Element beanEle, String beanName) 468 throws BeanDefinitionStoreException { 469 470 NodeList nl = beanEle.getChildNodes(); 471 ConstructorArgumentValues cargs = new ConstructorArgumentValues(); 472 for (int i = 0; i < nl.getLength(); i++) { 473 Node node = nl.item(i); 474 if (node instanceof Element && CONSTRUCTOR_ARG_ELEMENT.equals(node.getNodeName())) { 475 parseConstructorArgElement((Element ) node, beanName, cargs); 476 } 477 } 478 return cargs; 479 } 480 481 484 protected MutablePropertyValues parsePropertyElements(Element beanEle, String beanName) 485 throws BeanDefinitionStoreException { 486 487 NodeList nl = beanEle.getChildNodes(); 488 MutablePropertyValues pvs = new MutablePropertyValues(); 489 for (int i = 0; i < nl.getLength(); i++) { 490 Node node = nl.item(i); 491 if (node instanceof Element && PROPERTY_ELEMENT.equals(node.getNodeName())) { 492 parsePropertyElement((Element ) node, beanName, pvs); 493 } 494 } 495 return pvs; 496 } 497 498 501 protected void parseLookupOverrideSubElements(Element beanEle, String beanName, MethodOverrides overrides) 502 throws BeanDefinitionStoreException { 503 504 NodeList nl = beanEle.getChildNodes(); 505 for (int i = 0; i < nl.getLength(); i++) { 506 Node node = nl.item(i); 507 if (node instanceof Element && LOOKUP_METHOD_ELEMENT.equals(node.getNodeName())) { 508 Element ele = (Element ) node; 509 String methodName = ele.getAttribute(NAME_ATTRIBUTE); 510 String beanRef = ele.getAttribute(BEAN_ELEMENT); 511 overrides.addOverride(new LookupOverride(methodName, beanRef)); 512 } 513 } 514 } 515 516 519 protected void parseReplacedMethodSubElements(Element beanEle, String beanName, MethodOverrides overrides) 520 throws BeanDefinitionStoreException { 521 522 NodeList nl = beanEle.getChildNodes(); 523 for (int i = 0; i < nl.getLength(); i++) { 524 Node node = nl.item(i); 525 if (node instanceof Element && REPLACED_METHOD_ELEMENT.equals(node.getNodeName())) { 526 Element replacedMethodEle = (Element ) node; 527 String name = replacedMethodEle.getAttribute(NAME_ATTRIBUTE); 528 String callback = replacedMethodEle.getAttribute(REPLACER_ATTRIBUTE); 529 ReplaceOverride replaceOverride = new ReplaceOverride(name, callback); 530 List argTypeEles = DomUtils.getChildElementsByTagName(replacedMethodEle, ARG_TYPE_ELEMENT); 532 for (Iterator it = argTypeEles.iterator(); it.hasNext();) { 533 Element argTypeEle = (Element ) it.next(); 534 replaceOverride.addTypeIdentifier(argTypeEle.getAttribute(ARG_TYPE_MATCH_ATTRIBUTE)); 535 } 536 overrides.addOverride(replaceOverride); 537 } 538 } 539 } 540 541 544 protected void parseConstructorArgElement(Element ele, String beanName, ConstructorArgumentValues cargs) 545 throws BeanDefinitionStoreException { 546 547 Object val = parsePropertyValue(ele, beanName, null); 548 String indexAttr = ele.getAttribute(INDEX_ATTRIBUTE); 549 String typeAttr = ele.getAttribute(TYPE_ATTRIBUTE); 550 if (StringUtils.hasLength(indexAttr)) { 551 try { 552 int index = Integer.parseInt(indexAttr); 553 if (index < 0) { 554 throw new BeanDefinitionStoreException(getResource(), beanName, "'index' cannot be lower than 0"); 555 } 556 if (StringUtils.hasLength(typeAttr)) { 557 cargs.addIndexedArgumentValue(index, val, typeAttr); 558 } 559 else { 560 cargs.addIndexedArgumentValue(index, val); 561 } 562 } 563 catch (NumberFormatException ex) { 564 throw new BeanDefinitionStoreException(getResource(), beanName, 565 "Attribute 'index' of tag 'constructor-arg' must be an integer"); 566 } 567 } 568 else { 569 if (StringUtils.hasLength(typeAttr)) { 570 cargs.addGenericArgumentValue(val, typeAttr); 571 } 572 else { 573 cargs.addGenericArgumentValue(val); 574 } 575 } 576 } 577 578 581 protected void parsePropertyElement(Element ele, String beanName, MutablePropertyValues pvs) 582 throws BeanDefinitionStoreException { 583 584 String propertyName = ele.getAttribute(NAME_ATTRIBUTE); 585 if (!StringUtils.hasLength(propertyName)) { 586 throw new BeanDefinitionStoreException( 587 getResource(), beanName, "Tag 'property' must have a 'name' attribute"); 588 } 589 if (pvs.contains(propertyName)) { 590 throw new BeanDefinitionStoreException( 591 getResource(), beanName, "Multiple 'property' definitions for property '" + propertyName + "'"); 592 } 593 Object val = parsePropertyValue(ele, beanName, propertyName); 594 pvs.addPropertyValue(propertyName, val); 595 } 596 597 598 602 protected Object parsePropertyValue(Element ele, String beanName, String propertyName) 603 throws BeanDefinitionStoreException { 604 605 String elementName = (propertyName != null) ? 606 "<property> element for property '" + propertyName + "'" : 607 "<constructor-arg> element"; 608 609 NodeList nl = ele.getChildNodes(); 611 Element subElement = null; 612 for (int i = 0; i < nl.getLength(); i++) { 613 if (nl.item(i) instanceof Element ) { 614 Element candidateEle = (Element ) nl.item(i); 615 if (DESCRIPTION_ELEMENT.equals(candidateEle.getTagName())) { 616 } 618 else { 619 if (subElement != null) { 621 throw new BeanDefinitionStoreException( 622 getResource(), beanName, elementName + " must not contain more than one sub-element"); 623 } 624 subElement = candidateEle; 625 } 626 } 627 } 628 629 boolean hasRefAttribute = ele.hasAttribute(REF_ATTRIBUTE); 630 boolean hasValueAttribute = ele.hasAttribute(VALUE_ATTRIBUTE); 631 if ((hasRefAttribute && hasValueAttribute) || 632 ((hasRefAttribute || hasValueAttribute)) && subElement != null) { 633 throw new BeanDefinitionStoreException( 634 getResource(), beanName, elementName + 635 " is only allowed to contain either a 'ref' attribute OR a 'value' attribute OR a sub-element"); 636 } 637 if (hasRefAttribute) { 638 return new RuntimeBeanReference(ele.getAttribute(REF_ATTRIBUTE)); 639 } 640 else if (hasValueAttribute) { 641 return ele.getAttribute(VALUE_ATTRIBUTE); 642 } 643 644 if (subElement == null) { 645 throw new BeanDefinitionStoreException( 647 getResource(), beanName, elementName + " must specify a ref or value"); 648 } 649 650 return parsePropertySubElement(subElement, beanName); 651 } 652 653 658 protected Object parsePropertySubElement(Element ele, String beanName) throws BeanDefinitionStoreException { 659 if (ele.getTagName().equals(BEAN_ELEMENT)) { 660 return parseBeanDefinitionElement(ele); 661 } 662 else if (ele.getTagName().equals(REF_ELEMENT)) { 663 String beanRef = ele.getAttribute(BEAN_REF_ATTRIBUTE); 665 if (!StringUtils.hasLength(beanRef)) { 666 beanRef = ele.getAttribute(LOCAL_REF_ATTRIBUTE); 668 if (!StringUtils.hasLength(beanRef)) { 669 beanRef = ele.getAttribute(PARENT_REF_ATTRIBUTE); 671 if (!StringUtils.hasLength(beanRef)) { 672 throw new BeanDefinitionStoreException( 673 getResource(), beanName, "'bean', 'local' or 'parent' is required for a reference"); 674 } 675 return new RuntimeBeanReference(beanRef, true); 676 } 677 } 678 return new RuntimeBeanReference(beanRef); 679 } 680 else if (ele.getTagName().equals(IDREF_ELEMENT)) { 681 String beanRef = ele.getAttribute(BEAN_REF_ATTRIBUTE); 683 if (!StringUtils.hasLength(beanRef)) { 684 beanRef = ele.getAttribute(LOCAL_REF_ATTRIBUTE); 686 if (!StringUtils.hasLength(beanRef)) { 687 throw new BeanDefinitionStoreException( 688 getResource(), beanName, "Either 'bean' or 'local' is required for an idref"); 689 } 690 } 691 return beanRef; 692 } 693 else if (ele.getTagName().equals(VALUE_ELEMENT)) { 694 String value = DomUtils.getTextValue(ele); 696 if (ele.hasAttribute(TYPE_ATTRIBUTE)) { 697 String typeClassName = ele.getAttribute(TYPE_ATTRIBUTE); 698 try { 699 Class typeClass = ClassUtils.forName(typeClassName, this.beanDefinitionReader.getBeanClassLoader()); 700 return new TypedStringValue(value, typeClass); 701 } 702 catch (ClassNotFoundException ex) { 703 throw new BeanDefinitionStoreException( 704 getResource(), beanName, "Value type class [" + typeClassName + "] not found", ex); 705 } 706 } 707 return value; 708 } 709 else if (ele.getTagName().equals(NULL_ELEMENT)) { 710 return null; 712 } 713 else if (ele.getTagName().equals(LIST_ELEMENT)) { 714 return parseListElement(ele, beanName); 715 } 716 else if (ele.getTagName().equals(SET_ELEMENT)) { 717 return parseSetElement(ele, beanName); 718 } 719 else if (ele.getTagName().equals(MAP_ELEMENT)) { 720 return parseMapElement(ele, beanName); 721 } 722 else if (ele.getTagName().equals(PROPS_ELEMENT)) { 723 return parsePropsElement(ele, beanName); 724 } 725 throw new BeanDefinitionStoreException( 726 getResource(), beanName, "Unknown property sub-element: <" + ele.getTagName() + ">"); 727 } 728 729 732 protected List parseListElement(Element collectionEle, String beanName) throws BeanDefinitionStoreException { 733 NodeList nl = collectionEle.getChildNodes(); 734 ManagedList list = new ManagedList(nl.getLength()); 735 for (int i = 0; i < nl.getLength(); i++) { 736 if (nl.item(i) instanceof Element ) { 737 Element ele = (Element ) nl.item(i); 738 list.add(parsePropertySubElement(ele, beanName)); 739 } 740 } 741 return list; 742 } 743 744 747 protected Set parseSetElement(Element collectionEle, String beanName) throws BeanDefinitionStoreException { 748 NodeList nl = collectionEle.getChildNodes(); 749 ManagedSet set = new ManagedSet(nl.getLength()); 750 for (int i = 0; i < nl.getLength(); i++) { 751 if (nl.item(i) instanceof Element ) { 752 Element ele = (Element ) nl.item(i); 753 set.add(parsePropertySubElement(ele, beanName)); 754 } 755 } 756 return set; 757 } 758 759 762 protected Map parseMapElement(Element mapEle, String beanName) throws BeanDefinitionStoreException { 763 List entryEles = DomUtils.getChildElementsByTagName(mapEle, ENTRY_ELEMENT); 764 Map map = new ManagedMap(entryEles.size()); 765 766 for (Iterator it = entryEles.iterator(); it.hasNext();) { 767 Element entryEle = (Element ) it.next(); 768 NodeList entrySubNodes = entryEle.getChildNodes(); 771 772 Element keyEle = null; 773 Element valueEle = null; 774 for (int j = 0; j < entrySubNodes.getLength(); j++) { 775 if (entrySubNodes.item(j) instanceof Element ) { 776 Element candidateEle = (Element ) entrySubNodes.item(j); 777 if (candidateEle.getTagName().equals(KEY_ELEMENT)) { 778 if (keyEle != null) { 779 throw new BeanDefinitionStoreException( 780 getResource(), beanName, "<entry> is only allowed to contain one <key> sub-element"); 781 } 782 keyEle = candidateEle; 783 } 784 else { 785 if (valueEle != null) { 787 throw new BeanDefinitionStoreException( 788 getResource(), beanName, "<entry> must not contain more than one value sub-element"); 789 } 790 valueEle = candidateEle; 791 } 792 } 793 } 794 795 Object key = null; 797 boolean hasKeyAttribute = entryEle.hasAttribute(KEY_ATTRIBUTE); 798 boolean hasKeyRefAttribute = entryEle.hasAttribute(KEY_REF_ATTRIBUTE); 799 if ((hasKeyAttribute && hasKeyRefAttribute) || 800 ((hasKeyAttribute || hasKeyRefAttribute)) && keyEle != null) { 801 throw new BeanDefinitionStoreException( 802 getResource(), beanName, "<entry> is only allowed to contain either " + 803 "a 'key' attribute OR a 'key-ref' attribute OR a <key> sub-element"); 804 } 805 if (hasKeyAttribute) { 806 key = entryEle.getAttribute(KEY_ATTRIBUTE); 807 } 808 else if (hasKeyRefAttribute) { 809 key = new RuntimeBeanReference(entryEle.getAttribute(KEY_REF_ATTRIBUTE)); 810 } 811 else if (keyEle != null) { 812 key = parseKeyElement(keyEle, beanName); 813 } 814 else { 815 throw new BeanDefinitionStoreException( 816 getResource(), beanName, "<entry> must specify a key"); 817 } 818 819 Object value = null; 821 boolean hasValueAttribute = entryEle.hasAttribute(VALUE_ATTRIBUTE); 822 boolean hasValueRefAttribute = entryEle.hasAttribute(VALUE_REF_ATTRIBUTE); 823 if ((hasValueAttribute && hasValueRefAttribute) || 824 ((hasValueAttribute || hasValueRefAttribute)) && valueEle != null) { 825 throw new BeanDefinitionStoreException( 826 getResource(), beanName, "<entry> is only allowed to contain either " + 827 "a 'value' attribute OR a 'value-ref' attribute OR a value sub-element"); 828 } 829 if (hasValueAttribute) { 830 value = entryEle.getAttribute(VALUE_ATTRIBUTE); 831 } 832 else if (hasValueRefAttribute) { 833 value = new RuntimeBeanReference(entryEle.getAttribute(VALUE_REF_ATTRIBUTE)); 834 } 835 else if (valueEle != null) { 836 value = parsePropertySubElement(valueEle, beanName); 837 } 838 else { 839 throw new BeanDefinitionStoreException( 840 getResource(), beanName, "<entry> must specify a value"); 841 } 842 843 map.put(key, value); 845 } 846 847 return map; 848 } 849 850 853 protected Object parseKeyElement(Element keyEle, String beanName) throws BeanDefinitionStoreException { 854 NodeList nl = keyEle.getChildNodes(); 855 Element subElement = null; 856 for (int i = 0; i < nl.getLength(); i++) { 857 if (nl.item(i) instanceof Element ) { 858 Element candidateEle = (Element ) nl.item(i); 859 if (subElement != null) { 861 throw new BeanDefinitionStoreException( 862 getResource(), beanName, "<key> must not contain more than one value sub-element"); 863 } 864 subElement = candidateEle; 865 } 866 } 867 return parsePropertySubElement(subElement, beanName); 868 } 869 870 873 protected Properties parsePropsElement(Element propsEle, String beanName) throws BeanDefinitionStoreException { 874 Properties props = new Properties (); 875 List propEles = DomUtils.getChildElementsByTagName(propsEle, PROP_ELEMENT); 876 for (Iterator it = propEles.iterator(); it.hasNext();) { 877 Element propEle = (Element ) it.next(); 878 String key = propEle.getAttribute(KEY_ATTRIBUTE); 879 String value = DomUtils.getTextValue(propEle).trim(); 882 props.setProperty(key, value); 883 } 884 return props; 885 } 886 887 } 888 | Popular Tags |