package com.google.code.joto.eventrecorder.spy.calls;
import java.lang.reflect.Method;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.framework.ReflectiveMethodInvocation;
import com.google.code.joto.eventrecorder.RecordEventSummary;
import com.google.code.joto.eventrecorder.writer.RecordEventWriter;
import com.google.code.joto.eventrecorder.writer.RecordEventWriterCallback.CorrelatedEventSetterCallback;
/**
* AOP-Alliance support class for recording events to EventStore
*
* pseudo code:
* <pre>
* {@code
* @Override // implements org.aopalliance.intercept.MethodInterceptor
* public Object invoke(MethodInvocation methInvocation) throws Throwable {
*
* // record beginning of method:
* RecordEventSummary requestEvent = new RecordEventSummary(...);
* EventMethodRequestData requestData = new EventMethodRequestData(methodObject, methodArguments);
* eventWriter.addEvent(evt, reqObjData, ...);
* int requestEventId = ... // pseudo-code: retreived eventId (with async callbacks)
*
* // the method..
* // *** do call ***
* Object res = method.invoke(target, args);
*
* // record end of method
* RecordEventSummary responseEvent = new RecordEventSummary(...);
* responseEvent.setCorrelatedEventId(requestEventId); // pseudo-code ... (with in async callback)
* EventMethodResponseData responseData = new EventMethodResponseData(methodResult, methodException)
* eventWriter.addEvent(responseEvent, responseData, ...);
*
* return res;
* }
* }</pre>
*
*/
public class MethodEventWriterAopInterceptor implements MethodInterceptor {
private RecordEventWriter eventWriter;
private String eventType;
private String requestEventSubType;
private String responseEventSubType;
private ObjectReplacementMap objectReplacementMap;
//-------------------------------------------------------------------------
public MethodEventWriterAopInterceptor(
RecordEventWriter eventWriter,
String eventType) {
this(eventWriter, eventType,
MethodCallEventUtils.REQUEST_EVENT_SUBTYPE, MethodCallEventUtils.RESPONSE_EVENT_SUBTYPE);
}
public MethodEventWriterAopInterceptor(
RecordEventWriter eventWriter,
String eventType,
String requestEventSubType,
String responseEventSubType
) {
this.eventWriter = eventWriter;
this.eventType = eventType;
this.requestEventSubType = requestEventSubType;
this.responseEventSubType = responseEventSubType;
}
//-------------------------------------------------------------------------
public ObjectReplacementMap getObjectReplacementMap() {
return objectReplacementMap;
}
public void setObjectReplacementMap(ObjectReplacementMap p) {
this.objectReplacementMap = p;
}
@Override
public Object invoke(MethodInvocation methInvocation) throws Throwable {
Object target = methInvocation.getThis();
Object proxy = target;
if (methInvocation instanceof ReflectiveMethodInvocation) {
ReflectiveMethodInvocation r = (ReflectiveMethodInvocation) methInvocation;
proxy = r.getProxy();
}
String className = MethodCallEventUtils.extractEventClassName(target.getClass());
Method method = methInvocation.getMethod();
String methodName = method.getName();
Object[] args = methInvocation.getArguments();
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 replProxy = proxy;
Object[] replArgs = args; // TODO not required to replace args in current version?
if (objectReplacementMap != null) {
replProxy = objectReplacementMap.checkReplace(replProxy);
replArgs = objectReplacementMap.checkReplaceArray(replArgs);
}
EventMethodRequestData reqObjData = new EventMethodRequestData(replProxy, method, replArgs);
RecordEventSummary responseEvt = MethodCallEventUtils.createEvent(eventType, responseEventSubType, className, methodName);
CorrelatedEventSetterCallback callbackForEventId =
new CorrelatedEventSetterCallback(responseEvt);
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(responseEvt, respObjData, null);
return res;
} catch(Exception ex) {
EventMethodResponseData respObjData = new EventMethodResponseData(null, ex);
eventWriter.addEvent(responseEvt, respObjData, null);
throw ex; // rethow!
}
}
}
}