001: /*
002: * Copyright 2005 John G. Wilson
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: *
016: */
017:
018: package groovy.lang;
019:
020: import java.lang.reflect.Method;
021: import java.util.List;
022: import java.util.logging.Logger;
023:
024: import org.codehaus.groovy.ast.ClassNode;
025: import org.codehaus.groovy.runtime.MetaClassHelper;
026:
027: /**
028: * Base class for meta class implementations.
029: * The meta class is used to invoke methods or to get
030: * fields/properties. For proper initialization of this class
031: * it is not enough to only call the constructor, the
032: * initialize() must be called too. The invoke methods should
033: * check that initialize() was called. Adding methods is
034: * valid unless initilise method was called. Therefore
035: * addNewStaticMethod and addNewInstanceMethod should check that
036: * that initilise awas not called before.
037: *
038: *
039: * @author John Wilson
040: *
041: */
042:
043: public abstract class MetaClass {
044: protected static final Logger log = Logger
045: .getLogger(MetaClass.class.getName());
046: protected static boolean useReflection = false;
047: public static final Object NO_METHOD_FOUND = new Object();
048: protected final Class theClass;
049: private boolean isGroovyObject;
050:
051: public static boolean isUseReflection() {
052: return MetaClass.useReflection;
053: }
054:
055: /**
056: * Allows reflection to be enabled in situations where bytecode generation
057: * of method invocations causes issues.
058: *
059: * @param useReflection
060: */
061: public static void setUseReflection(boolean useReflection) {
062: MetaClass.useReflection = useReflection;
063: }
064:
065: protected MetaClass(final Class theClass) {
066: this .theClass = theClass;
067: isGroovyObject = GroovyObject.class.isAssignableFrom(theClass);
068: }
069:
070: public boolean isGroovyObject() {
071: return isGroovyObject;
072: }
073:
074: public Object invokeMissingMethod(Object instance,
075: String methodName, Object[] arguments) {
076: GroovyObject pogo = (GroovyObject) instance;
077: return pogo.invokeMethod(methodName, arguments);
078: }
079:
080: public Object invokeMethod(Object object, String methodName,
081: Object arguments) {
082: if (arguments == null) {
083: return invokeMethod(object, methodName,
084: MetaClassHelper.EMPTY_ARRAY);
085: }
086: if (arguments instanceof Tuple) {
087: Tuple tuple = (Tuple) arguments;
088: return invokeMethod(object, methodName, tuple.toArray());
089: }
090: if (arguments instanceof Object[]) {
091: return invokeMethod(object, methodName,
092: (Object[]) arguments);
093: } else {
094: return invokeMethod(object, methodName,
095: new Object[] { arguments });
096: }
097: }
098:
099: public Object invokeMethod(Class sender, Object receiver,
100: String methodName, Object[] arguments,
101: boolean isCallToSuper, boolean fromInsideClass) {
102: return invokeMethod(receiver, methodName, arguments);
103: }
104:
105: public Object getProperty(Class sender, Object receiver,
106: String messageName, boolean useSuper,
107: boolean fromInsideClass) {
108: return getProperty(receiver, messageName);
109: }
110:
111: public void setProperty(Class sender, Object receiver,
112: String messageName, Object messageValue, boolean useSuper,
113: boolean fromInsideClass) {
114: setProperty(receiver, messageName, messageValue);
115: }
116:
117: public Object getAttribute(Class sender, Object receiver,
118: String messageName, boolean useSuper) {
119: return getAttribute(receiver, messageName);
120: }
121:
122: public void setAttribute(Class sender, Object receiver,
123: String messageName, Object messageValue, boolean useSuper,
124: boolean fromInsideClass) {
125: setAttribute(receiver, messageName, messageValue);
126: }
127:
128: public abstract Object invokeConstructor(Object[] arguments);
129:
130: public abstract Object invokeMethod(Object object,
131: String methodName, Object[] arguments);
132:
133: public abstract Object invokeStaticMethod(Object object,
134: String methodName, Object[] arguments);
135:
136: public abstract Object getProperty(Object object, String property);
137:
138: public abstract void setProperty(Object object, String property,
139: Object newValue);
140:
141: public abstract Object getAttribute(Object object, String attribute);
142:
143: public abstract void setAttribute(Object object, String attribute,
144: Object newValue);
145:
146: /**
147: * adds a new instance method to this meta class. Instance
148: * methods are able to overwrite the original methods of the
149: * class. Calling this method should not be done after
150: * initlise was called.
151: * @param method the method to be added
152: */
153: public abstract void addNewInstanceMethod(Method method);
154:
155: /**
156: * adds a new static method to this meta class. This is only
157: * possible as long as initilise was not called.
158: * @param method the method to be added
159: */
160: public abstract void addNewStaticMethod(Method method);
161:
162: /**
163: * complete the initlialisation process. After this method
164: * is called no methods should be added to the meta class.
165: * Invocation of methods or access to fields/proeprties is
166: * forbidden unless this method is called. This method
167: * should contain any initialisation code, taking a longer
168: * time to complete. An example is the creation of the
169: * Reflector. It is suggested to synchronize this
170: * method.
171: */
172: public abstract void initialize();
173:
174: public abstract List getProperties();
175:
176: public abstract ClassNode getClassNode();
177:
178: public abstract List getMetaMethods();
179:
180: public abstract List getMethods();
181:
182: /**
183: * Warning, this method will be removed
184: * @deprecated use invokeConstructor instead
185: */
186: public Object invokeConstructorAt(Class at, Object[] arguments) {
187: return invokeConstructor(arguments);
188: }
189:
190: /**
191: * Selects a method by name and argument classes. This method
192: * does not search for an exact match, it searches for a compatible
193: * method. For this the method selection mechanism is used as provided
194: * bye the implementation of this MetaClass. pickMethod may or may
195: * not used during the method selection process when invoking a method
196: * thereis no warranty for that.
197: *
198: * @returns a matching MetaMethod or null
199: * @throws GroovyRuntimeException if there is more than one matching method
200: */
201: public abstract MetaMethod pickMethod(String methodName,
202: Class[] arguments);
203:
204: /**
205: * Warning, this method will be removed
206: * @deprecated usw pickMethod instead
207: */
208: protected MetaMethod retrieveMethod(String methodName,
209: Class[] arguments) {
210: return pickMethod(methodName, arguments);
211: }
212:
213: }
|