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.impl;
018    
019    import org.apache.commons.logging.Log;
020    import org.apache.commons.logging.LogFactory;
021    import org.springframework.beans.MutablePropertyValues;
022    import org.springframework.beans.PropertyValue;
023    import org.springframework.beans.factory.config.TypedStringValue;
024    import org.springframework.beans.factory.support.AbstractBeanDefinition;
025    import org.springframework.beans.factory.support.ManagedList;
026    import org.w3c.dom.Element;
027    import org.w3c.dom.Node;
028    
029    import javax.xml.namespace.QName;
030    
031    import java.beans.PropertyDescriptor;
032    import java.lang.reflect.Method;
033    import java.util.Iterator;
034    import java.util.List;
035    
036    /**
037     * 
038     * @version $Revision: 1.1 $
039     */
040    public class QNameHelper {
041        private static final Log log = LogFactory.getLog(QNameHelper.class);
042    
043        public static QName createQName(Element element, String qualifiedName) {
044            int index = qualifiedName.indexOf(':');
045            if (index >= 0) {
046                String prefix = qualifiedName.substring(0, index);
047                String localName = qualifiedName.substring(index + 1);
048                String uri = recursiveGetAttributeValue(element, "xmlns:" + prefix);
049                return new QName(uri, localName, prefix);
050            }
051            else {
052                String uri = recursiveGetAttributeValue(element, "xmlns");
053                if (uri != null) {
054                    return new QName(uri, qualifiedName);
055                }
056                return new QName(qualifiedName);
057            }
058        }
059    
060        /**
061         * Recursive method to find a given attribute value
062         */
063        public static String recursiveGetAttributeValue(Element element, String attributeName) {
064            String answer = null;
065            try {
066                answer = element.getAttribute(attributeName);
067            }
068            catch (Exception e) {
069                if (log.isTraceEnabled()) {
070                    log.trace("Caught exception looking up attribute: " + attributeName + " on element: " + element + ". Cause: " + e, e);
071                }
072            }
073            if (answer == null || answer.length() == 0) {
074                Node parentNode = element.getParentNode();
075                if (parentNode instanceof Element) {
076                    return recursiveGetAttributeValue((Element) parentNode, attributeName);
077                }
078            }
079            return answer;
080        }
081    
082        public static void coerceQNamePropertyValues(QNameReflectionParams params) {
083            coerceNamespaceAwarePropertyValues(params.getBeanDefinition(), params.getElement(), params.getDescriptors(), params.getIndex());
084        }
085        
086        public static void coerceNamespaceAwarePropertyValues(AbstractBeanDefinition bd, Element element, PropertyDescriptor[] descriptors, int i) {
087            PropertyDescriptor descriptor = descriptors[i];
088            // When the property is an indexed property, the getPropertyType can return null.
089            if (descriptor.getPropertyType() == null) {
090                return;
091            }
092            if (descriptor.getPropertyType().isAssignableFrom(QName.class)) {
093                String name = descriptor.getName();
094                MutablePropertyValues propertyValues = bd.getPropertyValues();
095                PropertyValue propertyValue = propertyValues.getPropertyValue(name);
096                if (propertyValue != null) {
097                    Object value = propertyValue.getValue();
098                    if (value instanceof String) {
099                        propertyValues.removePropertyValue(propertyValue);
100                        addPropertyValue(propertyValues, name, createQName(element, (String) value));
101                    } else if (value instanceof TypedStringValue) {
102                        propertyValues.removePropertyValue(propertyValue);
103                        addPropertyValue(propertyValues, name, createQName(element, ((TypedStringValue) value).getValue()));
104                    }
105                }
106            } else if (descriptor.getPropertyType().isAssignableFrom(QName[].class)) {
107                String name = descriptor.getName();
108                MutablePropertyValues propertyValues = bd.getPropertyValues();
109                PropertyValue propertyValue = propertyValues.getPropertyValue(name);
110                if (propertyValue != null) {
111                    Object value = propertyValue.getValue();
112                    if (value instanceof List) {
113                        List values = (List) value;
114                        List newValues = new ManagedList();
115                        for (Iterator iter = values.iterator(); iter.hasNext();) {
116                            Object v = iter.next();
117                            if (v instanceof String) {
118                                newValues.add(createQName(element, (String) v));
119                            } else {
120                                newValues.add(v);
121                            }
122                        }
123                        propertyValues.removePropertyValue(propertyValue);
124                        propertyValues.addPropertyValue(name, newValues);
125                    }
126                }
127            }
128        }
129    
130        // Fix Spring 1.2.6 to 1.2.7 binary incompatibility.
131        // The addPropertyValueMethod has changed to return a
132        // value instead of void.
133        // So use reflectiom to handle both cases.
134        private static final Method addPropertyValueMethod;
135        static {
136            try {
137                addPropertyValueMethod = MutablePropertyValues.class.getMethod(
138                            "addPropertyValue",
139                            new Class[] { String.class, Object.class });
140            } catch (Exception e) {
141                throw new RuntimeException("Unable to find MutablePropertyValues:addPropertyValue", e);
142            }
143        }
144        public static void addPropertyValue(MutablePropertyValues values, String name, Object value) {
145            try {
146                addPropertyValueMethod.invoke(values, new Object[] { name, value });
147            } catch (Exception e) {
148                throw new RuntimeException("Error adding property definition", e);
149            }
150        }
151    
152    }