package org.atomnuke.plugin.proxy.japi;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import org.atomnuke.plugin.InstanceContext;
import org.atomnuke.plugin.operation.ComplexOperation;
import org.atomnuke.plugin.operation.OperationFailureException;
import org.atomnuke.util.result.ResultCatchImpl;
import org.atomnuke.service.Service;
/**
*
* @author zinic
*/
public class ServiceInvocationHandler implements InvocationHandler {
private final Map<String, Method> actualMethodLookaside;
private final InstanceContext<Service> context;
public ServiceInvocationHandler(InstanceContext<Service> context) {
this.context = context;
actualMethodLookaside = new HashMap<String, Method>();
}
private synchronized Method getActualMethod(final Method searchFor) throws NoSuchMethodException {
Method cachedMethod = actualMethodLookaside.get(searchFor.getName());
if (cachedMethod == null) {
cachedMethod = context.instance().instance().getClass().getMethod(searchFor.getName(), searchFor.getParameterTypes());
}
return cachedMethod;
}
@Override
public Object invoke(Object proxy, final Method method, final Object[] args) throws NoSuchMethodException, OperationFailureException {
final ResultCatchImpl resultCatch = new ResultCatchImpl();
// TODO: Failure to find the actual method should result in a failure...
final Method actualMethod = getActualMethod(method);
context.perform(new ComplexOperation<Service, ResultCatchImpl>() {
@Override
public void perform(Service service, ResultCatchImpl argument) throws OperationFailureException {
try {
argument.setResult(actualMethod.invoke(service.instance(), args));
} catch (InvocationTargetException ex) {
throw new OperationFailureException(ex.getTargetException());
} catch (Exception ex) {
throw new OperationFailureException(ex);
}
}
}, resultCatch);
return resultCatch.result();
}
}