View Javadoc

1   /*
2    * $Id: MetaMethod.java,v 1.18 2005/10/17 08:36:21 tug 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.MetaClassHelper;
45  import org.codehaus.groovy.runtime.Reflector;
46  
47  /***
48   * Represents a Method on a Java object a little like {@link java.lang.reflect.Method}
49   * except without using reflection to invoke the method
50   * 
51   * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
52   * @version $Revision: 1.18 $
53   */
54  public class MetaMethod implements Cloneable {
55  
56      private static final Logger log = Logger.getLogger(MetaMethod.class.getName());
57  
58      private String name;
59      private Class declaringClass;
60      private Class interfaceClass;
61      private Class[] parameterTypes;
62      private Class returnType;
63      private int modifiers;
64      private Reflector reflector;
65      private int methodIndex;
66      private Method method;
67  
68      public MetaMethod(String name, Class declaringClass, Class[] parameterTypes, Class returnType, int modifiers) {
69          this.name = name;
70          this.declaringClass = declaringClass;
71          this.parameterTypes = parameterTypes;
72          this.returnType = returnType;
73          this.modifiers = modifiers;
74      }
75  
76      public MetaMethod(Method method) {
77          this(
78              method.getName(),
79              method.getDeclaringClass(),
80              method.getParameterTypes(),
81              method.getReturnType(),
82              method.getModifiers());
83          this.method = method;
84      }
85  
86      public MetaMethod(MetaMethod metaMethod) {
87          this(metaMethod.method);
88      }
89  
90      /***
91       * Checks that the given parameters are valid to call this method
92       * 
93       * @param arguments
94       * @throws IllegalArgumentException if the parameters are not valid
95       */
96      public void checkParameters(Class[] arguments) {
97          // lets check that the argument types are valid
98          if (!MetaClassHelper.isValidMethod(getParameterTypes(), arguments, false)) {
99              throw new IllegalArgumentException(
100                     "Parameters to method: "
101                     + getName()
102                     + " do not match types: "
103                     + InvokerHelper.toString(getParameterTypes())
104                     + " for arguments: "
105                     + InvokerHelper.toString(arguments));
106         }
107     }
108     
109     public Object invoke(Object object, Object[] arguments) throws Exception {
110         if (reflector != null) {
111             return reflector.invoke(this, object, arguments);
112         }
113         else {
114             AccessController.doPrivileged(new PrivilegedAction() {
115 	    			public Object run() {
116 	    			    method.setAccessible(true);
117 	    			    return null;
118 	    			}
119 	    		});
120             return method.invoke(object, arguments);
121         }
122     }
123 
124     public Class getDeclaringClass() {
125         return declaringClass;
126     }
127     
128     public void setDeclaringClass(Class c) {
129         declaringClass=c;
130     }
131 
132     public int getMethodIndex() {
133         return methodIndex;
134     }
135 
136     public void setMethodIndex(int methodIndex) {
137         this.methodIndex = methodIndex;
138     }
139 
140     public int getModifiers() {
141         return modifiers;
142     }
143 
144     public String getName() {
145         return name;
146     }
147 
148     public Class[] getParameterTypes() {
149         return parameterTypes;
150     }
151 
152     public Class getReturnType() {
153         return returnType;
154     }
155 
156     public Reflector getReflector() {
157         return reflector;
158     }
159 
160     public void setReflector(Reflector reflector) {
161         this.reflector = reflector;
162     }
163 
164     public boolean isMethod(Method method) {
165         return name.equals(method.getName())
166             && modifiers == method.getModifiers()
167             && returnType.equals(method.getReturnType())
168             && equal(parameterTypes, method.getParameterTypes());
169     }
170 
171     protected boolean equal(Class[] a, Class[] b) {
172         if (a.length == b.length) {
173             for (int i = 0, size = a.length; i < size; i++) {
174                 if (!a[i].equals(b[i])) {
175                     return false;
176                 }
177             }
178             return true;
179         }
180         return false;
181     }
182 
183     public String toString() {
184         return super.toString()
185             + "[name: "
186             + name
187             + " params: "
188             + InvokerHelper.toString(parameterTypes)
189             + " returns: "
190             + returnType
191             + " owner: "
192             + declaringClass
193             + "]";
194     }
195 
196     public Object clone() {
197         try {
198             return super.clone();
199         }
200         catch (CloneNotSupportedException e) {
201             throw new GroovyRuntimeException("This should never happen", e);
202         }
203     }
204 
205     public boolean isStatic() {
206         return (modifiers & Modifier.STATIC) != 0;
207     }
208 
209     public boolean isPrivate() {
210         return (modifiers & Modifier.PRIVATE) != 0;
211     }
212 
213     public boolean isProtected() {
214         return (modifiers & Modifier.PROTECTED) != 0;
215     }
216 
217     public boolean isPublic() {
218         return (modifiers & Modifier.PUBLIC) != 0;
219     }
220 
221     /***
222      * @return true if the given method has the same name, parameters, return type
223      * and modifiers but may be defined on another type
224      */
225     public boolean isSame(MetaMethod method) {
226         return name.equals(method.getName())
227             && compatibleModifiers(modifiers, method.getModifiers())
228             && returnType.equals(method.getReturnType())
229             && equal(parameterTypes, method.getParameterTypes());
230     }
231 
232     protected boolean compatibleModifiers(int modifiersA, int modifiersB) {
233         int mask = Modifier.PRIVATE | Modifier.PROTECTED | Modifier.PUBLIC | Modifier.STATIC;
234         return (modifiersA & mask) == (modifiersB & mask);
235     }
236 
237     public Class getInterfaceClass() {
238         return interfaceClass;
239     }
240 
241     public void setInterfaceClass(Class interfaceClass) {
242         this.interfaceClass = interfaceClass;
243     }
244 
245     public boolean isCacheable() {
246         return true;
247     }
248 
249 }