~ubuntu-branches/ubuntu/trusty/cglib/trusty

« back to all changes in this revision

Viewing changes to src/proxy/net/sf/cglib/proxy/MethodProxy.java

  • Committer: Bazaar Package Importer
  • Author(s): Damien Raude-Morvan
  • Date: 2009-10-08 21:23:45 UTC
  • Revision ID: james.westby@ubuntu.com-20091008212345-t2zy5hv2g8o4i40k
Tags: upstream-2.2+dfsg
ImportĀ upstreamĀ versionĀ 2.2+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright 2003,2004 The Apache Software Foundation
 
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
package net.sf.cglib.proxy;
 
17
 
 
18
import java.lang.reflect.InvocationTargetException;
 
19
import java.lang.reflect.Method;
 
20
 
 
21
import net.sf.cglib.core.AbstractClassGenerator;
 
22
import net.sf.cglib.core.CodeGenerationException;
 
23
import net.sf.cglib.core.GeneratorStrategy;
 
24
import net.sf.cglib.core.NamingPolicy;
 
25
import net.sf.cglib.core.Signature;
 
26
import net.sf.cglib.reflect.FastClass;
 
27
 
 
28
/**
 
29
 * Classes generated by {@link Enhancer} pass this object to the
 
30
 * registered {@link MethodInterceptor} objects when an intercepted method is invoked. It can
 
31
 * be used to either invoke the original method, or call the same method on a different
 
32
 * object of the same type.
 
33
 * @version $Id: MethodProxy.java,v 1.14 2008/05/26 04:05:50 herbyderby Exp $
 
34
 */
 
