package com.google.code.joto.eventrecorder.spy.calls;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import com.google.code.joto.eventrecorder.RecordEventSummary;
import com.google.code.joto.eventrecorder.writer.RecordEventWriter;
import com.google.code.joto.eventrecorder.writer.RecordEventWriterCallback.CorrelatedEventSetterCallback;
/**
* default implementation of java Proxy reflection,
* for generating record events as request/response
*/
public class MethodEventWriterInvocationHandler implements InvocationHandler {
private Object target;
private RecordEventWriter eventWriter;
private String eventType;
private String requestEventSubType;
private String responseEventSubType;
private ObjectReplacementMap objectReplacementMap;
//-------------------------------------------------------------------------
public MethodEventWriterInvocationHandler(Object target,
RecordEventWriter eventWriter,
String eventType,
String requestEventSubType,
String responseEventSubType,
ObjectReplacementMap objectReplacementMap
) {
this.target = target;
this.eventWriter = eventWriter;
this.eventType = eventType;
this.requestEventSubType = requestEventSubType;
this.responseEventSubType = responseEventSubType;
this.objectReplacementMap = objectReplacementMap;
}
//-------------------------------------------------------------------------
public ObjectReplacementMap getObjectReplacementMap() {
return objectReplacementMap;
}
public void setObjectReplacementMap(ObjectReplacementMap p) {
this.objectReplacementMap = p;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Class<?> clss = method.getDeclaringClass();
String className = MethodCallEventUtils.extractEventClassName(clss);
final String methodName = method.getName();
// Handle the methods from java.lang.Object
if (method.getDeclaringClass() == Object.class) {
if (args == null && methodName.equals("toString")) {
return "EventDataSourceProxy[" + target + "]";
} else if (args == null && methodName.equals("hashCode")) {
return target.hashCode() + 123;
} else if (args.length == 1
&& method.getParameterTypes()[0] == Object.class
&& methodName.equals("equals")) {
return proxy == args[0];
}
}
// generate event for method request
boolean enable = eventWriter.isEnable();
if (!enable) {
// *** do call (case 1/3, no event) ***
Object res = method.invoke(target, args);
return res;
} else {
RecordEventSummary evt = MethodCallEventUtils.createEvent(eventType, requestEventSubType,
className, methodName);
if (!eventWriter.isEnable(evt)) {
// *** do call (case 2/3, no event) ***
Object res = method.invoke(target, args);
return res;
}
Object replTarget = target;
Object[] replArgs = args; // TODO not required to replace arg sin current version?
if (objectReplacementMap != null) {
replTarget = objectReplacementMap.checkReplace(replTarget);
replArgs = objectReplacementMap.checkReplaceArray(replArgs);
}
EventMethodRequestData reqObjData = new EventMethodRequestData(replTarget, method, replArgs);
RecordEventSummary respEvt = MethodCallEventUtils.createEvent(eventType, responseEventSubType,
className, methodName);
CorrelatedEventSetterCallback callbackForEventId =
new CorrelatedEventSetterCallback(respEvt);
eventWriter.addEvent(evt, reqObjData, callbackForEventId);
try {
// *** do call (case 3/3, with events) ***
Object res = method.invoke(target, args);
Object replRes = res;
if (objectReplacementMap != null) {
replRes = objectReplacementMap.checkReplace(res);
}
EventMethodResponseData respObjData = new EventMethodResponseData(replRes, null);
eventWriter.addEvent(respEvt, respObjData, null);
return res;
} catch(Exception ex) {
EventMethodResponseData respObjData = new EventMethodResponseData(null, ex);
eventWriter.addEvent(respEvt, respObjData, null);
throw ex; // rethow!
}
}
}
}