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.v2c;
018    
019    import java.beans.BeanInfo;
020    import java.beans.IntrospectionException;
021    import java.beans.Introspector;
022    import java.beans.PropertyDescriptor;
023    
024    import org.apache.xbean.spring.context.impl.PropertyEditorHelper;
025    import org.apache.xbean.spring.context.impl.QNameReflectionHelper;
026    import org.springframework.beans.factory.BeanDefinitionStoreException;
027    import org.springframework.beans.factory.config.BeanDefinition;
028    import org.springframework.beans.factory.support.AbstractBeanDefinition;
029    import org.springframework.beans.factory.xml.XmlReaderContext;
030    import org.w3c.dom.Element;
031    
032    public class XBeanQNameHelper {
033    
034        private XmlReaderContext readerContext;
035        
036        private boolean qnameIsOnClassPath;
037    
038        private boolean initQNameOnClassPath;
039        
040        public XBeanQNameHelper(XmlReaderContext readerContext) {
041            this.readerContext = readerContext;
042        }
043        
044        /**
045         * Any namespace aware property values (such as QNames) need to be coerced
046         * while we still have access to the XML Element from which its value comes -
047         * so lets do that now before we trash the DOM and just have the bean
048         * definition.
049         */
050        public void coerceNamespaceAwarePropertyValues(BeanDefinition definition, Element element) {
051            if (definition instanceof AbstractBeanDefinition && isQnameIsOnClassPath()) {
052                AbstractBeanDefinition bd = (AbstractBeanDefinition) definition;
053                // lets check for any QName types
054                BeanInfo beanInfo = getBeanInfo(bd.getBeanClassName());
055                if (beanInfo != null) {
056                    PropertyDescriptor[] descriptors = beanInfo.getPropertyDescriptors();
057                    for (int i = 0; i < descriptors.length; i++) {
058                        QNameReflectionHelper.coerceNamespaceAwarePropertyValues(bd, element, descriptors, i);
059                    }
060                }
061            }
062        }
063    
064        public BeanInfo getBeanInfo(String className) throws BeanDefinitionStoreException {
065            if (className == null) {
066                return null;
067            }
068    
069            BeanInfo info = null;
070            Class type = null;
071            try {
072                type = loadClass(className);
073            }
074            catch (ClassNotFoundException e) {
075                throw new BeanDefinitionStoreException("Failed to load type: " + className + ". Reason: " + e, e);
076            }
077            try {
078                info = Introspector.getBeanInfo(type);
079            }
080            catch (IntrospectionException e) {
081                throw new BeanDefinitionStoreException("Failed to introspect type: " + className + ". Reason: " + e, e);
082            }
083            return info;
084        }
085    
086        /**
087         * Attempts to load the class on the current thread context class loader or
088         * the class loader which loaded us
089         */
090        protected Class loadClass(String name) throws ClassNotFoundException {
091            ClassLoader beanClassLoader = readerContext.getReader().getBeanClassLoader();
092            if (beanClassLoader != null) {
093                try {
094                    return beanClassLoader.loadClass(name);
095                }
096                catch (ClassNotFoundException e) {
097                }
098            }
099            ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
100            if (contextClassLoader != null) {
101                try {
102                    return contextClassLoader.loadClass(name);
103                }
104                catch (ClassNotFoundException e) {
105                }
106            }
107            return getClass().getClassLoader().loadClass(name);
108        }
109    
110        protected boolean isQnameIsOnClassPath() {
111            if (initQNameOnClassPath == false) {
112                qnameIsOnClassPath = PropertyEditorHelper.loadClass("javax.xml.namespace.QName") != null;
113                initQNameOnClassPath = true;
114            }
115            return qnameIsOnClassPath;
116        }
117        
118    }