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 */ 017package org.apache.xbean.spring.context.v2; 018 019import java.io.IOException; 020import java.lang.reflect.InvocationTargetException; 021import java.lang.reflect.Method; 022 023import org.springframework.beans.factory.BeanDefinitionStoreException; 024import org.springframework.beans.factory.config.BeanDefinitionHolder; 025import org.springframework.beans.factory.parsing.BeanComponentDefinition; 026import org.springframework.beans.factory.support.BeanDefinitionReaderUtils; 027import org.springframework.beans.factory.xml.BeanDefinitionParserDelegate; 028import org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader; 029import org.springframework.beans.factory.xml.XmlReaderContext; 030import org.springframework.core.io.Resource; 031import org.springframework.core.io.support.ResourcePatternUtils; 032import org.springframework.util.StringUtils; 033import org.springframework.util.SystemPropertyUtils; 034import org.springframework.util.xml.DomUtils; 035import org.w3c.dom.Element; 036import org.w3c.dom.Node; 037import org.w3c.dom.NodeList; 038 039public 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}