package android.hardware.camera2.utils;
import java.lang.reflect.*;
/**
* This is an implementation of the 'decorator' design pattern using Java's proxy mechanism.
*
* @see android.hardware.camera2.utils.Decorator#newInstance
*
* @hide
*/
public class Decorator<T> implements InvocationHandler {
public interface DecoratorListener {
/**
* This method is called before the target method is invoked
* @param args arguments to target method
* @param m Method being called
*/
void onBeforeInvocation(Method m, Object[] args);
/**
* This function is called after the target method is invoked
* if there were no uncaught exceptions
* @param args arguments to target method
* @param m Method being called
* @param result return value of target method
*/
void onAfterInvocation(Method m, Object[] args, Object result);
/**
* This method is called only if there was an exception thrown by the target method
* during its invocation.
*
* @param args arguments to target method
* @param m Method being called
* @param t Throwable that was thrown
* @return false to rethrow exception, true if the exception was handled
*/
boolean onCatchException(Method m, Object[] args, Throwable t);
/**
* This is called after the target method is invoked, regardless of whether or not
* there were any exceptions.
* @param args arguments to target method
* @param m Method being called
*/
void onFinally(Method m, Object[] args);
}
private final T mObject;
private final DecoratorListener mListener;
/**
* Create a decorator wrapping the specified object's method calls.
*
* @param obj the object whose method calls you want to intercept
* @param listener the decorator handler for intercepted method calls
* @param <T> the type of the element you want to wrap. This must be an interface.
* @return a wrapped interface-compatible T
*/
@SuppressWarnings("unchecked")
public static<T> T newInstance(T obj, DecoratorListener listener) {
return (T)java.lang.reflect.Proxy.newProxyInstance(
obj.getClass().getClassLoader(),
obj.getClass().getInterfaces(),
new Decorator<T>(obj, listener));
}
private Decorator(T obj, DecoratorListener listener) {
this.mObject = obj;
this.mListener = listener;
}
@Override
public Object invoke(Object proxy, Method m, Object[] args)
throws Throwable
{
Object result = null;
try {
mListener.onBeforeInvocation(m, args);
result = m.invoke(mObject, args);
mListener.onAfterInvocation(m, args, result);
} catch (InvocationTargetException e) {
Throwable t = e.getTargetException();
if (!mListener.onCatchException(m, args, t)) {
throw t;
}
} finally {
mListener.onFinally(m, args);
}
return result;
}
}