001 /**
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017 package org.apache.xbean.spring.context.v2;
018
019 import java.io.IOException;
020 import java.lang.reflect.InvocationTargetException;
021 import java.lang.reflect.Method;
022
023 import org.springframework.beans.factory.BeanDefinitionStoreException;
024 import org.springframework.beans.factory.config.BeanDefinitionHolder;
025 import org.springframework.beans.factory.parsing.BeanComponentDefinition;
026 import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
027 import org.springframework.beans.factory.xml.BeanDefinitionParserDelegate;
028 import org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader;
029 import org.springframework.beans.factory.xml.XmlReaderContext;
030 import org.springframework.core.io.Resource;
031 import org.springframework.core.io.support.ResourcePatternUtils;
032 import org.springframework.util.StringUtils;
033 import org.springframework.util.SystemPropertyUtils;
034 import org.springframework.util.xml.DomUtils;
035 import org.w3c.dom.Element;
036 import org.w3c.dom.Node;
037 import org.w3c.dom.NodeList;
038
039 public class XBeanBeanDefinitionDocumentReader extends DefaultBeanDefinitionDocumentReader {
040
041 protected BeanDefinitionParserDelegate createHelper(XmlReaderContext readerContext, Element root) {
042 BeanDefinitionParserDelegate delegate = XBeanV2Helper.createParser(readerContext);
043 delegate.initDefaults(root);
044 return delegate;
045 }
046
047 protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
048 String namespaceUri = root.getNamespaceURI();
049 if (!DomUtils.nodeNameEquals(root, "beans") &&
050 !delegate.isDefaultNamespace(namespaceUri)) {
051 try {
052 try {
053 Method m = BeanDefinitionParserDelegate.class.getMethod("parseCustomElement", new Class[] { Element.class });
054 m.invoke(delegate, new Object[] { root });
055 } catch (NoSuchMethodException e) {
056 try {
057 Method m = BeanDefinitionParserDelegate.class.getMethod("parseCustomElement", new Class[] { Element.class, boolean.class });
058 m.invoke(delegate, new Object[] { root, Boolean.FALSE });
059 } catch (NoSuchMethodException e2) {
060 throw new IllegalStateException(e);
061 }
062 }
063 } catch (IllegalAccessException e) {
064 throw new RuntimeException(e);
065 } catch (IllegalArgumentException e) {
066 throw new RuntimeException(e);
067 } catch (InvocationTargetException e) {
068 if (e.getCause() instanceof RuntimeException) {
069 throw (RuntimeException) e.getCause();
070 }
071 throw new RuntimeException(e);
072 }
073 } else if (DomUtils.nodeNameEquals(root, "beans")) {
074 NodeList nl = root.getChildNodes();
075 for (int i = 0; i < nl.getLength(); i++) {
076 Node node = nl.item(i);
077 if (node instanceof Element) {
078 Element ele = (Element) node;
079 String childNamespaceUri = ele.getNamespaceURI();
080 if (delegate.isDefaultNamespace(childNamespaceUri)) {
081 parseDefaultElement(ele, delegate);
082 }
083 else {
084 delegate.parseCustomElement(ele);
085 }
086 }
087 }
088 } else {
089 super.parseBeanDefinitions(root, delegate);
090 }
091 }
092
093 private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
094 if (DomUtils.nodeNameEquals(ele, IMPORT_ELEMENT)) {
095 importBeanDefinitionResource(ele);
096 }
097 else if (DomUtils.nodeNameEquals(ele, ALIAS_ELEMENT)) {
098 processAliasRegistration(ele);
099 }
100 else if (DomUtils.nodeNameEquals(ele, BEAN_ELEMENT)) {
101 processBeanDefinition(ele, delegate);
102 }
103 }
104
105 /**
106 * Parse an "import" element and load the bean definitions
107 * from the given resource into the bean factory.
108 */
109 protected void importBeanDefinitionResource(Element ele) {
110 String location = ele.getAttribute(RESOURCE_ATTRIBUTE);
111 if (!StringUtils.hasText(location)) {
112 getReaderContext().error("Resource location must not be empty", ele);
113 return;
114 }
115
116 // Resolve system properties: e.g. "${user.dir}"
117 location = SystemPropertyUtils.resolvePlaceholders(location);
118
119 if (ResourcePatternUtils.isUrl(location)) {
120 int importCount = getReaderContext().getReader().loadBeanDefinitions(location);
121 if (logger.isDebugEnabled()) {
122 logger.debug("Imported " + importCount + " bean definitions from URL location [" + location + "]");
123 }
124 }
125 else {
126 // No URL -> considering resource location as relative to the current file.
127 try {
128 Resource relativeResource = getReaderContext().getResource().createRelative(location);
129 int importCount = getReaderContext().getReader().loadBeanDefinitions(relativeResource);
130 if (logger.isDebugEnabled()) {
131 logger.debug("Imported " + importCount + " bean definitions from relative location [" + location + "]");
132 }
133 }
134 catch (IOException ex) {
135 getReaderContext().error(
136 "Invalid relative resource location [" + location + "] to import bean definitions from", ele, null, ex);
137 }
138 }
139
140 getReaderContext().fireImportProcessed(location, extractSource(ele));
141 }
142
143 /**
144 * Process the given alias element, registering the alias with the registry.
145 */
146 protected void processAliasRegistration(Element ele) {
147 String name = ele.getAttribute(NAME_ATTRIBUTE);
148 String alias = ele.getAttribute(ALIAS_ATTRIBUTE);
149 boolean valid = true;
150 if (!StringUtils.hasText(name)) {
151 getReaderContext().error("Name must not be empty", ele);
152 valid = false;
153 }
154 if (!StringUtils.hasText(alias)) {
155 getReaderContext().error("Alias must not be empty", ele);
156 valid = false;
157 }
158 if (valid) {
159 try {
160 getReaderContext().getRegistry().registerAlias(name, alias);
161 }
162 catch (BeanDefinitionStoreException ex) {
163 getReaderContext().error(ex.getMessage(), ele);
164 }
165 getReaderContext().fireAliasRegistered(name, alias, extractSource(ele));
166 }
167 }
168
169 /**
170 * Process the given bean element, parsing the bean definition
171 * and registering it with the registry.
172 */
173 protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
174 BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
175 if (bdHolder != null) {
176 bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
177 // Register the final decorated instance.
178 BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
179 // Send registration event.
180 getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
181 }
182 }
183
184
185 }