001: /*
002: * Copyright 2003,2004 The Apache Software Foundation
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: package net.sf.cglib.reflect;
017:
018: import java.lang.reflect.*;
019: import net.sf.cglib.*;
020: import net.sf.cglib.core.*;
021: import org.objectweb.asm.ClassVisitor;
022: import org.objectweb.asm.Type;
023:
024: // TODO: don't require exact match for return type
025:
026: /**
027: * <b>DOCUMENTATION FROM APACHE AVALON DELEGATE CLASS</b>
028: *
029: * <p>
030: * Delegates are a typesafe pointer to another method. Since Java does not
031: * have language support for such a construct, this utility will construct
032: * a proxy that forwards method calls to any method with the same signature.
033: * This utility is inspired in part by the C# delegate mechanism. We
034: * implemented it in a Java-centric manner.
035: * </p>
036: *
037: * <h2>Delegate</h2>
038: * <p>
039: * Any interface with one method can become the interface for a delegate.
040: * Consider the example below:
041: * </p>
042: *
043: * <pre>
044: * public interface MainDelegate {
045: * int main(String[] args);
046: * }
047: * </pre>
048: *
049: * <p>
050: * The interface above is an example of an interface that can become a
051: * delegate. It has only one method, and the interface is public. In
052: * order to create a delegate for that method, all we have to do is
053: * call <code>MethodDelegate.create(this, "alternateMain", MainDelegate.class)</code>.
054: * The following program will show how to use it:
055: * </p>
056: *
057: * <pre>
058: * public class Main {
059: * public static int main( String[] args ) {
060: * Main newMain = new Main();
061: * MainDelegate start = (MainDelegate)
062: * MethodDelegate.create(newMain, "alternateMain", MainDelegate.class);
063: * return start.main( args );
064: * }
065: *
066: * public int alternateMain( String[] args ) {
067: * for (int i = 0; i < args.length; i++) {
068: * System.out.println( args[i] );
069: * }
070: * return args.length;
071: * }
072: * }
073: * </pre>
074: *
075: * <p>
076: * By themselves, delegates don't do much. Their true power lies in the fact that
077: * they can be treated like objects, and passed to other methods. In fact that is
078: * one of the key building blocks of building Intelligent Agents which in tern are
079: * the foundation of artificial intelligence. In the above program, we could have
080: * easily created the delegate to match the static <code>main</code> method by
081: * substituting the delegate creation call with this:
082: * <code>MethodDelegate.createStatic(getClass(), "main", MainDelegate.class)</code>.
083: * </p>
084: * <p>
085: * Another key use for Delegates is to register event listeners. It is much easier
086: * to have all the code for your events separated out into methods instead of individual
087: * classes. One of the ways Java gets around that is to create anonymous classes.
088: * They are particularly troublesome because many Debuggers do not know what to do
089: * with them. Anonymous classes tend to duplicate alot of code as well. We can
090: * use any interface with one declared method to forward events to any method that
091: * matches the signature (although the method name can be different).
092: * </p>
093: *
094: * <h3>Equality</h3>
095: * The criteria that we use to test if two delegates are equal are:
096: * <ul>
097: * <li>
098: * They both refer to the same instance. That is, the <code>instance</code>
099: * parameter passed to the newDelegate method was the same for both. The
100: * instances are compared with the identity equality operator, <code>==</code>.
101: * </li>
102: * <li>They refer to the same method as resolved by <code>Method.equals</code>.</li>
103: * </ul>
104: *
105: * @version $Id: MethodDelegate.java,v 1.25 2006/03/05 02:43:19 herbyderby Exp $
106: */
107: abstract public class MethodDelegate {
108: private static final MethodDelegateKey KEY_FACTORY = (MethodDelegateKey) KeyFactory
109: .create(MethodDelegateKey.class, KeyFactory.CLASS_BY_NAME);
110:
111: protected Object target;
112: protected String eqMethod;
113:
114: interface MethodDelegateKey {
115: Object newInstance(Class delegateClass, String methodName,
116: Class iface);
117: }
118:
119: public static MethodDelegate createStatic(Class targetClass,
120: String methodName, Class iface) {
121: Generator gen = new Generator();
122: gen.setTargetClass(targetClass);
123: gen.setMethodName(methodName);
124: gen.setInterface(iface);
125: return gen.create();
126: }
127:
128: public static MethodDelegate create(Object target,
129: String methodName, Class iface) {
130: Generator gen = new Generator();
131: gen.setTarget(target);
132: gen.setMethodName(methodName);
133: gen.setInterface(iface);
134: return gen.create();
135: }
136:
137: public boolean equals(Object obj) {
138: MethodDelegate other = (MethodDelegate) obj;
139: return target == other.target
140: && eqMethod.equals(other.eqMethod);
141: }
142:
143: public int hashCode() {
144: return target.hashCode() ^ eqMethod.hashCode();
145: }
146:
147: public Object getTarget() {
148: return target;
149: }
150:
151: abstract public MethodDelegate newInstance(Object target);
152:
153: public static class Generator extends AbstractClassGenerator {
154: private static final Source SOURCE = new Source(
155: MethodDelegate.class.getName());
156: private static final Type METHOD_DELEGATE = TypeUtils
157: .parseType("net.sf.cglib.reflect.MethodDelegate");
158: private static final Signature NEW_INSTANCE = new Signature(
159: "newInstance", METHOD_DELEGATE,
160: new Type[] { Constants.TYPE_OBJECT });
161:
162: private Object target;
163: private Class targetClass;
164: private String methodName;
165: private Class iface;
166:
167: public Generator() {
168: super (SOURCE);
169: }
170:
171: public void setTarget(Object target) {
172: this .target = target;
173: this .targetClass = target.getClass();
174: }
175:
176: public void setTargetClass(Class targetClass) {
177: this .targetClass = targetClass;
178: }
179:
180: public void setMethodName(String methodName) {
181: this .methodName = methodName;
182: }
183:
184: public void setInterface(Class iface) {
185: this .iface = iface;
186: }
187:
188: protected ClassLoader getDefaultClassLoader() {
189: return targetClass.getClassLoader();
190: }
191:
192: public MethodDelegate create() {
193: setNamePrefix(targetClass.getName());
194: Object key = KEY_FACTORY.newInstance(targetClass,
195: methodName, iface);
196: return (MethodDelegate) super .create(key);
197: }
198:
199: protected Object firstInstance(Class type) {
200: return ((MethodDelegate) ReflectUtils.newInstance(type))
201: .newInstance(target);
202: }
203:
204: protected Object nextInstance(Object instance) {
205: return ((MethodDelegate) instance).newInstance(target);
206: }
207:
208: public void generateClass(ClassVisitor v)
209: throws NoSuchMethodException {
210: Method proxy = ReflectUtils.findInterfaceMethod(iface);
211: final Method method = targetClass.getMethod(methodName,
212: proxy.getParameterTypes());
213: if (!proxy.getReturnType().isAssignableFrom(
214: method.getReturnType())) {
215: throw new IllegalArgumentException(
216: "incompatible return types");
217: }
218:
219: MethodInfo methodInfo = ReflectUtils.getMethodInfo(method);
220:
221: boolean isStatic = TypeUtils.isStatic(methodInfo
222: .getModifiers());
223: if ((target == null) ^ isStatic) {
224: throw new IllegalArgumentException("Static method "
225: + (isStatic ? "not " : "") + "expected");
226: }
227:
228: ClassEmitter ce = new ClassEmitter(v);
229: CodeEmitter e;
230: ce.begin_class(Constants.V1_2, Constants.ACC_PUBLIC,
231: getClassName(), METHOD_DELEGATE, new Type[] { Type
232: .getType(iface) }, Constants.SOURCE_FILE);
233: ce.declare_field(Constants.PRIVATE_FINAL_STATIC,
234: "eqMethod", Constants.TYPE_STRING, null);
235: EmitUtils.null_constructor(ce);
236:
237: // generate proxied method
238: MethodInfo proxied = ReflectUtils.getMethodInfo(iface
239: .getDeclaredMethods()[0]);
240: e = EmitUtils.begin_method(ce, proxied,
241: Constants.ACC_PUBLIC);
242: e.load_this ();
243: e.super _getfield("target", Constants.TYPE_OBJECT);
244: e.checkcast(methodInfo.getClassInfo().getType());
245: e.load_args();
246: e.invoke(methodInfo);
247: e.return_value();
248: e.end_method();
249:
250: // newInstance
251: e = ce.begin_method(Constants.ACC_PUBLIC, NEW_INSTANCE,
252: null);
253: e.new_instance_this ();
254: e.dup();
255: e.dup2();
256: e.invoke_constructor_this ();
257: e.getfield("eqMethod");
258: e.super _putfield("eqMethod", Constants.TYPE_STRING);
259: e.load_arg(0);
260: e.super _putfield("target", Constants.TYPE_OBJECT);
261: e.return_value();
262: e.end_method();
263:
264: // static initializer
265: e = ce.begin_static();
266: e.push(methodInfo.getSignature().toString());
267: e.putfield("eqMethod");
268: e.return_value();
269: e.end_method();
270:
271: ce.end_class();
272: }
273: }
274: }
|