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 */
16package org.mockito.cglib.proxy;
17
18import java.io.Serializable;
19import java.lang.reflect.Method;
20import java.util.List;
21
22import org.mockito.cglib.core.CodeGenerationException;
23
24/**
25 * This class is meant to be used as replacement for
26 * <code>java.lang.reflect.Proxy</code> under JDK 1.2. There are some known
27 * subtle differences:
28 * <ul>
29 * <li>The exceptions returned by invoking <code>getExceptionTypes</code>
30 * on the <code>Method</code> passed to the <code>invoke</code> method
31 * <b>are</b> the exact set that can be thrown without resulting in an
32 * <code>UndeclaredThrowableException</code> being thrown.
33 * <li>{@link UndeclaredThrowableException} is used instead
34 * of <code>java.lang.reflect.UndeclaredThrowableException</code>.
35 * </ul>
36 * <p>
37 * @version $Id: Proxy.java,v 1.6 2004/06/24 21:15:19 herbyderby Exp $
38 */
39public class Proxy implements Serializable {
40    protected InvocationHandler h;
41
42    private static final CallbackFilter BAD_OBJECT_METHOD_FILTER = new CallbackFilter() {
43        public int accept(Method method, List<Method> allMethods) {
44            if (method.getDeclaringClass().getName().equals("java.lang.Object")) {
45                String name = method.getName();
46                if (!(name.equals("hashCode") ||
47                      name.equals("equals") ||
48                      name.equals("toString"))) {
49                    return 1;
50                }
51            }
52            return 0;
53        }
54    };
55
56    protected Proxy(InvocationHandler h) {
57        Enhancer.registerCallbacks(getClass(), new Callback[]{ h, null });
58        this.h = h;
59    }
60
61    // private for security of isProxyClass
62    private static class ProxyImpl extends Proxy {
63        protected ProxyImpl(InvocationHandler h) {
64            super(h);
65        }
66    }
67
68    public static InvocationHandler getInvocationHandler(Object proxy) {
69        if (!(proxy instanceof ProxyImpl)) {
70            throw new IllegalArgumentException("Object is not a proxy");
71        }
72        return ((Proxy)proxy).h;
73    }
74
75    public static Class getProxyClass(ClassLoader loader, Class[] interfaces) {
76        Enhancer e = new Enhancer();
77        e.setSuperclass(ProxyImpl.class);
78        e.setInterfaces(interfaces);
79        e.setCallbackTypes(new Class[]{
80            InvocationHandler.class,
81            NoOp.class,
82        });
83        e.setCallbackFilter(BAD_OBJECT_METHOD_FILTER);
84        e.setUseFactory(false);
85        return e.createClass();
86    }
87
88    public static boolean isProxyClass(Class cl) {
89        return cl.getSuperclass().equals(ProxyImpl.class);
90    }
91
92    public static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h) {
93        try {
94            Class clazz = getProxyClass(loader, interfaces);
95            return clazz.getConstructor(new Class[]{ InvocationHandler.class }).newInstance(new Object[]{ h });
96        } catch (RuntimeException e) {
97            throw e;
98        } catch (Exception e) {
99            throw new CodeGenerationException(e);
100        }
101    }
102}
103