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.v2c;
018
019import java.beans.BeanInfo;
020import java.beans.IntrospectionException;
021import java.beans.Introspector;
022import java.beans.PropertyDescriptor;
023
024import org.apache.xbean.spring.context.impl.PropertyEditorHelper;
025import org.apache.xbean.spring.context.impl.QNameReflectionHelper;
026import org.springframework.beans.factory.BeanDefinitionStoreException;
027import org.springframework.beans.factory.config.BeanDefinition;
028import org.springframework.beans.factory.support.AbstractBeanDefinition;
029import org.springframework.beans.factory.xml.XmlReaderContext;
030import org.w3c.dom.Element;
031
032public 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}