KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > springframework > beans > factory > xml > DefaultXmlBeanDefinitionParser


1 /*
2  * Copyright 2002-2005 the original author or authors.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16
17 package org.springframework.beans.factory.xml;
18
19 import java.io.IOException JavaDoc;
20 import java.util.ArrayList JavaDoc;
21 import java.util.Arrays JavaDoc;
22 import java.util.Iterator JavaDoc;
23 import java.util.List JavaDoc;
24 import java.util.Map JavaDoc;
25 import java.util.Properties JavaDoc;
26 import java.util.Set JavaDoc;
27
28 import org.apache.commons.logging.Log;
29 import org.apache.commons.logging.LogFactory;
30 import org.w3c.dom.Document JavaDoc;
31 import org.w3c.dom.Element JavaDoc;
32 import org.w3c.dom.Node JavaDoc;
33 import org.w3c.dom.NodeList JavaDoc;
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 /**
59  * Default implementation of the XmlBeanDefinitionParser interface.
60  * Parses bean definitions according to the "spring-beans" DTD,
61  * that is, Spring's default XML bean definition format.
62  *
63  * <p>The structure, elements and attribute names of the required XML document
64  * are hard-coded in this class. (Of course a transform could be run if necessary
65  * to produce this format). "beans" doesn't need to be the root element of the XML
66  * document: This class will parse all bean definition elements in the XML file.
67  *
68  * @author Rod Johnson
69  * @author Juergen Hoeller
70  * @since 18.12.2003
71  */

