001: /*
002: * $Id: MetaMethod.java 4254 2006-11-23 20:38:19Z blackdrag $
003: *
004: * Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
005: *
006: * Redistribution and use of this software and associated documentation
007: * ("Software"), with or without modification, are permitted provided that the
008: * following conditions are met:
009: * 1. Redistributions of source code must retain copyright statements and
010: * notices. Redistributions must also contain a copy of this document.
011: * 2. Redistributions in binary form must reproduce the above copyright
012: * notice, this list of conditions and the following disclaimer in the
013: * documentation and/or other materials provided with the distribution.
014: * 3. The name "groovy" must not be used to endorse or promote products
015: * derived from this Software without prior written permission of The Codehaus.
016: * For written permission, please contact info@codehaus.org.
017: * 4. Products derived from this Software may not be called "groovy" nor may
018: * "groovy" appear in their names without prior written permission of The
019: * Codehaus. "groovy" is a registered trademark of The Codehaus.
020: * 5. Due credit should be given to The Codehaus - http://groovy.codehaus.org/
021: *
022: * THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS ``AS IS'' AND ANY
023: * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
024: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
025: * DISCLAIMED. IN NO EVENT SHALL THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR
026: * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
027: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
028: * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
029: * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
030: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
031: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
032: * DAMAGE.
033: *
034: */
035: package groovy.lang;
036:
037: import java.lang.reflect.Method;
038: import java.lang.reflect.Modifier;
039: import java.security.AccessController;
040: import java.security.PrivilegedAction;
041: import java.util.logging.Logger;
042:
043: import org.codehaus.groovy.runtime.InvokerHelper;
044: import org.codehaus.groovy.runtime.InvokerInvocationException;
045: import org.codehaus.groovy.runtime.MetaClassHelper;
046: import org.codehaus.groovy.runtime.Reflector;
047:
048: /**
049: * Represents a Method on a Java object a little like {@link java.lang.reflect.Method}
050: * except without using reflection to invoke the method
051: *
052: * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
053: * @version $Revision: 4254 $
054: */
055: public class MetaMethod implements Cloneable {
056:
057: private static final Logger log = Logger.getLogger(MetaMethod.class
058: .getName());
059:
060: private String name;
061: private Class callClass;
062: private Class declaringClass;
063: private Class interfaceClass;
064: private Class[] parameterTypes;
065: private Class returnType;
066: private int modifiers;
067: private Reflector reflector;
068: private int methodIndex;
069: private Method method;
070:
071: public MetaMethod(String name, Class declaringClass,
072: Class[] parameterTypes, Class returnType, int modifiers) {
073: this .name = name;
074: this .callClass = declaringClass;
075: this .declaringClass = declaringClass;
076: this .parameterTypes = parameterTypes;
077: this .returnType = returnType;
078: this .modifiers = modifiers;
079: }
080:
081: public MetaMethod(Method method) {
082: this (method.getName(), method.getDeclaringClass(), method
083: .getParameterTypes(), method.getReturnType(), method
084: .getModifiers());
085: this .method = method;
086: }
087:
088: public MetaMethod(MetaMethod metaMethod) {
089: this (metaMethod.method);
090: }
091:
092: /**
093: * Checks that the given parameters are valid to call this method
094: *
095: * @param arguments
096: * @throws IllegalArgumentException if the parameters are not valid
097: */
098: public void checkParameters(Class[] arguments) {
099: // lets check that the argument types are valid
100: if (!MetaClassHelper.isValidMethod(getParameterTypes(),
101: arguments, false)) {
102: throw new IllegalArgumentException("Parameters to method: "
103: + getName() + " do not match types: "
104: + InvokerHelper.toString(getParameterTypes())
105: + " for arguments: "
106: + InvokerHelper.toString(arguments));
107: }
108: }
109:
110: public Object invoke(Object object, Object[] arguments) {
111: try {
112: if (reflector != null) {
113: return reflector.invoke(this , object, arguments);
114: } else {
115: AccessController.doPrivileged(new PrivilegedAction() {
116: public Object run() {
117: method.setAccessible(true);
118: return null;
119: }
120: });
121: return method.invoke(object, arguments);
122: }
123: } catch (Exception e) {
124: throw new InvokerInvocationException(e);
125: }
126: }
127:
128: public Class getCallClass() {
129: return callClass;
130: }
131:
132: public void setCallClass(Class c) {
133: callClass = c;
134: }
135:
136: public int getMethodIndex() {
137: return methodIndex;
138: }
139:
140: public void setMethodIndex(int methodIndex) {
141: this .methodIndex = methodIndex;
142: }
143:
144: public int getModifiers() {
145: return modifiers;
146: }
147:
148: public String getName() {
149: return name;
150: }
151:
152: public Class[] getParameterTypes() {
153: return parameterTypes;
154: }
155:
156: public Class getReturnType() {
157: return returnType;
158: }
159:
160: public Reflector getReflector() {
161: return reflector;
162: }
163:
164: public void setReflector(Reflector reflector) {
165: this .reflector = reflector;
166: }
167:
168: public boolean isMethod(Method method) {
169: return name.equals(method.getName())
170: && modifiers == method.getModifiers()
171: && returnType.equals(method.getReturnType())
172: && equal(parameterTypes, method.getParameterTypes());
173: }
174:
175: protected boolean equal(Class[] a, Class[] b) {
176: if (a.length == b.length) {
177: for (int i = 0, size = a.length; i < size; i++) {
178: if (!a[i].equals(b[i])) {
179: return false;
180: }
181: }
182: return true;
183: }
184: return false;
185: }
186:
187: public String toString() {
188: return super .toString() + "[name: " + name + " params: "
189: + InvokerHelper.toString(parameterTypes) + " returns: "
190: + returnType + " owner: " + callClass + "]";
191: }
192:
193: public Object clone() {
194: try {
195: return super .clone();
196: } catch (CloneNotSupportedException e) {
197: throw new GroovyRuntimeException(
198: "This should never happen", e);
199: }
200: }
201:
202: public boolean isStatic() {
203: return (modifiers & Modifier.STATIC) != 0;
204: }
205:
206: public boolean isPrivate() {
207: return (modifiers & Modifier.PRIVATE) != 0;
208: }
209:
210: public boolean isProtected() {
211: return (modifiers & Modifier.PROTECTED) != 0;
212: }
213:
214: public boolean isPublic() {
215: return (modifiers & Modifier.PUBLIC) != 0;
216: }
217:
218: /**
219: * @return true if the given method has the same name, parameters, return type
220: * and modifiers but may be defined on another type
221: */
222: public boolean isSame(MetaMethod method) {
223: return name.equals(method.getName())
224: && compatibleModifiers(modifiers, method.getModifiers())
225: && returnType.equals(method.getReturnType())
226: && equal(parameterTypes, method.getParameterTypes());
227: }
228:
229: protected boolean compatibleModifiers(int modifiersA, int modifiersB) {
230: int mask = Modifier.PRIVATE | Modifier.PROTECTED
231: | Modifier.PUBLIC | Modifier.STATIC;
232: return (modifiersA & mask) == (modifiersB & mask);
233: }
234:
235: public Class getInterfaceClass() {
236: return interfaceClass;
237: }
238:
239: public void setInterfaceClass(Class interfaceClass) {
240: this .interfaceClass = interfaceClass;
241: }
242:
243: public boolean isCacheable() {
244: return true;
245: }
246:
247: public Class getDeclaringClass() {
248: return declaringClass;
249: }
250: }
|