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.io.read;
17  
18  import org.apache.commons.betwixt.ElementDescriptor;
19  import org.apache.commons.betwixt.registry.PolymorphicReferenceResolver;
20  import org.apache.commons.logging.Log;
21  
22  /***  
23    * Group of factory methods for <code>ChainedBeanCreator</code>'s.
24    * The standard implementations used by Betwixt are present here.
25    *
26    * @author Robert Burrell Donkin
27    * @since 0.5
28    */
29  public class ChainedBeanCreatorFactory {
30      
31      /*** Singleton instance for creating derived beans */
32      private static final ChainedBeanCreator derivedBeanCreator 
33          = new ChainedBeanCreator() {
34              public Object create(
35                                  ElementMapping elementMapping, 
36                                  ReadContext context, 
37                                  BeanCreationChain chain) {
38                                  
39                  String className 
40                      = elementMapping
41                          .getAttributes().getValue( context.getClassNameAttribute() );
42                  if ( className != null ) {
43                      try {
44                          // load the class we should instantiate
45                          ClassLoader classLoader = context.getClassLoader();
46                          if ( classLoader == null ) {
47                              context.getLog().warn( 
48              "Could not create derived instance: read context classloader not set." );
49                          }
50                          Class clazz = classLoader.loadClass( className );
51                          return clazz.newInstance();
52                                          
53                      } catch (Exception e) {
54                          // it would be nice to have a pluggable strategy for exception management
55                          context.getLog().warn( "Could not create instance of type: " + className );
56                          context.getLog().debug( "Create new instance failed: ", e );
57                          return null;
58                      }
59                      
60                  } else {
61                      // pass responsibility down the chain
62                      return chain.create( elementMapping, context );
63                  }
64              }
65          };
66      
67      /***
68        * Creates a <code>ChainedBeanCreator</code> that constructs derived beans.
69        * These have their classname set by an xml attribute.
70        * @return <code>ChainedBeanCreator</code> that implements Derived beans logic, not null
71        */
72      public static final ChainedBeanCreator createDerivedBeanCreator() {
73          return derivedBeanCreator;
74      }
75      
76      /*** Singleton instance that creates beans based on type */
77      private static final ChainedBeanCreator elementTypeBeanCreator 
78          = new ChainedBeanCreator() {
79              public Object create(
80                                  ElementMapping element, 
81                                  ReadContext context, 
82                                  BeanCreationChain chain) {
83                  
84                  Log log = context.getLog();
85                  Class theClass = null;
86                  
87                  ElementDescriptor descriptor = element.getDescriptor();
88                  if ( descriptor != null ) {
89                      // check for polymorphism 
90                      if (descriptor.isPolymorphic()) {
91                          theClass = context.getXMLIntrospector().getPolymorphicReferenceResolver()
92                              .resolveType(element, context);
93                      }
94                      
95                      if (theClass == null)
96                      {
97                          // created based on implementation class
98                          theClass = descriptor.getImplementationClass();
99                      }
100                 }
101                 
102                 if ( theClass == null ) {
103                     // create based on type
104                     theClass = element.getType();
105                 }
106                 
107                 if ( log.isTraceEnabled() ) {
108                     log.trace(
109                         "Creating instance of class " + theClass.getName() 
110                         + " for element " + element.getName());
111                 }
112                 
113                 try {
114 
115                     return theClass.newInstance();
116                     
117                 } catch (Exception e) {
118                     // it would be nice to have a pluggable strategy for exception management
119                     context.getLog().warn( 
120                         "Could not create instance of type: " + theClass.getName() );
121                     context.getLog().debug( "Create new instance failed: ", e );
122                     return null;
123                 }
124             }
125         }; 
126     
127     /***
128       * Creates a <code>ChainedBeanCreator</code> that constructs beans based on element type.
129       * @return <code>ChainedBeanCreator</code> that implements load by type beans logic, not null
130       */
131     public static final ChainedBeanCreator createElementTypeBeanCreator() {
132         return elementTypeBeanCreator;
133     }
134     
135     /*** Singleton instance that creates beans based on IDREF */
136     private static final ChainedBeanCreator idRefBeanCreator 
137         = new ChainedBeanCreator() {
138             public Object create(
139                                 ElementMapping elementMapping, 
140                                 ReadContext context, 
141                                 BeanCreationChain chain) {
142                 if ( context.getMapIDs() ) {
143                     String idref = elementMapping.getAttributes().getValue( "idref" );
144                     if ( idref != null ) {
145                         // XXX need to check up about ordering
146                         // XXX this is a very simple system that assumes that 
147                         // XXX id occurs before idrefs
148                         // XXX would need some thought about how to implement a fuller system
149                         context.getLog().trace( "Found IDREF" );
150                         Object bean = context.getBean( idref );
151                         if ( bean != null ) {
152                             if ( context.getLog().isTraceEnabled() ) {
153                                 context.getLog().trace( "Matched bean " + bean );
154                             }
155                             return bean;
156                         }
157                         context.getLog().trace( "No match found" );
158                     }
159                 }
160                 return chain.create( elementMapping, context );
161             }
162         }; 
163     
164     /***
165       * Creates a <code>ChainedBeanCreator</code> that finds existing beans based on their IDREF.
166       * @return <code>ChainedBeanCreator</code> that implements IDREF beans logic, not null
167       */
168     public static final ChainedBeanCreator createIDREFBeanCreator() {
169         return idRefBeanCreator;
170     }
171 }