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.Method;
19  
20  /*** <p><code>MethodExpression</code> evaluates a method on the current bean context.</p>
21    *
22    * @author <a href="mailto:jstrachan@apache.org">James Strachan</a>
23    * @version $Revision: 1.8 $
24    */
25  public class MethodExpression implements Expression {
26  
27      /*** null arguments */
28      protected static Object[] NULL_ARGUMENTS;
29      /*** null classes */
30      protected static Class[] NULL_CLASSES;
31      
32      /*** The method to call on the bean */
33      private Method method;
34      
35      /*** Base constructor */
36      public MethodExpression() {
37      }
38      
39      /***  
40       * Convenience constructor sets method property 
41       * @param method the Method whose return value when invoked on the bean 
42       * will the value of this expression
43       */
44      public MethodExpression(Method method) {
45          this.method = method;
46      }
47  
48      /*** 
49       * Evaluate by calling the read method on the current bean 
50       *
51       * @param context the context against which this expression will be evaluated
52       * @return the value returned by the method when it's invoked on the context's bean,
53       * so long as the method can be invoked.
54       * Otherwise, null.
55       */
56      public Object evaluate(Context context) {
57          Object bean = context.getBean();
58          if ( bean != null ) {
59              Object[] arguments = getArguments();
60              try {
61                  return method.invoke( bean, arguments );
62                  
63              } catch (IllegalAccessException e) {
64                  // lets try use another method with the same name
65                  try {
66                      Class type = bean.getClass();
67                      Method alternate = findAlternateMethod( type, method );
68                      if ( alternate != null ) {
69                          return alternate.invoke( bean, arguments );
70                      }
71                  } catch (Exception e2) {
72                      handleException(context, e2);
73                  }
74              } catch (Exception e) {
75                  handleException(context, e);
76              }
77          }
78          return null;
79      }
80  
81      /*** 
82       * Do nothing.
83       * @see org.apache.commons.betwixt.expression.Expression
84       */
85      public void update(Context context, String newValue) {
86          // do nothing
87      }
88  
89      /*** 
90       * Gets the method used to evaluate this expression.
91       * @return the method whose value (when invoked against the context's bean) will be used 
92       * to evaluate this expression.
93       */
94      public Method getMethod() {
95          return method;
96      }
97      
98      /*** 
99       * Sets the method used to evaluate this expression 
100      * @param method method whose value (when invoked against the context's bean) will be used 
101      * to evaluate this expression 
102      */
103     public void setMethod(Method method) {
104         this.method = method;
105     }
106     
107     // Implementation methods
108     //-------------------------------------------------------------------------    
109     
110     /*** 
111      * Allows derived objects to create arguments for the method call 
112      * @return {@link #NULL_ARGUMENTS}
113      */
114     protected Object[] getArguments() {
115         return NULL_ARGUMENTS;
116     }
117     
118     /*** Tries to find an alternate method for the given type using interfaces
119       * which gets around the problem of inner classes, 
120       * such as on Map.Entry implementations.
121       *
122       * @param type the Class whose methods are to be searched
123       * @param method the Method for which an alternative is to be search for
124       * @return the alternative Method, if one can be found. Otherwise null.
125       */
126     protected Method findAlternateMethod( 
127                                             Class type, 
128                                             Method method ) {
129         // XXX
130         // Would it be better to use the standard reflection code in eg. lang
131         // since this code contains workarounds for common JVM bugs?
132         //
133         Class[] interfaces = type.getInterfaces();
134         if ( interfaces != null ) {
135             String name = method.getName();
136             for ( int i = 0, size = interfaces.length; i < size; i++ ) {
137                 Class otherType = interfaces[i];
138                 //
139                 // catch NoSuchMethodException so that all interfaces will be tried
140                 try {
141                     Method alternate = otherType.getMethod( name, NULL_CLASSES );
142                     if ( alternate != null && alternate != method ) {
143                         return alternate;
144                     }
145                 } catch (NoSuchMethodException e) {
146                     // swallow
147                 }
148             }
149         }
150         return null;
151     }
152     
153     /*** 
154       * <p>Log error to context's logger.</p> 
155       *
156       * <p>Allows derived objects to handle exceptions differently.</p>
157       *
158       * @param context the Context being evaluated when the exception occured
159       * @param e the exception to handle
160       */
161     protected void handleException(Context context, Exception e) {
162         // use the context's logger to log the problem
163         context.getLog().error("[MethodExpression] Cannot evaluate expression ", e);
164     }
165     
166     /*** 
167      * Returns something useful for logging.
168      * @return something useful for logging
169      */
170     public String toString() {
171         return "MethodExpression [method=" + method + "]";
172     }
173 }