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