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.expression;
17  
18  import java.lang.reflect.Array;
19  import java.lang.reflect.Method;
20  import java.util.Collection;
21  
22  import org.apache.commons.logging.Log;
23  import org.apache.commons.logging.LogFactory;
24  
25  /*** <p><code>MethodUpdater</code> updates the current bean context 
26    * by calling a WriteMethod with the String value from the XML attribute 
27    * or element.</p>
28    *
29    * @author <a href="mailto:jstrachan@apache.org">James Strachan</a>
30    * @version $Revision: 1.13 $
31    */
32  public class MethodUpdater implements Updater {
33  
34      /*** Logger */
35      private static Log log = LogFactory.getLog( MethodUpdater.class );
36  
37      /*** 
38       * Programmatically set log 
39       * @param aLog the implementation to which this class should log
40       */
41      public static void setLog( Log aLog ) {
42          log = aLog;
43      }
44      
45      /*** The method to call on the bean */
46      private Method method;
47      /*** The type of the first parameter of the method */
48      private Class valueType;
49      
50      /*** Base constructor */
51      public MethodUpdater() {
52      }
53      
54      /*** 
55       * Convenience constructor sets method property 
56       * @param method the Method to be invoked on the context's bean in the update
57       */
58      public MethodUpdater(Method method) {
59          setMethod( method );
60      }
61  
62      /*** 
63       * Updates the current bean context with the given String value 
64       * @param context the Context to be updated
65       * @param newValue the update to this new value 
66       */
67      public void update(Context context, Object newValue) {
68          Object bean = context.getBean();
69          if ( bean != null ) {
70              if ( newValue instanceof String ) {
71                  // try to convert into primitive types
72                  if ( log.isTraceEnabled() ) {
73                      log.trace("Converting primitive to " + valueType);
74                  }
75                  newValue = context.getObjectStringConverter()
76                      .stringToObject( (String) newValue, valueType, null, context );
77              }
78              if ( newValue != null ) {
79                  // check that it is of the correct type
80  /*                
81                  if ( ! valueType.isAssignableFrom( newValue.getClass() ) ) {
82                      log.warn( 
83                          "Cannot call setter method: " + method.getName() + " on bean: " + bean
84                          + " with type: " + bean.getClass().getName() 
85                          + " as parameter should be of type: " + valueType.getName() 
86                          + " but is: " + newValue.getClass().getName() 
87                      );
88                      return;
89                  }
90  */                
91              }
92              // special case for collection objects into arrays                    
93              if (newValue instanceof Collection && valueType.isArray()) {
94                  Collection valuesAsCollection = (Collection) newValue;
95                  Class componentType = valueType.getComponentType();
96                  if (componentType != null) {
97                      Object[] valuesAsArray = 
98                          (Object[]) Array.newInstance(componentType, valuesAsCollection.size());
99                      newValue = valuesAsCollection.toArray(valuesAsArray);
100                 }
101             }
102             
103             Object[] arguments = { newValue };
104             try {
105                 if ( log.isDebugEnabled() ) {
106                     log.debug( 
107                         "Calling setter method: " + method.getName() + " on bean: " + bean 
108                         + " with new value: " + newValue 
109                     );
110                 }
111                 method.invoke( bean, arguments );
112                 
113             } catch (Exception e) {
114                 String valueTypeName = (newValue != null) ? newValue.getClass().getName() : "null";
115                 log.warn( 
116                     "Cannot evaluate method: " + method.getName() + " on bean: " + bean 
117                     + " of type: " + bean.getClass().getName() + " with value: " + newValue 
118                     + " of type: " + valueTypeName 
119                 );
120                 handleException(context, e);
121             }
122         }
123     }
124 
125     /*** 
126      * Gets the method which will be invoked by the update
127      *
128      * @return the Method to be invoked by the update
129      */
130     public Method getMethod() {
131         return method;
132     }
133     
134     /*** 
135      * Sets the constant value of this expression 
136      * @param method the Method to be invoked by the update
137      */
138     public void setMethod(Method method) {
139         this.method = method;
140         Class[] types = method.getParameterTypes();
141         if ( types == null || types.length <= 0 ) {
142             throw new IllegalArgumentException( "The Method must have at least one parameter" );
143         }
144         this.valueType = types[0];
145     }
146     
147     // Implementation methods
148     //-------------------------------------------------------------------------    
149     
150     /*** 
151      * Strategy method to allow derivations to handle exceptions differently.
152      * @param context the Context being updated when this exception occured
153      * @param e the Exception that occured during the update
154      */
155     protected void handleException(Context context, Exception e) {
156         log.info( "Caught exception: " + e, e );
157     }
158     
159     /***
160      * Returns something useful for logging.
161      * @return something useful for logging
162      */
163     public String toString() {
164         return "MethodUpdater [method=" + method + "]";
165     }
166 }