35
public class MethodProxy {
 
36
    private Signature sig1;
 
37
    private Signature sig2;
 
38
    private CreateInfo createInfo;
 
39
    
 
40
    private final Object initLock = new Object();
 
41
    private volatile FastClassInfo fastClassInfo;
 
42
    
 
43
    /**
 
44
     * For internal use by {@link Enhancer} only; see the {@link net.sf.cglib.reflect.FastMethod} class
 
45
     * for similar functionality.
 
46
     */
 
47
    public static MethodProxy create(Class c1, Class c2, String desc, String name1, String name2) {
 
48
        MethodProxy proxy = new MethodProxy();
 
49
        proxy.sig1 = new Signature(name1, desc);
 
50
        proxy.sig2 = new Signature(name2, desc);
 
51
        proxy.createInfo = new CreateInfo(c1, c2);
 
52
        return proxy;
 
53
    }
 
54
 
 
55
    private void init()
 
56
    {
 
57
        /* 
 
58
         * Using a volatile invariant allows us to initialize the FastClass and
 
59
         * method index pairs atomically.
 
60
         * 
 
61
         * Double-checked locking is safe with volatile in Java 5.  Before 1.5 this 
 
62
         * code could allow fastClassInfo to be instantiated more than once, which
 
63
         * appears to be benign.
 
64
         */
 
65
        if (fastClassInfo == null)
 
66
        {
 
67
            synchronized (initLock)
 
68
            {
 
69
                if (fastClassInfo == null)
 
70
                {
 
71
                    CreateInfo ci = createInfo;
 
72
 
 
73
                    FastClassInfo fci = new FastClassInfo();
 
74
                    fci.f1 = helper(ci, ci.c1);
 
75
                    fci.f2 = helper(ci, ci.c2);
 
76
                    fci.i1 = fci.f1.getIndex(sig1);
 
77
                    fci.i2 = fci.f2.getIndex(sig2);
 
78
                    fastClassInfo = fci;
 
79
                }
 
80
            }
 
81
        }
 
82
    }
 
83
 
 
84
    private static class FastClassInfo
 
85
    {
 
86
        FastClass f1;
 
87
        FastClass f2;
 
88
        int i1;
 
89
        int i2;
 
90
    }
 
91
 
 
92
    private static class CreateInfo
 
93
    {
 
94
        Class c1;
 
95
        Class c2;
 
96
        NamingPolicy namingPolicy;
 
97
        GeneratorStrategy strategy;
 
98
        boolean attemptLoad;
 
99
        
 
100
        public CreateInfo(Class c1, Class c2)
 
101
        {
 
102
            this.c1 = c1;
 
103
            this.c2 = c2;
 
104
            AbstractClassGenerator fromEnhancer = AbstractClassGenerator.getCurrent();
 
105
            if (fromEnhancer != null) {
 
106
                namingPolicy = fromEnhancer.getNamingPolicy();
 
107
                strategy = fromEnhancer.getStrategy();
 
108
                attemptLoad = fromEnhancer.getAttemptLoad();
 
109
            }
 
110
        }
 
111
    }
 
112
 
 
113
    private static FastClass helper(CreateInfo ci, Class type) {
 
114
        FastClass.Generator g = new FastClass.Generator();
 
115
        g.setType(type);
 
116
        g.setClassLoader(ci.c2.getClassLoader());
 
117
        g.setNamingPolicy(ci.namingPolicy);
 
118
        g.setStrategy(ci.strategy);
 
119
        g.setAttemptLoad(ci.attemptLoad);
 
120
        return g.create();
 
121
    }
 
122
 
 
123
    private MethodProxy() {
 
124
    }
 
125
 
 
126
    /**
 
127
     * Return the signature of the proxied method.
 
128
     */
 
129
    public Signature getSignature() {
 
130
        return sig1;
 
131
    }
 
132
 
 
133
    /**
 
134
     * Return the name of the synthetic method created by CGLIB which is
 
135
     * used by {@link #invokeSuper} to invoke the superclass
 
136
     * (non-intercepted) method implementation. The parameter types are
 
137
     * the same as the proxied method.
 
138
     */
 
139
    public String getSuperName() {
 
140
        return sig2.getName();
 
141
    }
 
142
 
 
143
    /**
 
144
     * Return the {@link net.sf.cglib.reflect.FastClass} method index
 
145
     * for the method used by {@link #invokeSuper}. This index uniquely
 
146
     * identifies the method within the generated proxy, and therefore
 
147
     * can be useful to reference external metadata.
 
148
     * @see #getSuperName
 
149
     */
 
150
    public int getSuperIndex() {
 
151
        init();
 
152
        return fastClassInfo.i2;
 
153
    }
 
154
 
 
155
    /**
 
156
     * Return the <code>MethodProxy</code> used when intercepting the method
 
157
     * matching the given signature.
 
158
     * @param type the class generated by Enhancer
 
159
     * @param sig the signature to match
 
160
     * @return the MethodProxy instance, or null if no applicable matching method is found
 
161
     * @throws IllegalArgumentException if the Class was not created by Enhancer or does not use a MethodInterceptor
 
162
     */
 
163
    public static MethodProxy find(Class type, Signature sig) {
 
164
        try {
 
165
            Method m = type.getDeclaredMethod(MethodInterceptorGenerator.FIND_PROXY_NAME,
 
166
                                              MethodInterceptorGenerator.FIND_PROXY_TYPES);
 
167
            return (MethodProxy)m.invoke(null, new Object[]{ sig });
 
168
        } catch (NoSuchMethodException e) {
 
169
            throw new IllegalArgumentException("Class " + type + " does not use a MethodInterceptor");
 
170
        } catch (IllegalAccessException e) {
 
171
            throw new CodeGenerationException(e);
 
172
        } catch (InvocationTargetException e) {
 
173
            throw new CodeGenerationException(e);
 
174
        }
 
175
    }
 
176
 
 
177
    /**
 
178
     * Invoke the original method, on a different object of the same type.
 
179
     * @param obj the compatible object; recursion will result if you use the object passed as the first
 
180
     * argument to the MethodInterceptor (usually not what you want)
 
181
     * @param args the arguments passed to the intercepted method; you may substitute a different
 
182
     * argument array as long as the types are compatible
 
183
     * @see MethodInterceptor#intercept
 
184
     * @throws Throwable the bare exceptions thrown by the called method are passed through
 
185
     * without wrapping in an <code>InvocationTargetException</code>
 
186
     */
 
187
    public Object invoke(Object obj, Object[] args) throws Throwable {
 
188
        try {
 
189
            init();
 
190
            FastClassInfo fci = fastClassInfo;
 
191
            return fci.f1.invoke(fci.i1, obj, args);
 
192
        } catch (InvocationTargetException e) {
 
193
            throw e.getTargetException();
 
194
        } catch (IllegalArgumentException e) {
 
195
            if (fastClassInfo.i1 < 0)
 
196
                throw new IllegalArgumentException("Protected method: " + sig1);
 
197
            throw e;
 
198
        }
 
199
    }
 
200
 
 
201
    /**
 
202
     * Invoke the original (super) method on the specified object.
 
203
     * @param obj the enhanced object, must be the object passed as the first
 
204
     * argument to the MethodInterceptor
 
205
     * @param args the arguments passed to the intercepted method; you may substitute a different
 
206
     * argument array as long as the types are compatible
 
207
     * @see MethodInterceptor#intercept
 
208
     * @throws Throwable the bare exceptions thrown by the called method are passed through
 
209
     * without wrapping in an <code>InvocationTargetException</code>
 
210
     */
 
211
    public Object invokeSuper(Object obj, Object[] args) throws Throwable {
 
212
        try {
 
213
            init();
 
214
            FastClassInfo fci = fastClassInfo;
 
215
            return fci.f2.invoke(fci.i2, obj, args);
 
216
        } catch (InvocationTargetException e) {
 
217
            throw e.getTargetException();
 
218
        }
 
219
    }
 
220
}