001: /*
002: $Id: Invoker.java 4294 2006-12-02 19:31:27Z 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
008: that the following conditions are met:
009:
010: 1. Redistributions of source code must retain copyright
011: statements and notices. Redistributions must also contain a
012: copy of this document.
013:
014: 2. Redistributions in binary form must reproduce the
015: above copyright notice, this list of conditions and the
016: following disclaimer in the documentation and/or other
017: materials provided with the distribution.
018:
019: 3. The name "groovy" must not be used to endorse or promote
020: products derived from this Software without prior written
021: permission of The Codehaus. For written permission,
022: please contact info@codehaus.org.
023:
024: 4. Products derived from this Software may not be called "groovy"
025: nor may "groovy" appear in their names without prior written
026: permission of The Codehaus. "groovy" is a registered
027: trademark of The Codehaus.
028:
029: 5. Due credit should be given to The Codehaus -
030: http://groovy.codehaus.org/
031:
032: THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
033: ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
034: NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
035: FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
036: THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
037: INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
038: (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
039: SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
040: HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
041: STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
042: ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
043: OF THE POSSIBILITY OF SUCH DAMAGE.
044:
045: */
046: package org.codehaus.groovy.runtime;
047:
048: import groovy.lang.Closure;
049: import groovy.lang.GroovyInterceptable;
050: import groovy.lang.GroovyObject;
051: import groovy.lang.GroovyRuntimeException;
052: import groovy.lang.MetaClass;
053: import groovy.lang.MetaClassRegistry;
054: import groovy.lang.MissingMethodException;
055:
056: import java.util.Map;
057:
058: /**
059: * A helper class to invoke methods or extract properties on arbitrary Java objects dynamically
060: *
061: * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
062: * @version $Revision: 4294 $
063: */
064: public class Invoker {
065:
066: protected static final Object[] EMPTY_ARGUMENTS = {};
067: protected static final Class[] EMPTY_TYPES = {};
068:
069: public MetaClassRegistry getMetaRegistry() {
070: return metaRegistry;
071: }
072:
073: private MetaClassRegistry metaRegistry = new MetaClassRegistry();
074:
075: public MetaClass getMetaClass(Object object) {
076: return metaRegistry.getMetaClass(object.getClass());
077: }
078:
079: /**
080: * Invokes the given method on the object.
081: *
082: * @param object
083: * @param methodName
084: * @param arguments
085: * @return
086: */
087: public Object invokeMethod(Object object, String methodName,
088: Object arguments) {
089: /*
090: System
091: .out
092: .println(
093: "Invoker - Invoking method on object: "
094: + object
095: + " method: "
096: + methodName
097: + " arguments: "
098: + InvokerHelper.toString(arguments));
099: */
100:
101: if (object == null) {
102: object = NullObject.getNullObject();
103: //throw new NullPointerException("Cannot invoke method " + methodName + "() on null object");
104: }
105:
106: // if the object is a Class, call a static method from that class
107: if (object instanceof Class) {
108: Class theClass = (Class) object;
109: MetaClass metaClass = metaRegistry.getMetaClass(theClass);
110: return metaClass.invokeStaticMethod(object, methodName,
111: asArray(arguments));
112: } else // it's an instance
113: {
114: // if it's not an object implementing GroovyObject (thus not builder, nor a closure)
115: if (!(object instanceof GroovyObject)) {
116: Class theClass = object.getClass();
117: MetaClass metaClass = metaRegistry
118: .getMetaClass(theClass);
119: return metaClass.invokeMethod(object, methodName,
120: asArray(arguments));
121: }
122: // it's an object implementing GroovyObject
123: else {
124: GroovyObject groovy = (GroovyObject) object;
125: try {
126: // if it's a pure interceptable object (even intercepting toString(), clone(), ...)
127: if (groovy instanceof GroovyInterceptable) {
128: return groovy.invokeMethod(methodName,
129: asArray(arguments));
130: }
131: //else if there's a statically typed method or a GDK method
132: else {
133: return groovy.getMetaClass().invokeMethod(
134: object, methodName, asArray(arguments));
135: }
136: } catch (MissingMethodException e) {
137: if (e.getMethod().equals(methodName)
138: && object.getClass() == e.getType()) {
139: // in case there's nothing else, invoke the object's own invokeMethod()
140: return groovy.invokeMethod(methodName,
141: asArray(arguments));
142: } else {
143: throw e;
144: }
145: }
146: }
147: }
148: }
149:
150: public Object invokeSuperMethod(Object object, String methodName,
151: Object arguments) {
152: if (object == null) {
153: throw new NullPointerException("Cannot invoke method "
154: + methodName + "() on null object");
155: }
156:
157: Class theClass = object.getClass();
158:
159: MetaClass metaClass = metaRegistry.getMetaClass(theClass
160: .getSuperclass());
161: return metaClass.invokeMethod(object, methodName,
162: asArray(arguments));
163: }
164:
165: public Object invokeStaticMethod(Class type, String method,
166: Object arguments) {
167: MetaClass metaClass = metaRegistry.getMetaClass(type);
168: return metaClass.invokeStaticMethod(type, method,
169: asArray(arguments));
170: }
171:
172: public Object invokeConstructorOf(Class type, Object arguments) {
173: MetaClass metaClass = metaRegistry.getMetaClass(type);
174: return metaClass.invokeConstructor(asArray(arguments));
175: }
176:
177: /**
178: * Converts the given object into an array; if its an array then just
179: * cast otherwise wrap it in an array
180: */
181: public Object[] asArray(Object arguments) {
182: if (arguments == null) {
183: return EMPTY_ARGUMENTS;
184: } else if (arguments instanceof Object[]) {
185: return (Object[]) arguments;
186: } else {
187: return new Object[] { arguments };
188: }
189: }
190:
191: /**
192: * Looks up the given property of the given object
193: */
194: public Object getProperty(Object object, String property) {
195: if (object == null) {
196: throw new NullPointerException("Cannot get property: "
197: + property + " on null object");
198: } else if (object instanceof GroovyObject) {
199: GroovyObject pogo = (GroovyObject) object;
200: return pogo.getProperty(property);
201: } else if (object instanceof Map) {
202: Map map = (Map) object;
203: return map.get(property);
204: } else if (object instanceof Class) {
205: Class c = (Class) object;
206: return metaRegistry.getMetaClass(c).getProperty(object,
207: property);
208: } else {
209: return metaRegistry.getMetaClass(object.getClass())
210: .getProperty(object, property);
211: }
212: }
213:
214: /**
215: * Sets the property on the given object
216: */
217: public void setProperty(Object object, String property,
218: Object newValue) {
219: if (object == null) {
220: throw new GroovyRuntimeException(
221: "Cannot set property on null object");
222: } else if (object instanceof GroovyObject) {
223: GroovyObject pogo = (GroovyObject) object;
224: pogo.setProperty(property, newValue);
225: } else if (object instanceof Map) {
226: Map map = (Map) object;
227: map.put(property, newValue);
228: } else {
229: if (object instanceof Class)
230: metaRegistry.getMetaClass((Class) object).setProperty(
231: (Class) object, property, newValue);
232: else
233: metaRegistry.getMetaClass(object.getClass())
234: .setProperty(object, property, newValue);
235: }
236: }
237:
238: /**
239: * Looks up the given attribute (field) on the given object
240: */
241: public Object getAttribute(Object object, String attribute) {
242: if (object == null) {
243: throw new NullPointerException("Cannot get attribute: "
244: + attribute + " on null object");
245:
246: /**
247: } else if (object instanceof GroovyObject) {
248: GroovyObject pogo = (GroovyObject) object;
249: return pogo.getAttribute(attribute);
250: } else if (object instanceof Map) {
251: Map map = (Map) object;
252: return map.get(attribute);
253: */
254: } else {
255: if (object instanceof Class) {
256: return metaRegistry.getMetaClass((Class) object)
257: .getAttribute(object, attribute);
258: } else if (object instanceof GroovyObject) {
259: return ((GroovyObject) object).getMetaClass()
260: .getAttribute(object, attribute);
261: } else {
262: return metaRegistry.getMetaClass(object.getClass())
263: .getAttribute(object, attribute);
264: }
265: }
266: }
267:
268: /**
269: * Sets the given attribute (field) on the given object
270: */
271: public void setAttribute(Object object, String attribute,
272: Object newValue) {
273: if (object == null) {
274: throw new GroovyRuntimeException(
275: "Cannot set attribute on null object");
276: /*
277: } else if (object instanceof GroovyObject) {
278: GroovyObject pogo = (GroovyObject) object;
279: pogo.setProperty(attribute, newValue);
280: } else if (object instanceof Map) {
281: Map map = (Map) object;
282: map.put(attribute, newValue);
283: */
284: } else {
285: if (object instanceof Class) {
286: metaRegistry.getMetaClass((Class) object).setAttribute(
287: object, attribute, newValue);
288: } else if (object instanceof GroovyObject) {
289: ((GroovyObject) object).getMetaClass().setAttribute(
290: object, attribute, newValue);
291: } else {
292: metaRegistry.getMetaClass(object.getClass())
293: .setAttribute(object, attribute, newValue);
294: }
295: }
296: }
297:
298: /**
299: * Returns the method pointer for the given object name
300: */
301: public Closure getMethodPointer(Object object, String methodName) {
302: if (object == null) {
303: throw new NullPointerException(
304: "Cannot access method pointer for '" + methodName
305: + "' on null object");
306: }
307: return MetaClassHelper.getMethodPointer(object, methodName);
308: }
309:
310: public void removeMetaClass(Class clazz) {
311: getMetaRegistry().removeMetaClass(clazz);
312: }
313: }
|