View Javadoc

    1   /*
    2    $Id: Invoker.java 4294 2006-12-02 19:31:27Z blackdrag $
    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
    8    that the following conditions are met:
    9
    10   1. Redistributions of source code must retain copyright
    11      statements and notices.  Redistributions must also contain a
    12      copy of this document.
    13
    14   2. Redistributions in binary form must reproduce the
    15      above copyright notice, this list of conditions and the
    16      following disclaimer in the documentation and/or other
    17      materials provided with the distribution.
    18
    19   3. The name "groovy" must not be used to endorse or promote
    20      products derived from this Software without prior written
    21      permission of The Codehaus.  For written permission,
    22      please contact info@codehaus.org.
    23
    24   4. Products derived from this Software may not be called "groovy"
    25      nor may "groovy" appear in their names without prior written
    26      permission of The Codehaus. "groovy" is a registered
    27      trademark of The Codehaus.
    28
    29   5. Due credit should be given to The Codehaus -
    30      http://groovy.codehaus.org/
    31
    32   THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
    33   ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
    34   NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
    35   FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
    36   THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
    37   INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
    38   (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
    39   SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
    40   HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
    41   STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    42   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
    43   OF THE POSSIBILITY OF SUCH DAMAGE.
    44
    45   */
    46  package org.codehaus.groovy.runtime;
    47
    48  import groovy.lang.Closure;
    49  import groovy.lang.GroovyInterceptable;
    50  import groovy.lang.GroovyObject;
    51  import groovy.lang.GroovyRuntimeException;
    52  import groovy.lang.MetaClass;
    53  import groovy.lang.MetaClassRegistry;
    54  import groovy.lang.MissingMethodException;
    55
    56  import java.util.Map;
    57
    58  /***
    59   * A helper class to invoke methods or extract properties on arbitrary Java objects dynamically
    60   *
    61   * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
    62   * @version $Revision: 4294 $
    63   */
    64  public class Invoker {
    65
    66      protected static final Object[] EMPTY_ARGUMENTS = {
    67      };
    68      protected static final Class[] EMPTY_TYPES = {
    69      };
    70
    71      public MetaClassRegistry getMetaRegistry() {
    72          return metaRegistry;
    73      }
    74
    75      private MetaClassRegistry metaRegistry = new MetaClassRegistry();
    76
    77      public MetaClass getMetaClass(Object object) {
    78          return metaRegistry.getMetaClass(object.getClass());
    79      }
    80
    81      /***
    82       * Invokes the given method on the object.
    83       *
    84       * @param object
    85       * @param methodName
    86       * @param arguments
    87       * @return
    88       */
    89      public Object invokeMethod(Object object, String methodName, Object arguments) {
    90          /*
    91          System
    92              .out
    93              .println(
    94                  "Invoker - Invoking method on object: "
    95                      + object
    96                      + " method: "
    97                      + methodName
    98                      + " arguments: "
    99                      + InvokerHelper.toString(arguments));
    100                     */
    101
    102         if (object == null) {
    103             object = NullObject.getNullObject();
    104             //throw new NullPointerException("Cannot invoke method " + methodName + "() on null object");
    105         }
    106
    107         // if the object is a Class, call a static method from that class
    108         if (object instanceof Class) {
    109             Class theClass = (Class) object;
    110             MetaClass metaClass = metaRegistry.getMetaClass(theClass);
    111             return metaClass.invokeStaticMethod(object, methodName, asArray(arguments));
    112         }
    113         else // it's an instance
    114         {
    115             // if it's not an object implementing GroovyObject (thus not builder, nor a closure)
    116             if (!(object instanceof GroovyObject)) {
    117                 Class theClass = object.getClass();
    118                 MetaClass metaClass = metaRegistry.getMetaClass(theClass);
    119                 return metaClass.invokeMethod(object, methodName, asArray(arguments));
    120             }
    121             // it's an object implementing GroovyObject
    122             else {
    123                 GroovyObject groovy = (GroovyObject) object;
    124                 try {
    125                     // if it's a pure interceptable object (even intercepting toString(), clone(), ...)
    126                     if (groovy instanceof GroovyInterceptable) {
    127                         return groovy.invokeMethod(methodName, asArray(arguments));
    128                     }
    129                     //else if there's a statically typed method or a GDK method
    130                     else {
    131                         return groovy.getMetaClass().invokeMethod(object, methodName, asArray(arguments));
    132                     }
    133                 } catch (MissingMethodException e) {
    134                     if (e.getMethod().equals(methodName) && object.getClass() == e.getType()) {
    135                         // in case there's nothing else, invoke the object's own invokeMethod()
    136                         return groovy.invokeMethod(methodName, asArray(arguments));
    137                     } else {
    138                         throw e;
    139                     }
    140                 }
    141             }
    142         }
    143     }
    144
    145     public Object invokeSuperMethod(Object object, String methodName, Object arguments) {
    146         if (object == null) {
    147             throw new NullPointerException("Cannot invoke method " + methodName + "() on null object");
    148         }
    149
    150         Class theClass = object.getClass();
    151
    152         MetaClass metaClass = metaRegistry.getMetaClass(theClass.getSuperclass());
    153         return metaClass.invokeMethod(object, methodName, asArray(arguments));
    154     }
    155
    156     public Object invokeStaticMethod(Class type, String method, Object arguments) {
    157         MetaClass metaClass = metaRegistry.getMetaClass(type);
    158         return metaClass.invokeStaticMethod(type, method, asArray(arguments));
    159     }
    160
    161     public Object invokeConstructorOf(Class type, Object arguments) {
    162         MetaClass metaClass = metaRegistry.getMetaClass(type);
    163         return metaClass.invokeConstructor(asArray(arguments));
    164     }
    165
    166     /***
    167      * Converts the given object into an array; if its an array then just
    168      * cast otherwise wrap it in an array
    169      */
    170     public Object[] asArray(Object arguments) {
    171         if (arguments == null) {
    172             return EMPTY_ARGUMENTS;
    173         } else if (arguments instanceof Object[]) {
    174             return (Object[]) arguments;
    175         } else {
    176             return new Object[]{arguments};
    177         }
    178     }
    179
    180     /***
    181      * Looks up the given property of the given object
    182      */
    183     public Object getProperty(Object object, String property) {
    184         if (object == null) {
    185             throw new NullPointerException("Cannot get property: " + property + " on null object");
    186         }
    187         else if (object instanceof GroovyObject) {
    188             GroovyObject pogo = (GroovyObject) object;
    189             return pogo.getProperty(property);
    190         }
    191         else if (object instanceof Map) {
    192             Map map = (Map) object;
    193             return map.get(property);
    194         }
    195         else if (object instanceof Class) {
    196             Class c = (Class) object;
    197             return metaRegistry.getMetaClass(c).getProperty(object, property);
    198         }
    199         else {
    200             return metaRegistry.getMetaClass(object.getClass()).getProperty(object, property);
    201         }
    202     }
    203
    204     /***
    205      * Sets the property on the given object
    206      */
    207     public void setProperty(Object object, String property, Object newValue) {
    208         if (object == null) {
    209             throw new GroovyRuntimeException("Cannot set property on null object");
    210         }
    211         else if (object instanceof GroovyObject) {
    212             GroovyObject pogo = (GroovyObject) object;
    213             pogo.setProperty(property, newValue);
    214         }
    215         else if (object instanceof Map) {
    216             Map map = (Map) object;
    217             map.put(property, newValue);
    218         }
    219         else {
    220             if (object instanceof Class)
    221                 metaRegistry.getMetaClass((Class) object).setProperty((Class) object, property, newValue);
    222             else
    223                 metaRegistry.getMetaClass(object.getClass()).setProperty(object, property, newValue);
    224         }
    225     }
    226
    227     /***
    228      * Looks up the given attribute (field) on the given object
    229      */
    230     public Object getAttribute(Object object, String attribute) {
    231         if (object == null) {
    232             throw new NullPointerException("Cannot get attribute: " + attribute + " on null object");
    233
    234             /***
    235              } else if (object instanceof GroovyObject) {
    236              GroovyObject pogo = (GroovyObject) object;
    237              return pogo.getAttribute(attribute);
    238              } else if (object instanceof Map) {
    239              Map map = (Map) object;
    240              return map.get(attribute);
    241              */
    242         }
    243         else {
    244             if (object instanceof Class) {
    245                 return metaRegistry.getMetaClass((Class) object).getAttribute(object, attribute);
    246             } else if (object instanceof GroovyObject) {
    247                 return ((GroovyObject)object).getMetaClass().getAttribute(object, attribute);
    248             } else {
    249                 return metaRegistry.getMetaClass(object.getClass()).getAttribute(object, attribute);
    250             }
    251 	}
    252     }
    253
    254     /***
    255      * Sets the given attribute (field) on the given object
    256      */
    257     public void setAttribute(Object object, String attribute, Object newValue) {
    258         if (object == null) {
    259             throw new GroovyRuntimeException("Cannot set attribute on null object");
    260             /*
    261         } else if (object instanceof GroovyObject) {
    262             GroovyObject pogo = (GroovyObject) object;
    263             pogo.setProperty(attribute, newValue);
    264         } else if (object instanceof Map) {
    265             Map map = (Map) object;
    266             map.put(attribute, newValue);
    267             */
    268         }
    269         else {
    270             if (object instanceof Class) {
    271                 metaRegistry.getMetaClass((Class) object).setAttribute(object, attribute, newValue);
    272             } else if (object instanceof GroovyObject) {
    273                 ((GroovyObject)object).getMetaClass().setAttribute(object, attribute, newValue);
    274             } else {
    275                 metaRegistry.getMetaClass(object.getClass()).setAttribute(object, attribute, newValue);
    276             }
    277 	}
    278     }
    279
    280     /***
    281      * Returns the method pointer for the given object name
    282      */
    283     public Closure getMethodPointer(Object object, String methodName) {
    284         if (object == null) {
    285             throw new NullPointerException("Cannot access method pointer for '" + methodName + "' on null object");
    286         }
    287         return MetaClassHelper.getMethodPointer(object, methodName);
    288     }
    289
    290     public void removeMetaClass(Class clazz) {
    291         getMetaRegistry().removeMetaClass(clazz);
    292     }
    293 }