| /* |
| $Id$ |
| |
| Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved. |
| |
| Redistribution and use of this software and associated documentation |
| ("Software"), with or without modification, are permitted provided |
| that the following conditions are met: |
| |
| 1. Redistributions of source code must retain copyright |
| statements and notices. Redistributions must also contain a |
| copy of this document. |
| |
| 2. Redistributions in binary form must reproduce the |
| above copyright notice, this list of conditions and the |
| following disclaimer in the documentation and/or other |
| materials provided with the distribution. |
| |
| 3. The name "groovy" must not be used to endorse or promote |
| products derived from this Software without prior written |
| permission of The Codehaus. For written permission, |
| please contact info@codehaus.org. |
| |
| 4. Products derived from this Software may not be called "groovy" |
| nor may "groovy" appear in their names without prior written |
| permission of The Codehaus. "groovy" is a registered |
| trademark of The Codehaus. |
| |
| 5. Due credit should be given to The Codehaus - |
| http://groovy.codehaus.org/ |
| |
| THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS |
| ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT |
| NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND |
| FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL |
| THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, |
| INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
| (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR |
| SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
| HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, |
| STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
| ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED |
| OF THE POSSIBILITY OF SUCH DAMAGE. |
| |
| */ |
| package org.codehaus.groovy.runtime; |
| |
| import groovy.lang.Closure; |
| import groovy.lang.GroovyInterceptable; |
| import groovy.lang.GroovyObject; |
| import groovy.lang.GroovyRuntimeException; |
| import groovy.lang.MetaClass; |
| import groovy.lang.MetaClassRegistry; |
| import groovy.lang.MissingMethodException; |
| |
| import java.util.Map; |
| |
| /** |
| * A helper class to invoke methods or extract properties on arbitrary Java objects dynamically |
| * |
| * @author <a href="mailto:james@coredevelopers.net">James Strachan</a> |
| * @version $Revision$ |
| */ |
| public class Invoker { |
| |
| protected static final Object[] EMPTY_ARGUMENTS = { |
| }; |
| protected static final Class[] EMPTY_TYPES = { |
| }; |
| |
| public MetaClassRegistry getMetaRegistry() { |
| return metaRegistry; |
| } |
| |
| private MetaClassRegistry metaRegistry = new MetaClassRegistry(); |
| |
| public MetaClass getMetaClass(Object object) { |
| return metaRegistry.getMetaClass(object.getClass()); |
| } |
| |
| /** |
| * Invokes the given method on the object. |
| * |
| * @param object |
| * @param methodName |
| * @param arguments |
| * @return |
| */ |
| public Object invokeMethod(Object object, String methodName, Object arguments) { |
| /* |
| System |
| .out |
| .println( |
| "Invoker - Invoking method on object: " |
| + object |
| + " method: " |
| + methodName |
| + " arguments: " |
| + InvokerHelper.toString(arguments)); |
| */ |
| |
| if (object == null) { |
| object = NullObject.getNullObject(); |
| //throw new NullPointerException("Cannot invoke method " + methodName + "() on null object"); |
| } |
| |
| // if the object is a Class, call a static method from that class |
| if (object instanceof Class) { |
| Class theClass = (Class) object; |
| MetaClass metaClass = metaRegistry.getMetaClass(theClass); |
| return metaClass.invokeStaticMethod(object, methodName, asArray(arguments)); |
| } |
| else // it's an instance |
| { |
| // if it's not an object implementing GroovyObject (thus not builder, nor a closure) |
| if (!(object instanceof GroovyObject)) { |
| Class theClass = object.getClass(); |
| MetaClass metaClass = metaRegistry.getMetaClass(theClass); |
| return metaClass.invokeMethod(object, methodName, asArray(arguments)); |
| } |
| // it's an object implementing GroovyObject |
| else { |
| GroovyObject groovy = (GroovyObject) object; |
| try { |
| // if it's a pure interceptable object (even intercepting toString(), clone(), ...) |
| if (groovy instanceof GroovyInterceptable) { |
| return groovy.invokeMethod(methodName, asArray(arguments)); |
| } |
| //else if there's a statically typed method or a GDK method |
| else { |
| return groovy.getMetaClass().invokeMethod(object, methodName, asArray(arguments)); |
| } |
| } catch (MissingMethodException e) { |
| if (e.getMethod().equals(methodName) && object.getClass() == e.getType()) { |
| // in case there's nothing else, invoke the object's own invokeMethod() |
| return groovy.invokeMethod(methodName, asArray(arguments)); |
| } else { |
| throw e; |
| } |
| } |
| } |
| } |
| } |
| |
| public Object invokeSuperMethod(Object object, String methodName, Object arguments) { |
| if (object == null) { |
| throw new NullPointerException("Cannot invoke method " + methodName + "() on null object"); |
| } |
| |
| Class theClass = object.getClass(); |
| |
| MetaClass metaClass = metaRegistry.getMetaClass(theClass.getSuperclass()); |
| return metaClass.invokeMethod(object, methodName, asArray(arguments)); |
| } |
| |
| public Object invokeStaticMethod(Class type, String method, Object arguments) { |
| MetaClass metaClass = metaRegistry.getMetaClass(type); |
| return metaClass.invokeStaticMethod(type, method, asArray(arguments)); |
| } |
| |
| public Object invokeConstructorOf(Class type, Object arguments) { |
| MetaClass metaClass = metaRegistry.getMetaClass(type); |
| return metaClass.invokeConstructor(asArray(arguments)); |
| } |
| |
| /** |
| * Converts the given object into an array; if its an array then just |
| * cast otherwise wrap it in an array |
| */ |
| public Object[] asArray(Object arguments) { |
| if (arguments == null) { |
| return EMPTY_ARGUMENTS; |
| } else if (arguments instanceof Object[]) { |
| return (Object[]) arguments; |
| } else { |
| return new Object[]{arguments}; |
| } |
| } |
| |
| /** |
| * Looks up the given property of the given object |
| */ |
| public Object getProperty(Object object, String property) { |
| if (object == null) { |
| throw new NullPointerException("Cannot get property: " + property + " on null object"); |
| } |
| else if (object instanceof GroovyObject) { |
| GroovyObject pogo = (GroovyObject) object; |
| return pogo.getProperty(property); |
| } |
| else if (object instanceof Map) { |
| Map map = (Map) object; |
| return map.get(property); |
| } |
| else if (object instanceof Class) { |
| Class c = (Class) object; |
| return metaRegistry.getMetaClass(c).getProperty(object, property); |
| } |
| else { |
| return metaRegistry.getMetaClass(object.getClass()).getProperty(object, property); |
| } |
| } |
| |
| /** |
| * Sets the property on the given object |
| */ |
| public void setProperty(Object object, String property, Object newValue) { |
| if (object == null) { |
| throw new GroovyRuntimeException("Cannot set property on null object"); |
| } |
| else if (object instanceof GroovyObject) { |
| GroovyObject pogo = (GroovyObject) object; |
| pogo.setProperty(property, newValue); |
| } |
| else if (object instanceof Map) { |
| Map map = (Map) object; |
| map.put(property, newValue); |
| } |
| else { |
| if (object instanceof Class) |
| metaRegistry.getMetaClass((Class) object).setProperty((Class) object, property, newValue); |
| else |
| metaRegistry.getMetaClass(object.getClass()).setProperty(object, property, newValue); |
| } |
| } |
| |
| /** |
| * Looks up the given attribute (field) on the given object |
| */ |
| public Object getAttribute(Object object, String attribute) { |
| if (object == null) { |
| throw new NullPointerException("Cannot get attribute: " + attribute + " on null object"); |
| |
| /** |
| } else if (object instanceof GroovyObject) { |
| GroovyObject pogo = (GroovyObject) object; |
| return pogo.getAttribute(attribute); |
| } else if (object instanceof Map) { |
| Map map = (Map) object; |
| return map.get(attribute); |
| */ |
| } |
| else { |
| if (object instanceof Class) { |
| return metaRegistry.getMetaClass((Class) object).getAttribute(object, attribute); |
| } else if (object instanceof GroovyObject) { |
| return ((GroovyObject)object).getMetaClass().getAttribute(object, attribute); |
| } else { |
| return metaRegistry.getMetaClass(object.getClass()).getAttribute(object, attribute); |
| } |
| } |
| } |
| |
| /** |
| * Sets the given attribute (field) on the given object |
| */ |
| public void setAttribute(Object object, String attribute, Object newValue) { |
| if (object == null) { |
| throw new GroovyRuntimeException("Cannot set attribute on null object"); |
| /* |
| } else if (object instanceof GroovyObject) { |
| GroovyObject pogo = (GroovyObject) object; |
| pogo.setProperty(attribute, newValue); |
| } else if (object instanceof Map) { |
| Map map = (Map) object; |
| map.put(attribute, newValue); |
| */ |
| } |
| else { |
| if (object instanceof Class) { |
| metaRegistry.getMetaClass((Class) object).setAttribute(object, attribute, newValue); |
| } else if (object instanceof GroovyObject) { |
| ((GroovyObject)object).getMetaClass().setAttribute(object, attribute, newValue); |
| } else { |
| metaRegistry.getMetaClass(object.getClass()).setAttribute(object, attribute, newValue); |
| } |
| } |
| } |
| |
| /** |
| * Returns the method pointer for the given object name |
| */ |
| public Closure getMethodPointer(Object object, String methodName) { |
| if (object == null) { |
| throw new NullPointerException("Cannot access method pointer for '" + methodName + "' on null object"); |
| } |
| return MetaClassHelper.getMethodPointer(object, methodName); |
| } |
| |
| public void removeMetaClass(Class clazz) { |
| getMetaRegistry().removeMetaClass(clazz); |
| } |
| } |