Coverage Report - org.apache.commons.betwixt.digester.AttributeRule

Classes in this File Line Coverage Branch Coverage Complexity
AttributeRule
84% 
100% 
4.5

 1  
 package org.apache.commons.betwixt.digester;
 2  
 
 3  
 /*
 4  
  * Copyright 2001-2004 The Apache Software Foundation.
 5  
  * 
 6  
  * Licensed under the Apache License, Version 2.0 (the "License");
 7  
  * you may not use this file except in compliance with the License.
 8  
  * You may obtain a copy of the License at
 9  
  * 
 10  
  *      http://www.apache.org/licenses/LICENSE-2.0
 11  
  * 
 12  
  * Unless required by applicable law or agreed to in writing, software
 13  
  * distributed under the License is distributed on an "AS IS" BASIS,
 14  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 15  
  * See the License for the specific language governing permissions and
 16  
  * limitations under the License.
 17  
  */ 
 18  
 import java.beans.BeanInfo;
 19  
 import java.beans.Introspector;
 20  
 import java.beans.PropertyDescriptor;
 21  
 import java.lang.reflect.Method;
 22  
 
 23  
 import org.apache.commons.betwixt.AttributeDescriptor;
 24  
 import org.apache.commons.betwixt.ElementDescriptor;
 25  
 import org.apache.commons.betwixt.XMLUtils;
 26  
 import org.apache.commons.betwixt.expression.ConstantExpression;
 27  
 import org.apache.commons.betwixt.expression.MethodExpression;
 28  
 import org.apache.commons.betwixt.expression.MethodUpdater;
 29  
 import org.apache.commons.logging.Log;
 30  
 import org.apache.commons.logging.LogFactory;
 31  
 import org.xml.sax.Attributes;
 32  
 import org.xml.sax.SAXException;
 33  
 
 34  
 /** 
 35  
   * <p><code>AttributeRule</code> the digester Rule for parsing the 
 36  
   * &lt;attribute&gt; elements.</p>
 37  
   *
 38  
   * @author <a href="mailto:jstrachan@apache.org">James Strachan</a>
 39  
   * @version $Id: AttributeRule.java 370756 2006-01-20 08:44:05 +0000 (Fri, 20 Jan 2006) mvdb $
 40  
   */
 41  604
 public class AttributeRule extends RuleSupport {
 42  
 
 43  
     /** Logger */
 44  604
     private static final Log log = LogFactory.getLog( AttributeRule.class );
 45  
     /** This loads all classes created by name. Defaults to this class's classloader */
 46  
     private ClassLoader classLoader;
 47  
     /** The <code>Class</code> whose .betwixt file is being digested */
 48  
     private Class beanClass;
 49  
     
 50  
     /** Base constructor */
 51  1624
     public AttributeRule() {
 52  1624
         this.classLoader = getClass().getClassLoader();
 53  1624
     }
 54  
     
 55  
     // Rule interface
 56  
     //-------------------------------------------------------------------------    
 57  
     
 58  
     /**
 59  
      * Process the beginning of this element.
 60  
      *
 61  
      * @param attributes The attribute list of this element
 62  
      * @throws SAXException 1. If the attribute tag is not inside an element tag.
 63  
      * 2. If the name attribute is not valid XML attribute name.
 64  
      */
 65  
     public void begin(String name, String namespace, Attributes attributes) throws SAXException {
 66  
         
 67  2587
         AttributeDescriptor descriptor = new AttributeDescriptor();
 68  2587
         String nameAttributeValue = attributes.getValue( "name" );
 69  
 
 70  
         // check that name is well formed 
 71  2587
         if ( !XMLUtils.isWellFormedXMLName( nameAttributeValue ) ) {
 72  0
             throw new SAXException("'" + nameAttributeValue + "' would not be a well formed xml attribute name.");
 73  
         }
 74  
         
 75  2587
         String qName = nameAttributeValue;
 76  2587
         descriptor.setLocalName( nameAttributeValue );
 77  2587
         String uri = attributes.getValue( "uri" );
 78  2587
         if ( uri != null ) {
 79  117
             descriptor.setURI( uri );  
 80  117
             String prefix = getXMLIntrospector().getConfiguration().getPrefixMapper().getPrefix(uri);
 81  117
             qName = prefix + ":" + nameAttributeValue; 
 82  
         }
 83  2587
         descriptor.setQualifiedName( qName );
 84  
         
 85  2587
         String propertyName = attributes.getValue( "property" );
 86  2587
         descriptor.setPropertyName( propertyName );
 87  2587
         descriptor.setPropertyType( loadClass( attributes.getValue( "type" ) ) );
 88  
         
 89  2587
         if ( propertyName != null && propertyName.length() > 0 ) {
 90  2431
             configureDescriptor(descriptor);
 91  
         } else {
 92  156
             String value = attributes.getValue( "value" );
 93  156
             if ( value != null ) {
 94  156
                 descriptor.setTextExpression( new ConstantExpression( value ) );
 95  
             }
 96  
         }
 97  
 
 98  2587
         Object top = digester.peek();
 99  2587
         if ( top instanceof ElementDescriptor ) {
 100  2587
             ElementDescriptor parent = (ElementDescriptor) top;
 101  2587
             parent.addAttributeDescriptor( descriptor );
 102  
         } else {
 103  0
             throw new SAXException( "Invalid use of <attribute>. It should " 
 104  
                 + "be nested inside an <element> element" );
 105  
         }            
 106  
 
 107  2587
         digester.push(descriptor);        
 108  2587
     }
 109  
 
 110  
 
 111  
     /**
 112  
      * Process the end of this element.
 113  
      */
 114  
     public void end(String name, String namespace) {
 115  2587
         Object top = digester.pop();
 116  2587
     }
 117  
 
 118  
     
 119  
     // Implementation methods
 120  
     //-------------------------------------------------------------------------    
 121  
     /**
 122  
      * Loads a class (using the appropriate classloader)
 123  
      *
 124  
      * @param name the name of the class to load
 125  
      * @return the class instance loaded by the appropriate classloader
 126  
      */
 127  
     protected Class loadClass( String name ) {
 128  
         // XXX: should use a ClassLoader to handle complex class loading situations
 129  2587
         if ( name != null ) {
 130  
             try {
 131  0
                 return classLoader.loadClass(name);
 132  0
             } catch (Exception e) { // SWALLOW
 133  
             }
 134  
         }
 135  2587
         return null;            
 136  
     }
 137  
     
 138  
     /** 
 139  
      * Set the Expression and Updater from a bean property name 
 140  
      * @param attributeDescriptor configure this <code>AttributeDescriptor</code> 
 141  
      * from the property with a matching name in the bean class
 142  
      */
 143  
     protected void configureDescriptor(AttributeDescriptor attributeDescriptor) {
 144  2431
         Class beanClass = getBeanClass();
 145  2431
         if ( beanClass != null ) {
 146  2418
             String name = attributeDescriptor.getPropertyName();
 147  
             try {
 148  
                 BeanInfo beanInfo;
 149  2418
                 if( getXMLIntrospector().getConfiguration().ignoreAllBeanInfo() ) {
 150  0
                     beanInfo = Introspector.getBeanInfo( beanClass, Introspector.IGNORE_ALL_BEANINFO );
 151  
                 }
 152  
                 else {
 153  2418
                     beanInfo = Introspector.getBeanInfo( beanClass );
 154  
                 }
 155  2418
                 PropertyDescriptor[] descriptors = beanInfo.getPropertyDescriptors();
 156  2418
                 if ( descriptors != null ) {
 157  10582
                     for ( int i = 0, size = descriptors.length; i < size; i++ ) {
 158  10491
                         PropertyDescriptor descriptor = descriptors[i];
 159  10491
                         if ( name.equals( descriptor.getName() ) ) {
 160  2327
                             configureProperty( attributeDescriptor, descriptor );
 161  2327
                             getProcessedPropertyNameSet().add( name );
 162  2327
                             break;
 163  
                         }
 164  
                     }
 165  
                 }
 166  0
             } catch (Exception e) {
 167  0
                 log.warn( "Caught introspection exception", e );
 168  
             }
 169  
         }
 170  2431
     }    
 171  
     
 172  
     /**
 173  
      * Configure an <code>AttributeDescriptor</code> from a <code>PropertyDescriptor</code>
 174  
      *
 175  
      * @param attributeDescriptor configure this <code>AttributeDescriptor</code>
 176  
      * @param propertyDescriptor configure from this <code>PropertyDescriptor</code>
 177  
      */
 178  
     private void configureProperty( 
 179  
                                     AttributeDescriptor attributeDescriptor, 
 180  
                                     PropertyDescriptor propertyDescriptor ) {
 181  2327
         Class type = propertyDescriptor.getPropertyType();
 182  2327
         Method readMethod = propertyDescriptor.getReadMethod();
 183  2327
         Method writeMethod = propertyDescriptor.getWriteMethod();
 184  
         
 185  2327
         if ( readMethod == null ) {
 186  0
             log.trace( "No read method" );
 187  0
             return;
 188  
         }
 189  
         
 190  2327
         if ( log.isTraceEnabled() ) {
 191  0
             log.trace( "Read method=" + readMethod );
 192  
         }
 193  
         
 194  
         // choose response from property type
 195  2327
         if ( getXMLIntrospector().isLoopType( type ) ) {
 196  0
             log.warn( "Using loop type for an attribute. Type = " 
 197  0
                     + type.getName() + " attribute: " + attributeDescriptor.getQualifiedName() );
 198  
         }
 199  
 
 200  2327
         log.trace( "Standard property" );
 201  2327
         attributeDescriptor.setTextExpression( new MethodExpression( readMethod ) );
 202  
         
 203  2327
         if ( writeMethod != null ) {
 204  2314
             attributeDescriptor.setUpdater( new MethodUpdater( writeMethod ) );
 205  
         }
 206  
         
 207  2327
         attributeDescriptor.setPropertyName( propertyDescriptor.getName() );
 208  2327
         attributeDescriptor.setPropertyType( type );        
 209  
         
 210  
         // XXX: associate more bean information with the descriptor?
 211  
         //nodeDescriptor.setDisplayName( propertyDescriptor.getDisplayName() );
 212  
         //nodeDescriptor.setShortDescription( propertyDescriptor.getShortDescription() );
 213  2327
     }
 214  
     
 215  
 }