View Javadoc

1   /*
2    * Copyright 2001-2004 The Apache Software Foundation.
3    * 
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * 
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    * 
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */ 
16  package org.apache.commons.betwixt.digester;
17  
18  import java.beans.BeanInfo;
19  import java.beans.Introspector;
20  import java.beans.PropertyDescriptor;
21  
22  import org.apache.commons.logging.Log;
23  import org.apache.commons.logging.LogFactory;
24  
25  /*** <p>Factors out common code used by Betwixt rules that access bean properties.
26    * Maybe a lot of this should be moved into <code>BeanUtils</code>.</p>
27    *
28    * @author Robert Burrell Donkin
29    * @since 0.5
30    */
31  public abstract class MappedPropertyRule extends RuleSupport {
32  
33      /*** Logger */
34      private static final Log log = LogFactory.getLog( MappedPropertyRule.class );   
35       /*** Classloader used to load classes by name */
36      private ClassLoader classLoader;
37      /*** Base constructor */
38      public MappedPropertyRule() {
39          this.classLoader = getClass().getClassLoader();
40      }
41      
42      
43  
44      // Implementation methods
45      //-------------------------------------------------------------------------    
46  
47      /*** 
48       * Returns the property descriptor for the class and property name.
49       * Note that some caching could be used to improve performance of 
50       * this method. Or this method could be added to PropertyUtils.
51       *
52       * @param beanClass descriptor for property in this class
53       * @param propertyName descriptor for property with this name
54       * @return property descriptor for the named property in the given class 
55       */
56      protected PropertyDescriptor getPropertyDescriptor( Class beanClass, 
57                                                          String propertyName ) {
58          if ( beanClass != null && propertyName != null ) {
59              if (log.isTraceEnabled()) {
60                  log.trace("Searching for property " + propertyName + " on " + beanClass);
61              }
62              try {
63                  // TODO: replace this call to introspector to an object call
64                  // which finds all property descriptors for a class
65                  // this allows extra property descriptors to be added 
66                  BeanInfo beanInfo = Introspector.getBeanInfo( beanClass );
67                  PropertyDescriptor[] descriptors = 
68                      beanInfo.getPropertyDescriptors();
69                  if ( descriptors != null ) {
70                      for ( int i = 0, size = descriptors.length; i < size; i++ ) {
71                          PropertyDescriptor descriptor = descriptors[i];
72                          if ( propertyName.equals( descriptor.getName() ) ) {
73                              log.trace("Found matching method.");
74                              return descriptor;
75                          }
76                      }
77                  }
78                  // for interfaces, check all super interfaces
79                  if (beanClass.isInterface()) {
80                      Class[] superinterfaces = beanClass.getInterfaces();
81                      for (int i=0, size=superinterfaces.length; i<size; i++) {
82                          PropertyDescriptor descriptor = getPropertyDescriptor(superinterfaces[i], propertyName);
83                          if (descriptor != null)
84                          {
85                              return descriptor;
86                          }
87                      }
88                  }
89                  
90                  log.trace("No match found.");
91                  return null;
92              } catch (Exception e) {
93                  log.warn( "Caught introspection exception", e );
94              }
95          }
96          return null;
97      }
98      
99      
100     /***
101      * Gets the type of a property
102      *
103      * @param propertyClassName class name for property type (may be null)
104      * @param beanClass class that has property 
105      * @param propertyName the name of the property whose type is to be determined
106      * @return property type 
107      */
108     protected Class getPropertyType( String propertyClassName, 
109                                      Class beanClass, String propertyName ) {
110         // XXX: should use a ClassLoader to handle 
111         //      complex class loading situations
112         if ( propertyClassName != null ) {
113             try {
114                 Class answer = classLoader.loadClass(propertyClassName);
115                 if (answer != null) {
116                     if (log.isTraceEnabled()) {
117                         log.trace("Used specified type " + answer);
118                     }
119                     return answer;
120                 }
121             } catch (Exception e) {
122                 log.warn("Cannot load specified type", e);
123             }
124         }
125         
126         PropertyDescriptor descriptor = 
127             getPropertyDescriptor( beanClass, propertyName );        
128         if ( descriptor != null ) { 
129             return descriptor.getPropertyType();
130         }
131         
132         if (log.isTraceEnabled()) {
133             log.trace("Cannot find property type.");
134             log.trace("  className=" + propertyClassName 
135                         + " base=" + beanClass + " name=" + propertyName);
136         }
137         return null;            
138     }
139 }