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.commons.betwixt.digester;
018:
019: import java.beans.BeanInfo;
020: import java.beans.Introspector;
021: import java.beans.PropertyDescriptor;
022:
023: import org.apache.commons.logging.Log;
024: import org.apache.commons.logging.LogFactory;
025:
026: /** <p>Factors out common code used by Betwixt rules that access bean properties.
027: * Maybe a lot of this should be moved into <code>BeanUtils</code>.</p>
028: *
029: * @author Robert Burrell Donkin
030: * @since 0.5
031: */
032: public abstract class MappedPropertyRule extends RuleSupport {
033:
034: /** Logger */
035: private static final Log log = LogFactory
036: .getLog(MappedPropertyRule.class);
037: /** Classloader used to load classes by name */
038: private ClassLoader classLoader;
039:
040: /** Base constructor */
041: public MappedPropertyRule() {
042: this .classLoader = getClass().getClassLoader();
043: }
044:
045: // Implementation methods
046: //-------------------------------------------------------------------------
047:
048: /**
049: * Returns the property descriptor for the class and property name.
050: * Note that some caching could be used to improve performance of
051: * this method. Or this method could be added to PropertyUtils.
052: *
053: * @param beanClass descriptor for property in this class
054: * @param propertyName descriptor for property with this name
055: * @return property descriptor for the named property in the given class
056: */
057: protected PropertyDescriptor getPropertyDescriptor(Class beanClass,
058: String propertyName) {
059: if (beanClass != null && propertyName != null) {
060: if (log.isTraceEnabled()) {
061: log.trace("Searching for property " + propertyName
062: + " on " + beanClass);
063: }
064: try {
065: // TODO: replace this call to introspector to an object call
066: // which finds all property descriptors for a class
067: // this allows extra property descriptors to be added
068: BeanInfo beanInfo;
069: if (getXMLIntrospector().getConfiguration()
070: .ignoreAllBeanInfo()) {
071: beanInfo = Introspector.getBeanInfo(beanClass,
072: Introspector.IGNORE_ALL_BEANINFO);
073: } else {
074: beanInfo = Introspector.getBeanInfo(beanClass);
075: }
076: PropertyDescriptor[] descriptors = beanInfo
077: .getPropertyDescriptors();
078: if (descriptors != null) {
079: for (int i = 0, size = descriptors.length; i < size; i++) {
080: PropertyDescriptor descriptor = descriptors[i];
081: if (propertyName.equals(descriptor.getName())) {
082: log.trace("Found matching method.");
083: return descriptor;
084: }
085: }
086: }
087: // for interfaces, check all super interfaces
088: if (beanClass.isInterface()) {
089: Class[] super interfaces = beanClass.getInterfaces();
090: for (int i = 0, size = super interfaces.length; i < size; i++) {
091: PropertyDescriptor descriptor = getPropertyDescriptor(
092: super interfaces[i], propertyName);
093: if (descriptor != null) {
094: return descriptor;
095: }
096: }
097: }
098:
099: log.trace("No match found.");
100: return null;
101: } catch (Exception e) {
102: log.warn("Caught introspection exception", e);
103: }
104: }
105: return null;
106: }
107:
108: /**
109: * Gets the type of a property
110: *
111: * @param propertyClassName class name for property type (may be null)
112: * @param beanClass class that has property
113: * @param propertyName the name of the property whose type is to be determined
114: * @return property type
115: */
116: protected Class getPropertyType(String propertyClassName,
117: Class beanClass, String propertyName) {
118: // XXX: should use a ClassLoader to handle
119: // complex class loading situations
120: if (propertyClassName != null) {
121: try {
122: Class answer = classLoader.loadClass(propertyClassName);
123: if (answer != null) {
124: if (log.isTraceEnabled()) {
125: log.trace("Used specified type " + answer);
126: }
127: return answer;
128: }
129: } catch (Exception e) {
130: log.warn("Cannot load specified type", e);
131: }
132: }
133:
134: PropertyDescriptor descriptor = getPropertyDescriptor(
135: beanClass, propertyName);
136: if (descriptor != null) {
137: return descriptor.getPropertyType();
138: }
139:
140: if (log.isTraceEnabled()) {
141: log.trace("Cannot find property type.");
142: log.trace(" className=" + propertyClassName + " base="
143: + beanClass + " name=" + propertyName);
144: }
145: return null;
146: }
147: }
|