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.proxy;
017:
018: import java.lang.reflect.*;
019: import java.util.Arrays;
020: import java.util.List;
021: import net.sf.cglib.core.*;
022: import net.sf.cglib.reflect.*;
023:
024: /**
025: * Classes generated by {@link Enhancer} pass this object to the
026: * registered {@link MethodInterceptor} objects when an intercepted method is invoked. It can
027: * be used to either invoke the original method, or call the same method on a different
028: * object of the same type.
029: * @version $Id: MethodProxy.java,v 1.13 2006/01/11 21:47:43 herbyderby Exp $
030: */
031: public class MethodProxy {
032: private Signature sig1;
033: private Signature sig2;
034: private CreateInfo createInfo;
035: private FastClass f1;
036: private FastClass f2;
037: private int i1;
038: private int i2;
039:
040: /**
041: * For internal use by {@link Enhancer} only; see the {@link net.sf.cglib.reflect.FastMethod} class
042: * for similar functionality.
043: */
044: public static MethodProxy create(Class c1, Class c2, String desc,
045: String name1, String name2) {
046: MethodProxy proxy = new MethodProxy();
047: proxy.sig1 = new Signature(name1, desc);
048: proxy.sig2 = new Signature(name2, desc);
049: proxy.createInfo = new CreateInfo(c1, c2);
050: return proxy;
051: }
052:
053: private void init() {
054: CreateInfo ci = createInfo;
055: if (ci != null) {
056: f1 = helper(ci, ci.c1);
057: f2 = helper(ci, ci.c2);
058: i1 = f1.getIndex(sig1);
059: i2 = f2.getIndex(sig2);
060: createInfo = null;
061: }
062: }
063:
064: private static class CreateInfo {
065: Class c1;
066: Class c2;
067: NamingPolicy namingPolicy;
068: GeneratorStrategy strategy;
069: boolean attemptLoad;
070:
071: public CreateInfo(Class c1, Class c2) {
072: this .c1 = c1;
073: this .c2 = c2;
074: AbstractClassGenerator fromEnhancer = AbstractClassGenerator
075: .getCurrent();
076: if (fromEnhancer != null) {
077: namingPolicy = fromEnhancer.getNamingPolicy();
078: strategy = fromEnhancer.getStrategy();
079: attemptLoad = fromEnhancer.getAttemptLoad();
080: }
081: }
082: }
083:
084: private static FastClass helper(CreateInfo ci, Class type) {
085: FastClass.Generator g = new FastClass.Generator();
086: g.setType(type);
087: g.setClassLoader(ci.c2.getClassLoader());
088: g.setNamingPolicy(ci.namingPolicy);
089: g.setStrategy(ci.strategy);
090: g.setAttemptLoad(ci.attemptLoad);
091: return g.create();
092: }
093:
094: private MethodProxy() {
095: }
096:
097: /**
098: * Return the signature of the proxied method.
099: */
100: public Signature getSignature() {
101: return sig1;
102: }
103:
104: /**
105: * Return the name of the synthetic method created by CGLIB which is
106: * used by {@link #invokeSuper} to invoke the superclass
107: * (non-intercepted) method implementation. The parameter types are
108: * the same as the proxied method.
109: */
110: public String getSuperName() {
111: return sig2.getName();
112: }
113:
114: /**
115: * Return the {@link net.sf.cglib.reflect.FastClass} method index
116: * for the method used by {@link #invokeSuper}. This index uniquely
117: * identifies the method within the generated proxy, and therefore
118: * can be useful to reference external metadata.
119: * @see #getSuperName
120: */
121: public int getSuperIndex() {
122: init();
123: return i2;
124: }
125:
126: /**
127: * Return the <code>MethodProxy</code> used when intercepting the method
128: * matching the given signature.
129: * @param type the class generated by Enhancer
130: * @param sig the signature to match
131: * @return the MethodProxy instance, or null if no applicable matching method is found
132: * @throws IllegalArgumentException if the Class was not created by Enhancer or does not use a MethodInterceptor
133: */
134: public static MethodProxy find(Class type, Signature sig) {
135: try {
136: Method m = type.getDeclaredMethod(
137: MethodInterceptorGenerator.FIND_PROXY_NAME,
138: MethodInterceptorGenerator.FIND_PROXY_TYPES);
139: return (MethodProxy) m.invoke(null, new Object[] { sig });
140: } catch (NoSuchMethodException e) {
141: throw new IllegalArgumentException("Class " + type
142: + " does not use a MethodInterceptor");
143: } catch (IllegalAccessException e) {
144: throw new CodeGenerationException(e);
145: } catch (InvocationTargetException e) {
146: throw new CodeGenerationException(e);
147: }
148: }
149:
150: /**
151: * Invoke the original method, on a different object of the same type.
152: * @param obj the compatible object; recursion will result if you use the object passed as the first
153: * argument to the MethodInterceptor (usually not what you want)
154: * @param args the arguments passed to the intercepted method; you may substitute a different
155: * argument array as long as the types are compatible
156: * @see MethodInterceptor#intercept
157: * @throws Throwable the bare exceptions thrown by the called method are passed through
158: * without wrapping in an <code>InvocationTargetException</code>
159: */
160: public Object invoke(Object obj, Object[] args) throws Throwable {
161: try {
162: if (f1 == null)
163: init();
164: return f1.invoke(i1, obj, args);
165: } catch (InvocationTargetException e) {
166: throw e.getTargetException();
167: } catch (IllegalArgumentException e) {
168: if (i1 < 0)
169: throw new IllegalArgumentException("Protected method: "
170: + sig1);
171: throw e;
172: }
173: }
174:
175: /**
176: * Invoke the original (super) method on the specified object.
177: * @param obj the enhanced object, must be the object passed as the first
178: * argument to the MethodInterceptor
179: * @param args the arguments passed to the intercepted method; you may substitute a different
180: * argument array as long as the types are compatible
181: * @see MethodInterceptor#intercept
182: * @throws Throwable the bare exceptions thrown by the called method are passed through
183: * without wrapping in an <code>InvocationTargetException</code>
184: */
185: public Object invokeSuper(Object obj, Object[] args)
186: throws Throwable {
187: try {
188: if (f2 == null)
189: init();
190: return f2.invoke(i2, obj, args);
191: } catch (InvocationTargetException e) {
192: throw e.getTargetException();
193: }
194: }
195: }
|