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 }