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 }