1
2package android.hardware.camera2.utils;
3
4import java.lang.reflect.*;
5
6/**
7 * This is an implementation of the 'decorator' design pattern using Java's proxy mechanism.
8 *
9 * @see android.hardware.camera2.utils.Decorator#newInstance
10 *
11 * @hide
12 */
13public class Decorator<T> implements InvocationHandler {
14
15    public interface DecoratorListener {
16        /**
17         * This method is called before the target method is invoked
18         * @param args arguments to target method
19         * @param m Method being called
20         */
21        void onBeforeInvocation(Method m, Object[] args);
22        /**
23         * This function is called after the target method is invoked
24         * if there were no uncaught exceptions
25         * @param args arguments to target method
26         * @param m Method being called
27         * @param result return value of target method
28         */
29        void onAfterInvocation(Method m, Object[] args, Object result);
30        /**
31         * This method is called only if there was an exception thrown by the target method
32         * during its invocation.
33         *
34         * @param args arguments to target method
35         * @param m Method being called
36         * @param t Throwable that was thrown
37         * @return false to rethrow exception, true if the exception was handled
38         */
39        boolean onCatchException(Method m, Object[] args, Throwable t);
40        /**
41         * This is called after the target method is invoked, regardless of whether or not
42         * there were any exceptions.
43         * @param args arguments to target method
44         * @param m Method being called
45         */
46        void onFinally(Method m, Object[] args);
47    }
48
49    private final T mObject;
50    private final DecoratorListener mListener;
51
52    /**
53     * Create a decorator wrapping the specified object's method calls.
54     *
55     * @param obj the object whose method calls you want to intercept
56     * @param listener the decorator handler for intercepted method calls
57     * @param <T> the type of the element you want to wrap. This must be an interface.
58     * @return a wrapped interface-compatible T
59     */
60    @SuppressWarnings("unchecked")
61    public static<T> T newInstance(T obj, DecoratorListener listener) {
62        return (T)java.lang.reflect.Proxy.newProxyInstance(
63                obj.getClass().getClassLoader(),
64                obj.getClass().getInterfaces(),
65                new Decorator<T>(obj, listener));
66    }
67
68    private Decorator(T obj, DecoratorListener listener) {
69        this.mObject = obj;
70        this.mListener = listener;
71    }
72
73    @Override
74    public Object invoke(Object proxy, Method m, Object[] args)
75            throws Throwable
76    {
77        Object result = null;
78        try {
79            mListener.onBeforeInvocation(m, args);
80            result = m.invoke(mObject, args);
81            mListener.onAfterInvocation(m, args, result);
82        } catch (InvocationTargetException e) {
83            Throwable t = e.getTargetException();
84            if (!mListener.onCatchException(m, args, t)) {
85                throw t;
86            }
87        } finally {
88            mListener.onFinally(m, args);
89        }
90        return result;
91    }
92}
93