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    }