Home | History | Annotate | Download | only in utils
      1 
      2 package android.hardware.camera2.utils;
      3 
      4 import 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  */
     13 public 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