View Javadoc

1   /*
2    * $Id: MetaMethod.java,v 1.15 2005/06/30 16:12:05 blackdrag Exp $
3    *
4    * Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
5    *
6    * Redistribution and use of this software and associated documentation
7    * ("Software"), with or without modification, are permitted provided that the
8    * following conditions are met:
9    *  1. Redistributions of source code must retain copyright statements and
10   * notices. Redistributions must also contain a copy of this document.
11   *  2. Redistributions in binary form must reproduce the above copyright
12   * notice, this list of conditions and the following disclaimer in the
13   * documentation and/or other materials provided with the distribution.
14   *  3. The name "groovy" must not be used to endorse or promote products
15   * derived from this Software without prior written permission of The Codehaus.
16   * For written permission, please contact info@codehaus.org.
17   *  4. Products derived from this Software may not be called "groovy" nor may
18   * "groovy" appear in their names without prior written permission of The
19   * Codehaus. "groovy" is a registered trademark of The Codehaus.
20   *  5. Due credit should be given to The Codehaus - http://groovy.codehaus.org/
21   *
22   * THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS ``AS IS'' AND ANY
23   * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
24   * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25   * DISCLAIMED. IN NO EVENT SHALL THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR
26   * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27   * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
28   * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29   * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30   * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31   * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
32   * DAMAGE.
33   *
34   */
35  package groovy.lang;
36  
37  import java.lang.reflect.Method;
38  import java.lang.reflect.Modifier;
39  import java.security.AccessController;
40  import java.security.PrivilegedAction;
41  import java.util.logging.Logger;
42  
43  import org.codehaus.groovy.runtime.InvokerHelper;
44  import org.codehaus.groovy.runtime.Reflector;
45  
46  /***
47   * Represents a Method on a Java object a little like {@link java.lang.reflect.Method}
48   * except without using reflection to invoke the method
49   * 
50   * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
51   * @version $Revision: 1.15 $
52   */
53  public class MetaMethod implements Cloneable {
54  
55      private static final Logger log = Logger.getLogger(MetaMethod.class.getName());
56  
57      private String name;
58      private Class declaringClass;
59      private Class interfaceClass;
60      private Class[] parameterTypes;
61      private Class returnType;
62      private int modifiers;
63      private Reflector reflector;
64      private int methodIndex;
65      private Method method;
66  
67      public MetaMethod(String name, Class declaringClass, Class[] parameterTypes, Class returnType, int modifiers) {
68          this.name = name;
69          this.declaringClass = declaringClass;
70          this.parameterTypes = parameterTypes;
71          this.returnType = returnType;
72          this.modifiers = modifiers;
73      }
74  
75      public MetaMethod(Method method) {
76          this(
77              method.getName(),
78              method.getDeclaringClass(),
79              method.getParameterTypes(),
80              method.getReturnType(),
81              method.getModifiers());
82          this.method = method;
83      }
84  
85      public MetaMethod(MetaMethod metaMethod) {
86          this(metaMethod.method);
87      }
88  
89      /***
90       * Checks that the given parameters are valid to call this method
91       * 
92       * @param arguments
93       * @throws IllegalArgumentException if the parameters are not valid
94       */
95      public void checkParameters(Class[] arguments) {
96          // lets check that the argument types are valid
97          if (!MetaClass.isValidMethod(getParameterTypes(), arguments, false)) {
98              throw new IllegalArgumentException(
99                      "Parameters to method: "
100                     + getName()
101                     + " do not match types: "
102                     + InvokerHelper.toString(getParameterTypes())
103                     + " for arguments: "
104                     + InvokerHelper.toString(arguments));
105         }
106     }
107     
108     public Object invoke(Object object, Object[] arguments) throws Exception {
109         if (reflector != null) {
110             return reflector.invoke(this, object, arguments);
111         }
112         else {
113             AccessController.doPrivileged(new PrivilegedAction() {
114 	    			public Object run() {
115 	    			    method.setAccessible(true);
116 	    			    return null;
117 	    			}
118 	    		});
119             return method.invoke(object, arguments);
120         }
121     }
122 
123     public Class getDeclaringClass() {
124         return declaringClass;
125     }
126     
127     public void setDeclaringClass(Class c) {
128         declaringClass=c;
129     }
130 
131     public int getMethodIndex() {
132         return methodIndex;
133     }
134 
135     public void setMethodIndex(int methodIndex) {
136         this.methodIndex = methodIndex;
137     }
138 
139     public int getModifiers() {
140         return modifiers;
141     }
142 
143     public String getName() {
144         return name;
145     }
146 
147     public Class[] getParameterTypes() {
148         return parameterTypes;
149     }
150 
151     public Class getReturnType() {
152         return returnType;
153     }
154 
155     public Reflector getReflector() {
156         return reflector;
157     }
158 
159     public void setReflector(Reflector reflector) {
160         this.reflector = reflector;
161     }
162 
163     public boolean isMethod(Method method) {
164         return name.equals(method.getName())
165             && modifiers == method.getModifiers()
166             && returnType.equals(method.getReturnType())
167             && equal(parameterTypes, method.getParameterTypes());
168     }
169 
170     protected boolean equal(Class[] a, Class[] b) {
171         if (a.length == b.length) {
172             for (int i = 0, size = a.length; i < size; i++) {
173                 if (!a[i].equals(b[i])) {
174                     return false;
175                 }
176             }
177             return true;
178         }
179         return false;
180     }
181 
182     public String toString() {
183         return super.toString()
184             + "[name: "
185             + name
186             + " params: "
187             + InvokerHelper.toString(parameterTypes)
188             + " returns: "
189             + returnType
190             + " owner: "
191             + declaringClass
192             + "]";
193     }
194 
195     public Object clone() {
196         try {
197             return super.clone();
198         }
199         catch (CloneNotSupportedException e) {
200             throw new GroovyRuntimeException("This should never happen", e);
201         }
202     }
203 
204     public boolean isStatic() {
205         return (modifiers & Modifier.STATIC) != 0;
206     }
207 
208     public boolean isPrivate() {
209         return (modifiers & Modifier.PRIVATE) != 0;
210     }
211 
212     public boolean isProtected() {
213         return (modifiers & Modifier.PROTECTED) != 0;
214     }
215 
216     public boolean isPublic() {
217         return (modifiers & Modifier.PUBLIC) != 0;
218     }
219 
220     /***
221      * @return true if the given method has the same name, parameters, return type
222      * and modifiers but may be defined on another type
223      */
224     public boolean isSame(MetaMethod method) {
225         return name.equals(method.getName())
226             && compatibleModifiers(modifiers, method.getModifiers())
227             && returnType.equals(method.getReturnType())
228             && equal(parameterTypes, method.getParameterTypes());
229     }
230 
231     protected boolean compatibleModifiers(int modifiersA, int modifiersB) {
232         int mask = Modifier.PRIVATE | Modifier.PROTECTED | Modifier.PUBLIC | Modifier.STATIC;
233         return (modifiersA & mask) == (modifiersB & mask);
234     }
235 
236     public Class getInterfaceClass() {
237         return interfaceClass;
238     }
239 
240     public void setInterfaceClass(Class interfaceClass) {
241         this.interfaceClass = interfaceClass;
242     }
243 
244     public boolean isCacheable() {
245         return true;
246     }
247 
248 }