Coverage Report - org.apache.commons.betwixt.io.read.ChainedBeanCreatorFactory

Classes in this File Line Coverage Branch Coverage Complexity
ChainedBeanCreatorFactory
80% 
97% 
5.429

 1  526
 /*
 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.io.read;
 17  
 
 18  
 import java.beans.IntrospectionException;
 19  
 import java.lang.reflect.Constructor;
 20  
 
 21  
 import org.apache.commons.betwixt.ElementDescriptor;
 22  
 import org.apache.commons.betwixt.XMLBeanInfo;
 23  
 import org.apache.commons.logging.Log;
 24  
 
 25  
 /**  
 26  
   * Group of factory methods for <code>ChainedBeanCreator</code>'s.
 27  
   * The standard implementations used by Betwixt are present here.
 28  
   *
 29  
   * @author Robert Burrell Donkin
 30  
   * @since 0.5
 31  
   */
 32  406
 public class ChainedBeanCreatorFactory {
 33  120
     
 34  406
     private static final Class[] EMPTY_CLASS_ARRAY = {};
 35  526
     private static final Object[] EMPTY_OBJECT_ARRAY = {};
 36  120
     
 37  
     /** Singleton instance for creating derived beans */
 38  406
     private static final ChainedBeanCreator derivedBeanCreator 
 39  406
         = new ChainedBeanCreator() {
 40  120
             public Object create(
 41  
                                 ElementMapping elementMapping, 
 42  
                                 ReadContext context, 
 43  
                                 BeanCreationChain chain) {
 44  
                                 
 45  2756
                 Log log = context.getLog();
 46  3572
                 String className 
 47  3572
                     = elementMapping
 48  3572
                         .getAttributes().getValue( context.getClassNameAttribute() );
 49  3572
                 if ( className != null ) {
 50  816
                     try {
 51  
                         // load the class we should instantiate
 52  90
                         ClassLoader classLoader = context.getClassLoader();
 53  117
                         Class clazz = null;
 54  117
                         if ( classLoader == null ) {
 55  27
                             log.warn("Read context classloader not set." );
 56  0
                         } else {
 57  
                             try
 58  
                             {
 59  90
                                 clazz = classLoader.loadClass( className );
 60  27
                             } catch (ClassNotFoundException e) {
 61  0
                                 log.info("Class not found in context classloader:");
 62  0
                                 log.debug(clazz, e);
 63  0
                             }
 64  
                         }
 65  90
                         if (clazz == null) {
 66  27
                             clazz = Class.forName(className);
 67  0
                         }
 68  90
                         return newInstance(clazz, log);
 69  27
                                         
 70  0
                     } catch (Exception e) {
 71  0
                         // it would be nice to have a pluggable strategy for exception management
 72  0
                         log.warn( "Could not create instance of type: " + className );
 73  0
                         log.debug( "Create new instance failed: ", e );
 74  0
                         return null;
 75  0
                     }
 76  
                     
 77  
                 } else {
 78  
                     // pass responsibility down the chain
 79  2666
                     return chain.create( elementMapping, context );
 80  789
                 }
 81  
             }
 82  
         };
 83  
     
 84  
     /**
 85  
       * Creates a <code>ChainedBeanCreator</code> that constructs derived beans.
 86  
       * These have their classname set by an xml attribute.
 87  
       * @return <code>ChainedBeanCreator</code> that implements Derived beans logic, not null
 88  
       */
 89  
     public static final ChainedBeanCreator createDerivedBeanCreator() {
 90  886
         return derivedBeanCreator;
 91  264
     }
 92  
     
 93  
     /**
 94  
      * Constructs a new instance of the given class.
 95  
      * Access is forced.
 96  
      * @param theClass <code>Class</code>, not null
 97  
      * @param log <code>Log</code>, not null
 98  
      * @return <code>Object</code>, an instance of the given class
 99  
      * @throws Exception
 100  
      */
 101  2608
     private static final Object newInstance(Class theClass, Log log) throws Exception {
 102  3385
         Object result = null;
 103  777
         try {
 104  2608
             Constructor constructor = theClass.getConstructor(EMPTY_CLASS_ARRAY);
 105  3375
             if (!constructor.isAccessible()) {
 106  3372
                 constructor.setAccessible(true);
 107  774
             }
 108  2598
             result = constructor.newInstance(EMPTY_OBJECT_ARRAY);
 109  774
         } catch (SecurityException e) {
 110  0
             log.debug("Cannot force accessibility to constructor", e);
 111  0
         
 112  10
         } catch (NoSuchMethodException e) {
 113  13
             if (log.isDebugEnabled()) { 
 114  3
                 log.debug("Class " + theClass + " has no empty constructor.");
 115  0
             }
 116  
         }
 117  
         
 118  2608
         if (result == null) {
 119  787
             result = theClass.newInstance();
 120  3
         }
 121  2598
         return result; 
 122  774
     }
 123  
     
 124  
     /** Singleton instance that creates beans based on type */
 125  406
     private static final ChainedBeanCreator elementTypeBeanCreator 
 126  406
         = new ChainedBeanCreator() {
 127  120
             public Object create(
 128  
                                 ElementMapping element, 
 129  
                                 ReadContext context, 
 130  
                                 BeanCreationChain chain) {
 131  
                 
 132  2666
                 Log log = context.getLog();
 133  3455
                 Class theClass = null;
 134  789
                 
 135  2666
                 ElementDescriptor descriptor = element.getDescriptor();
 136  3455
                 if ( descriptor != null ) {
 137  789
                     // check for polymorphism 
 138  2666
                     theClass = context.resolvePolymorphicType(element);
 139  789
                     
 140  2666
                     if (theClass == null)
 141  789
                     {
 142  
                         // created based on implementation class
 143  2484
                         theClass = descriptor.getImplementationClass();
 144  738
                     }
 145  
                 }
 146  
                 
 147  2666
                 if ( theClass == null ) {
 148  789
                     // create based on type
 149  2484
                     theClass = element.getType();
 150  738
                 }
 151  
                 
 152  2666
                 if (descriptor != null && descriptor.isPolymorphic()) {
 153  789
                     // check that the type is suitably named
 154  
                     try {
 155  380
                         XMLBeanInfo xmlBeanInfo = context.getXMLIntrospector().introspect(theClass);
 156  485
                         String namespace = element.getNamespace();
 157  485
                         String name = element.getName();
 158  485
                         if (namespace == null) {
 159  105
                             if (!name.equals(xmlBeanInfo.getElementDescriptor().getQualifiedName())) {
 160  0
                                 context.getLog().debug("Polymorphic type does not match element");
 161  0
                                 return null;
 162  0
                             }
 163  380
                         } else if (!namespace.equals(xmlBeanInfo.getElementDescriptor().getURI())
 164  485
                                 || !name.equals(xmlBeanInfo.getElementDescriptor().getLocalName())) {
 165  253
                             context.getLog().debug("Polymorphic type does not match element");
 166  187
                             return null;
 167  39
                         }
 168  0
                     } catch (IntrospectionException e) {
 169  0
                         context.getLog().warn( 
 170  0
                             "Could not introspect type to test introspection: " + theClass.getName() );
 171  0
                         context.getLog().debug( "Introspection failed: ", e );
 172  0
                         return null;
 173  0
                     }
 174  
                     
 175  
                 }
 176  
                 
 177  2518
                 if ( log.isTraceEnabled() ) {
 178  750
                     log.trace(
 179  0
                         "Creating instance of class " + theClass.getName() 
 180  0
                         + " for element " + element.getName());
 181  0
                 }
 182  
                 
 183  
                 try {
 184  
 
 185  2518
                     Object result = newInstance(theClass, log);
 186  3258
                     return result;
 187  747
                     
 188  10
                 } catch (Exception e) {
 189  3
                     // it would be nice to have a pluggable strategy for exception management
 190  20
                     context.getLog().warn( 
 191  16
                         "Could not create instance of type: " + theClass.getName() );
 192  13
                     context.getLog().debug( "Create new instance failed: ", e );
 193  13
                     return null;
 194  3
                 }
 195  
             }
 196  
         }; 
 197  
     
 198  
     /**
 199  
       * Creates a <code>ChainedBeanCreator</code> that constructs beans based on element type.
 200  
       * @return <code>ChainedBeanCreator</code> that implements load by type beans logic, not null
 201  
       */
 202  
     public static final ChainedBeanCreator createElementTypeBeanCreator() {
 203  886
         return elementTypeBeanCreator;
 204  264
     }
 205  
     
 206  
     /** Singleton instance that creates beans based on IDREF */
 207  406
     private static final ChainedBeanCreator idRefBeanCreator 
 208  406
         = new ChainedBeanCreator() {
 209  120
             public Object create(
 210  
                                 ElementMapping elementMapping, 
 211  
                                 ReadContext context, 
 212  
                                 BeanCreationChain chain) {
 213  2826
                 if ( context.getMapIDs() ) {
 214  3187
                     String idref = elementMapping.getAttributes().getValue( "idref" );
 215  3055
                     if ( idref != null ) {
 216  705
                         // XXX need to check up about ordering
 217  
                         // XXX this is a very simple system that assumes that 
 218  
                         // XXX id occurs before idrefs
 219  
                         // XXX would need some thought about how to implement a fuller system
 220  30
                         context.getLog().trace( "Found IDREF" );
 221  39
                         Object bean = context.getBean( idref );
 222  39
                         if ( bean != null ) {
 223  39
                             if ( context.getLog().isTraceEnabled() ) {
 224  9
                                 context.getLog().trace( "Matched bean " + bean );
 225  0
                             }
 226  30
                             return bean;
 227  9
                         }
 228  0
                         context.getLog().trace( "No match found" );
 229  0
                     }
 230  
                 }
 231  2796
                 return chain.create( elementMapping, context );
 232  828
             }
 233  
         }; 
 234  
     
 235  
     /**
 236  
       * Creates a <code>ChainedBeanCreator</code> that finds existing beans based on their IDREF.
 237  
       * @return <code>ChainedBeanCreator</code> that implements IDREF beans logic, not null
 238  
       */
 239  
     public static final ChainedBeanCreator createIDREFBeanCreator() {
 240  886
         return idRefBeanCreator;
 241  264
     }
 242  
 }