Source Code Cross Referenced for BeanDefinitionParserDelegate.java in  » J2EE » spring-framework-2.5 » org » springframework » beans » factory » xml » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » J2EE » spring framework 2.5 » org.springframework.beans.factory.xml 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


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