72 public class DefaultXmlBeanDefinitionParser implements XmlBeanDefinitionParser {
73
74     public static final String JavaDoc BEAN_NAME_DELIMITERS = ",; ";
75
76     /**
77      * Value of a T/F attribute that represents true.
78      * Anything else represents false. Case seNsItive.
79      */

80     public static final String JavaDoc TRUE_VALUE = "true";
81     public static final String JavaDoc DEFAULT_VALUE = "default";
82     public static final String JavaDoc DESCRIPTION_ELEMENT = "description";
83
84     public static final String JavaDoc AUTOWIRE_BY_NAME_VALUE = "byName";
85     public static final String JavaDoc AUTOWIRE_BY_TYPE_VALUE = "byType";
86     public static final String JavaDoc AUTOWIRE_CONSTRUCTOR_VALUE = "constructor";
87     public static final String JavaDoc AUTOWIRE_AUTODETECT_VALUE = "autodetect";
88
89     public static final String JavaDoc DEPENDENCY_CHECK_ALL_ATTRIBUTE_VALUE = "all";
90     public static final String JavaDoc DEPENDENCY_CHECK_SIMPLE_ATTRIBUTE_VALUE = "simple";
91     public static final String JavaDoc DEPENDENCY_CHECK_OBJECTS_ATTRIBUTE_VALUE = "objects";
92
93     public static final String JavaDoc DEFAULT_LAZY_INIT_ATTRIBUTE = "default-lazy-init";
94     public static final String JavaDoc DEFAULT_AUTOWIRE_ATTRIBUTE = "default-autowire";
95     public static final String JavaDoc DEFAULT_DEPENDENCY_CHECK_ATTRIBUTE = "default-dependency-check";
96
97     public static final String JavaDoc IMPORT_ELEMENT = "import";
98     public static final String JavaDoc RESOURCE_ATTRIBUTE = "resource";
99
100     public static final String JavaDoc ALIAS_ELEMENT = "alias";
101     public static final String JavaDoc NAME_ATTRIBUTE = "name";
102     public static final String JavaDoc ALIAS_ATTRIBUTE = "alias";
103
104     public static final String JavaDoc BEAN_ELEMENT = "bean";
105     public static final String JavaDoc ID_ATTRIBUTE = "id";
106     public static final String JavaDoc PARENT_ATTRIBUTE = "parent";
107
108     public static final String JavaDoc CLASS_ATTRIBUTE = "class";
109     public static final String JavaDoc ABSTRACT_ATTRIBUTE = "abstract";
110     public static final String JavaDoc SINGLETON_ATTRIBUTE = "singleton";
111     public static final String JavaDoc LAZY_INIT_ATTRIBUTE = "lazy-init";
112     public static final String JavaDoc AUTOWIRE_ATTRIBUTE = "autowire";
113     public static final String JavaDoc DEPENDENCY_CHECK_ATTRIBUTE = "dependency-check";
114     public static final String JavaDoc DEPENDS_ON_ATTRIBUTE = "depends-on";
115     public static final String JavaDoc INIT_METHOD_ATTRIBUTE = "init-method";
116     public static final String JavaDoc DESTROY_METHOD_ATTRIBUTE = "destroy-method";
117     public static final String JavaDoc FACTORY_METHOD_ATTRIBUTE = "factory-method";
118     public static final String JavaDoc FACTORY_BEAN_ATTRIBUTE = "factory-bean";
119
120     public static final String JavaDoc CONSTRUCTOR_ARG_ELEMENT = "constructor-arg";
121     public static final String JavaDoc INDEX_ATTRIBUTE = "index";
122     public static final String JavaDoc TYPE_ATTRIBUTE = "type";
123     public static final String JavaDoc PROPERTY_ELEMENT = "property";
124     public static final String JavaDoc REF_ATTRIBUTE = "ref";
125     public static final String JavaDoc VALUE_ATTRIBUTE = "value";
126     public static final String JavaDoc LOOKUP_METHOD_ELEMENT = "lookup-method";
127
128     public static final String JavaDoc REPLACED_METHOD_ELEMENT = "replaced-method";
129     public static final String JavaDoc REPLACER_ATTRIBUTE = "replacer";
130     public static final String JavaDoc ARG_TYPE_ELEMENT = "arg-type";
131     public static final String JavaDoc ARG_TYPE_MATCH_ATTRIBUTE = "match";
132
133     public static final String JavaDoc REF_ELEMENT = "ref";
134     public static final String JavaDoc IDREF_ELEMENT = "idref";
135     public static final String JavaDoc BEAN_REF_ATTRIBUTE = "bean";
136     public static final String JavaDoc LOCAL_REF_ATTRIBUTE = "local";
137     public static final String JavaDoc PARENT_REF_ATTRIBUTE = "parent";
138
139     public static final String JavaDoc VALUE_ELEMENT = "value";
140     public static final String JavaDoc NULL_ELEMENT = "null";
141     public static final String JavaDoc LIST_ELEMENT = "list";
142     public static final String JavaDoc SET_ELEMENT = "set";
143     public static final String JavaDoc MAP_ELEMENT = "map";
144     public static final String JavaDoc ENTRY_ELEMENT = "entry";
145     public static final String JavaDoc KEY_ELEMENT = "key";
146     public static final String JavaDoc KEY_ATTRIBUTE = "key";
147     public static final String JavaDoc KEY_REF_ATTRIBUTE = "key-ref";
148     public static final String JavaDoc VALUE_REF_ATTRIBUTE = "value-ref";
149     public static final String JavaDoc PROPS_ELEMENT = "props";
150     public static final String JavaDoc 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 JavaDoc defaultLazyInit;
160
161     private String JavaDoc defaultAutowire;
162
163     private String JavaDoc defaultDependencyCheck;
164
165
166     public int registerBeanDefinitions(BeanDefinitionReader reader, Document JavaDoc doc, Resource resource)
167             throws BeanDefinitionStoreException {
168
169         this.beanDefinitionReader = reader;
170         this.resource = resource;
171
172         logger.debug("Loading bean definitions");
173         Element JavaDoc 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     /**
193      * Return the BeanDefinitionReader that this parser has been called from.
194      */

195     protected final BeanDefinitionReader getBeanDefinitionReader() {
196         return beanDefinitionReader;
197     }
198
199     /**
200      * Return the descriptor for the XML resource that this parser works on.
201      */

202     protected final Resource getResource() {
203         return resource;
204     }
205
206     /**
207      * Return the default lazy-init flag for the document that's currently parsed.
208      */

209     protected final String JavaDoc getDefaultLazyInit() {
210         return defaultLazyInit;
211     }
212
213     /**
214      * Return the default autowire setting for the document that's currently parsed.
215      */

216     protected final String JavaDoc getDefaultAutowire() {
217         return defaultAutowire;
218     }
219
220     /**
221      * Return the default dependency-check setting for the document that's currently parsed.
222      */

223     protected final String JavaDoc getDefaultDependencyCheck() {
224         return defaultDependencyCheck;
225     }
226
227
228     /**
229      * Allow the XML to be extensible by processing any custom element types first,
230      * before we start to process the bean definitions. This method is a natural
231      * extension point for any other custom pre processing of the XML.
232      * <p>Default implementation is empty. Subclasses can override this method to
233      * convert custom elements into standard Spring bean definitions, for example.
234      * Implementors have access to the parser's bean definition reader and the
235      * underlying XML resource, through the corresponding accessors.
236      * @see #getBeanDefinitionReader()
237      * @see #getResource()
238      */

239     protected void preProcessXml(Element JavaDoc root) throws BeanDefinitionStoreException {
240     }
241
242     /**
243      * Parse the elements at the root level in the document:
244      * "import", "alias", "bean".
245      * @param root the DOM root element of the document
246      * @return the number of bean definitions found
247      */

248     protected int parseBeanDefinitions(Element JavaDoc root) throws BeanDefinitionStoreException {
249         NodeList JavaDoc nl = root.getChildNodes();
250         int beanDefinitionCounter = 0;
251         for (int i = 0; i < nl.getLength(); i++) {
252             Node JavaDoc node = nl.item(i);
253             if (node instanceof Element JavaDoc) {
254                 Element JavaDoc ele = (Element JavaDoc) node;
255                 if (IMPORT_ELEMENT.equals(node.getNodeName())) {
256                     importBeanDefinitionResource(ele);
257                 }
258                 else if (ALIAS_ELEMENT.equals(node.getNodeName())) {
259                     String JavaDoc name = ele.getAttribute(NAME_ATTRIBUTE);
260                     String JavaDoc 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     /**
274      * Parse an "import" element and load the bean definitions
275      * from the given resource into the bean factory.
276      */

277     protected void importBeanDefinitionResource(Element JavaDoc ele) throws BeanDefinitionStoreException {
278         String JavaDoc 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 JavaDoc 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     /**
302      * Parse a standard bean definition into a BeanDefinitionHolder,
303      * including bean name and aliases.
304      * <p>Bean elements specify their canonical name as "id" attribute
305      * and their aliases as a delimited "name" attribute.
306      * <p>If no "id" specified, uses the first name in the "name" attribute
307      * as canonical name, registering all others as aliases.
308      */

309     protected BeanDefinitionHolder parseBeanDefinitionElement(Element JavaDoc ele) throws BeanDefinitionStoreException {
310         String JavaDoc id = ele.getAttribute(ID_ATTRIBUTE);
311         String JavaDoc nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
312
313         List JavaDoc aliases = new ArrayList JavaDoc();
314         if (StringUtils.hasLength(nameAttr)) {
315             String JavaDoc[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, BEAN_NAME_DELIMITERS);
316             aliases.addAll(Arrays.asList(nameArr));
317         }
318
319         String JavaDoc beanName = id;
320         if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
321             beanName = (String JavaDoc) 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 JavaDoc[] aliasesArray = (String JavaDoc[]) aliases.toArray(new String JavaDoc[aliases.size()]);
340         return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
341     }
342
343     /**
344      * Parse the BeanDefinition itself, without regard to name or aliases.
345      */

346     protected BeanDefinition parseBeanDefinitionElement(Element JavaDoc ele, String JavaDoc beanName)
347             throws BeanDefinitionStoreException {
348
349         String JavaDoc className = null;
350         if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
351             className = ele.getAttribute(CLASS_ATTRIBUTE);
352         }
353         String JavaDoc 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 JavaDoc 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 JavaDoc dependencyCheck = ele.getAttribute(DEPENDENCY_CHECK_ATTRIBUTE);
378             if (DEFAULT_VALUE.equals(dependencyCheck)) {
379                 dependencyCheck = getDefaultDependencyCheck();
380             }
381             bd.setDependencyCheck(getDependencyCheck(dependencyCheck));
382
383             String JavaDoc autowire = ele.getAttribute(AUTOWIRE_ATTRIBUTE);
384             if (DEFAULT_VALUE.equals(autowire)) {
385                 autowire = getDefaultAutowire();
386             }
387             bd.setAutowireMode(getAutowireMode(autowire));
388
389             String JavaDoc initMethodName = ele.getAttribute(INIT_METHOD_ATTRIBUTE);
390             if (!initMethodName.equals("")) {
391                 bd.setInitMethodName(initMethodName);
392             }
393             String JavaDoc 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 JavaDoc lazyInit = ele.getAttribute(LAZY_INIT_ATTRIBUTE);
412             if (DEFAULT_VALUE.equals(lazyInit) && bd.isSingleton()) {
413                 // Just apply default to singletons, as lazy-init has no meaning for prototypes.
414
lazyInit = this.defaultLazyInit;
415             }
416             bd.setLazyInit(TRUE_VALUE.equals(lazyInit));
417
418             return bd;
419         }
420         catch (ClassNotFoundException JavaDoc ex) {
421             throw new BeanDefinitionStoreException(
422                     this.resource, beanName, "Bean class [" + className + "] not found", ex);
423         }
424         catch (NoClassDefFoundError JavaDoc 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 JavaDoc 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         // Else leave default value.
442
return dependencyCheckCode;
443     }
444
445     protected int getAutowireMode(String JavaDoc 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         // Else leave default value.
460
return autowire;
461     }
462
463
464     /**
465      * Parse constructor-arg sub-elements of the given bean element.
466      */

467     protected ConstructorArgumentValues parseConstructorArgElements(Element JavaDoc beanEle, String JavaDoc beanName)
468             throws BeanDefinitionStoreException {
469
470         NodeList JavaDoc nl = beanEle.getChildNodes();
471         ConstructorArgumentValues cargs = new ConstructorArgumentValues();
472         for (int i = 0; i < nl.getLength(); i++) {
473             Node JavaDoc node = nl.item(i);
474             if (node instanceof Element JavaDoc && CONSTRUCTOR_ARG_ELEMENT.equals(node.getNodeName())) {
475                 parseConstructorArgElement((Element JavaDoc) node, beanName, cargs);
476             }
477         }
478         return cargs;
479     }
480
481     /**
482      * Parse property sub-elements of the given bean element.
483      */

484     protected MutablePropertyValues parsePropertyElements(Element JavaDoc beanEle, String JavaDoc beanName)
485             throws BeanDefinitionStoreException {
486
487         NodeList JavaDoc nl = beanEle.getChildNodes();
488         MutablePropertyValues pvs = new MutablePropertyValues();
489         for (int i = 0; i < nl.getLength(); i++) {
490             Node JavaDoc node = nl.item(i);
491             if (node instanceof Element JavaDoc && PROPERTY_ELEMENT.equals(node.getNodeName())) {
492                 parsePropertyElement((Element JavaDoc) node, beanName, pvs);
493             }
494         }
495         return pvs;
496     }
497
498     /**
499      * Parse lookup-override sub-elements of the given bean element.
500      */

501     protected void parseLookupOverrideSubElements(Element JavaDoc beanEle, String JavaDoc beanName, MethodOverrides overrides)
502             throws BeanDefinitionStoreException {
503
504         NodeList JavaDoc nl = beanEle.getChildNodes();
505         for (int i = 0; i < nl.getLength(); i++) {
506             Node JavaDoc node = nl.item(i);
507             if (node instanceof Element JavaDoc && LOOKUP_METHOD_ELEMENT.equals(node.getNodeName())) {
508                 Element JavaDoc ele = (Element JavaDoc) node;
509                 String JavaDoc methodName = ele.getAttribute(NAME_ATTRIBUTE);
510                 String JavaDoc beanRef = ele.getAttribute(BEAN_ELEMENT);
511                 overrides.addOverride(new LookupOverride(methodName, beanRef));
512             }
513         }
514     }
515
516     /**
517      * Parse replaced-method sub-elements of the given bean element.
518      */

519     protected void parseReplacedMethodSubElements(Element JavaDoc beanEle, String JavaDoc beanName, MethodOverrides overrides)
520             throws BeanDefinitionStoreException {
521
522         NodeList JavaDoc nl = beanEle.getChildNodes();
523         for (int i = 0; i < nl.getLength(); i++) {
524             Node JavaDoc node = nl.item(i);
525             if (node instanceof Element JavaDoc && REPLACED_METHOD_ELEMENT.equals(node.getNodeName())) {
526                 Element JavaDoc replacedMethodEle = (Element JavaDoc) node;
527                 String JavaDoc name = replacedMethodEle.getAttribute(NAME_ATTRIBUTE);
528                 String JavaDoc callback = replacedMethodEle.getAttribute(REPLACER_ATTRIBUTE);
529                 ReplaceOverride replaceOverride = new ReplaceOverride(name, callback);
530                 // Look for arg-type match elements.
531
List JavaDoc argTypeEles = DomUtils.getChildElementsByTagName(replacedMethodEle, ARG_TYPE_ELEMENT);
532                 for (Iterator JavaDoc it = argTypeEles.iterator(); it.hasNext();) {
533                     Element JavaDoc argTypeEle = (Element JavaDoc) it.next();
534                     replaceOverride.addTypeIdentifier(argTypeEle.getAttribute(ARG_TYPE_MATCH_ATTRIBUTE));
535                 }
536                 overrides.addOverride(replaceOverride);
537             }
538         }
539     }
540
541     /**
542      * Parse a constructor-arg element.
543      */

544     protected void parseConstructorArgElement(Element JavaDoc ele, String JavaDoc beanName, ConstructorArgumentValues cargs)
545             throws BeanDefinitionStoreException {
546
547         Object JavaDoc val = parsePropertyValue(ele, beanName, null);
548         String JavaDoc indexAttr = ele.getAttribute(INDEX_ATTRIBUTE);
549         String JavaDoc 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 JavaDoc 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     /**
579      * Parse a property element.
580      */

581     protected void parsePropertyElement(Element JavaDoc ele, String JavaDoc beanName, MutablePropertyValues pvs)
582             throws BeanDefinitionStoreException {
583
584         String JavaDoc 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 JavaDoc val = parsePropertyValue(ele, beanName, propertyName);
594         pvs.addPropertyValue(propertyName, val);
595     }
596
597
598     /**
599      * Get the value of a property element. May be a list etc.
600      * Also used for constructor arguments, "propertyName" being null in this case.
601      */

602     protected Object JavaDoc parsePropertyValue(Element JavaDoc ele, String JavaDoc beanName, String JavaDoc propertyName)
603             throws BeanDefinitionStoreException {
604
605         String JavaDoc elementName = (propertyName != null) ?
606                 "<property> element for property '" + propertyName + "'" :
607                 "<constructor-arg> element";
608
609         // Should only have one child element: ref, value, list, etc.
610
NodeList JavaDoc nl = ele.getChildNodes();
611         Element JavaDoc subElement = null;
612         for (int i = 0; i < nl.getLength(); i++) {
613             if (nl.item(i) instanceof Element JavaDoc) {
614                 Element JavaDoc candidateEle = (Element JavaDoc) nl.item(i);
615                 if (DESCRIPTION_ELEMENT.equals(candidateEle.getTagName())) {
616                     // Keep going: we don't use this value for now.
617
}
618                 else {
619                     // Child element is what we're looking for.
620
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             // Neither child element nor "ref" or "value" attribute found.
646
throw new BeanDefinitionStoreException(
647                     getResource(), beanName, elementName + " must specify a ref or value");
648         }
649
650         return parsePropertySubElement(subElement, beanName);
651     }
652
653     /**
654      * Parse a value, ref or collection sub-element of a property or
655      * constructor-arg element.
656      * @param ele subelement of property element; we don't know which yet
657      */

658     protected Object JavaDoc parsePropertySubElement(Element JavaDoc ele, String JavaDoc beanName) throws BeanDefinitionStoreException {
659         if (ele.getTagName().equals(BEAN_ELEMENT)) {
660             return parseBeanDefinitionElement(ele);
661         }
662         else if (ele.getTagName().equals(REF_ELEMENT)) {
663             // A generic reference to any name of any bean.
664
String JavaDoc beanRef = ele.getAttribute(BEAN_REF_ATTRIBUTE);
665             if (!StringUtils.hasLength(beanRef)) {
666                 // A reference to the id of another bean in the same XML file.
667
beanRef = ele.getAttribute(LOCAL_REF_ATTRIBUTE);
668                 if (!StringUtils.hasLength(beanRef)) {
669                     // A reference to the id of another bean in a parent context.
670
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             // A generic reference to any name of any bean.
682
String JavaDoc beanRef = ele.getAttribute(BEAN_REF_ATTRIBUTE);
683             if (!StringUtils.hasLength(beanRef)) {
684                 // A reference to the id of another bean in the same XML file.
685
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             // It's a literal value.
695
String JavaDoc value = DomUtils.getTextValue(ele);
696             if (ele.hasAttribute(TYPE_ATTRIBUTE)) {
697                 String JavaDoc typeClassName = ele.getAttribute(TYPE_ATTRIBUTE);
698                 try {
699                     Class JavaDoc typeClass = ClassUtils.forName(typeClassName, this.beanDefinitionReader.getBeanClassLoader());
700                     return new TypedStringValue(value, typeClass);
701                 }
702                 catch (ClassNotFoundException JavaDoc 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             // It's a distinguished null value.
711
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     /**
730      * Parse a list element.
731      */

732     protected List JavaDoc parseListElement(Element JavaDoc collectionEle, String JavaDoc beanName) throws BeanDefinitionStoreException {
733         NodeList JavaDoc 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 JavaDoc) {
737                 Element JavaDoc ele = (Element JavaDoc) nl.item(i);
738                 list.add(parsePropertySubElement(ele, beanName));
739             }
740         }
741         return list;
742     }
743
744     /**
745      * Parse a set element.
746      */

747     protected Set JavaDoc parseSetElement(Element JavaDoc collectionEle, String JavaDoc beanName) throws BeanDefinitionStoreException {
748         NodeList JavaDoc 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 JavaDoc) {
752                 Element JavaDoc ele = (Element JavaDoc) nl.item(i);
753                 set.add(parsePropertySubElement(ele, beanName));
754             }
755         }
756         return set;
757     }
758
759     /**
760      * Parse a map element.
761      */

762     protected Map JavaDoc parseMapElement(Element JavaDoc mapEle, String JavaDoc beanName) throws BeanDefinitionStoreException {
763         List JavaDoc entryEles = DomUtils.getChildElementsByTagName(mapEle, ENTRY_ELEMENT);
764         Map JavaDoc map = new ManagedMap(entryEles.size());
765
766         for (Iterator JavaDoc it = entryEles.iterator(); it.hasNext();) {
767             Element JavaDoc entryEle = (Element JavaDoc) it.next();
768             // Should only have one value child element: ref, value, list, etc.
769
// Optionally, there might be a key child element.
770
NodeList JavaDoc entrySubNodes = entryEle.getChildNodes();
771
772             Element JavaDoc keyEle = null;
773             Element JavaDoc valueEle = null;
774             for (int j = 0; j < entrySubNodes.getLength(); j++) {
775                 if (entrySubNodes.item(j) instanceof Element JavaDoc) {
776                     Element JavaDoc candidateEle = (Element JavaDoc) 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                         // Child element is what we're looking for.
786
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             // Extract key from attribute or sub-element.
796
Object JavaDoc 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             // Extract value from attribute or sub-element.
820
Object JavaDoc 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             // Add final key and value to the Map.
844
map.put(key, value);
845         }
846
847         return map;
848     }
849
850     /**
851      * Parse a key sub-element of a map element.
852      */

853     protected Object JavaDoc parseKeyElement(Element JavaDoc keyEle, String JavaDoc beanName) throws BeanDefinitionStoreException {
854         NodeList JavaDoc nl = keyEle.getChildNodes();
855         Element JavaDoc subElement = null;
856         for (int i = 0; i < nl.getLength(); i++) {
857             if (nl.item(i) instanceof Element JavaDoc) {
858                 Element JavaDoc candidateEle = (Element JavaDoc) nl.item(i);
859                 // Child element is what we're looking for.
860
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     /**
871      * Parse a props element.
872      */

873     protected Properties JavaDoc parsePropsElement(Element JavaDoc propsEle, String JavaDoc beanName) throws BeanDefinitionStoreException {
874         Properties JavaDoc props = new Properties JavaDoc();
875         List JavaDoc propEles = DomUtils.getChildElementsByTagName(propsEle, PROP_ELEMENT);
876         for (Iterator JavaDoc it = propEles.iterator(); it.hasNext();) {
877             Element JavaDoc propEle = (Element JavaDoc) it.next();
878             String JavaDoc key = propEle.getAttribute(KEY_ATTRIBUTE);
879             // Trim the text value to avoid unwanted whitespace
880
// caused by typical XML formatting.
881
String JavaDoc value = DomUtils.getTextValue(propEle).trim();
882             props.setProperty(key, value);
883         }
884         return props;
885     }
886
887 }
888
Popular Tags