View Javadoc

1   /*
2    * Copyright 2005 John G. Wilson
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   *
16   */
17  
18  package groovy.lang;
19  
20  import java.lang.reflect.Method;
21  import java.util.List;
22  import java.util.logging.Logger;
23  
24  import org.codehaus.groovy.ast.ClassNode;
25  import org.codehaus.groovy.runtime.MetaClassHelper;
26  
27  /***
28   * Base class for meta class implementations. 
29   * The meta class is used to invoke methods or to get 
30   * fields/properties. For proper initialization of this class 
31   * it is not enough to only call the constructor, the
32   * initialize() must be called too. The invoke methods should
33   * check that initialize() was called. Adding methods is
34   * valid unless initilise method was called. Therefore 
35   * addNewStaticMethod and addNewInstanceMethod should check that
36   * that initilise awas not called before.
37   * 
38   * 
39   * @author John Wilson
40   *
41   */
42  
43  public abstract class MetaClass {
44      protected static final Logger log = Logger.getLogger(MetaClass.class.getName());
45      protected static boolean useReflection = false;
46      public static final Object NO_METHOD_FOUND = new Object();
47      protected final Class theClass;
48      private boolean isGroovyObject;
49      
50      public static boolean isUseReflection() {
51          return MetaClass.useReflection;
52      }
53  
54      /***
55       * Allows reflection to be enabled in situations where bytecode generation
56       * of method invocations causes issues.
57       *
58       * @param useReflection
59       */
60      public static void setUseReflection(boolean useReflection) {
61          MetaClass.useReflection = useReflection;
62      }
63      
64      protected MetaClass(final Class theClass) {
65          this.theClass = theClass;
66          isGroovyObject = GroovyObject.class.isAssignableFrom(theClass);
67      }
68      
69      public boolean isGroovyObject(){
70          return isGroovyObject;
71      }
72      
73      public Object invokeMissingMethod(Object instance, String methodName, Object[] arguments) {
74          GroovyObject pogo = (GroovyObject) instance;
75          return pogo.invokeMethod(methodName,arguments);
76      }
77      
78      public Object invokeMethod(Object object, String methodName, Object arguments) {
79          if (arguments == null) {
80              return invokeMethod(object, methodName, MetaClassHelper.EMPTY_ARRAY);
81          }
82          if (arguments instanceof Tuple) {
83              Tuple tuple = (Tuple) arguments;
84              return invokeMethod(object, methodName, tuple.toArray());
85          }
86          if (arguments instanceof Object[]) {
87              return invokeMethod(object, methodName, (Object[])arguments);
88          }
89          else {
90              return invokeMethod(object, methodName, new Object[]{arguments});
91          }
92      }
93      
94      public Object invokeMethod(Class sender, Object receiver, String methodName, Object[] arguments, boolean isCallToSuper, boolean fromInsideClass){
95          return invokeMethod(receiver,methodName,arguments);
96      }
97      
98      public Object getProperty(Class sender, Object receiver, String messageName, boolean useSuper, boolean fromInsideClass) {
99          return getProperty(receiver,messageName);
100     }
101     
102     public void setProperty(Class sender, Object receiver, String messageName, Object messageValue, boolean useSuper, boolean fromInsideClass) {
103         setProperty(receiver,messageName,messageValue);
104     }
105     
106     public Object getAttribute(Class sender, Object receiver, String messageName, boolean useSuper) {
107         return getAttribute(receiver,messageName);
108     }
109     
110     public void setAttribute(Class sender, Object receiver, String messageName, Object messageValue, boolean useSuper, boolean fromInsideClass) {
111         setAttribute(receiver,messageName,messageValue);
112     }
113     
114     public abstract Object invokeConstructor(Object[] arguments);
115     public abstract Object invokeMethod(Object object, String methodName, Object[] arguments);
116     public abstract Object invokeStaticMethod(Object object, String methodName, Object[] arguments);
117     public abstract Object getProperty(Object object, String property);
118     public abstract void setProperty(Object object, String property, Object newValue);
119     public abstract Object getAttribute(Object object, String attribute);
120     public abstract void setAttribute(Object object, String attribute, Object newValue);
121     /***
122      * adds a new instance method to this meta class. Instance
123      * methods are able to overwrite the original methods of the
124      * class. Calling this method should not be done after 
125      * initlise was called.
126      * @param method the method to be added
127      */
128     public abstract void addNewInstanceMethod(Method method);
129     /***
130      * adds a new static method to this meta class. This is only
131      * possible as long as initilise was not called.
132      * @param method the method to be added
133      */
134     public abstract void addNewStaticMethod(Method method);
135     /***
136      * complete the initlialisation process. After this method
137      * is called no methods should be added to the meta class.
138      * Invocation of methods or access to fields/proeprties is
139      * forbidden unless this method is called. This method 
140      * should contain any initialisation code, taking a longer
141      * time to complete. An example is the creation of the 
142      * Reflector. It is suggested to synchronize this 
143      * method.
144      */
145     public abstract void initialize();
146     
147     public abstract List getProperties();
148     public abstract ClassNode getClassNode();
149     public abstract List getMetaMethods();
150     
151     public abstract List getMethods();
152     
153     /***
154      * Warning, this method will be removed
155      * @deprecated use invokeConstructor instead
156      */
157     public Object invokeConstructorAt(Class at, Object[] arguments) {
158         return invokeConstructor(arguments);
159     }
160 
161     /***
162      * Selects a method by name and argument classes. This method
163      * does not search for an exact match, it searches for a compatible
164      * method. For this the method selection mechanism is used as provided
165      * bye the implementation of this MetaClass. pickMethod may or may
166      * not used during the method selection process when invoking a method
167      * thereis no warranty for that.
168      * 
169      * @returns a matching MetaMethod or null
170      * @throws GroovyRuntimeException if there is more than one matching method
171      */
172     public abstract MetaMethod pickMethod(String methodName, Class[] arguments);
173     
174     /***
175      * Warning, this method will be removed
176      * @deprecated usw pickMethod instead
177      */
178     protected MetaMethod retrieveMethod(String methodName, Class[] arguments) {
179         return pickMethod(methodName,arguments);
180     }
181 
182 }