package org.distributeme.core.interceptor.moskito; import net.anotheria.moskito.core.calltrace.CurrentlyTracedCall; import net.anotheria.moskito.core.calltrace.RunningTraceContainer; import net.anotheria.moskito.core.calltrace.TraceStep; import net.anotheria.moskito.core.calltrace.TracedCall; import org.distributeme.core.ClientSideCallContext; import org.distributeme.core.ServerSideCallContext; import org.distributeme.core.interceptor.ClientSideRequestInterceptor; import org.distributeme.core.interceptor.InterceptionContext; import org.distributeme.core.interceptor.InterceptorResponse; import org.distributeme.core.interceptor.ServerSideRequestInterceptor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * This interceptor supports moskito journeys over the network, it transmits server side call trace back to the client. * * @author lrosenberg * @version $Id: $Id */ public class MoskitoJourneyInterceptor implements ClientSideRequestInterceptor, ServerSideRequestInterceptor{ /** * Constant for the name of the context attribute that is used to transfer the step back to client. */ private static final String CONTEXT_ATTRIBUTE_STEPBACKFROMSERVER = MoskitoJourneyInterceptor.class.getName()+"Step"; /** * Constant for the attribute name that signals that journey tracking is enabled for current call. */ private static final String CONTEXT_ATTRIBUTE_TRACE_FLAG = MoskitoJourneyInterceptor.class.getName()+"TraceFlag"; /** * Constant for the name of the attribute that stores the start time locally in the interception context to calculate call execution on each side. */ private static final String ICONTEXT_ATTRIBUTE_STARTTIME = MoskitoJourneyInterceptor.class.getName()+"Start"; /** * Logger. */ private static Logger log = LoggerFactory.getLogger(MoskitoJourneyInterceptor.class); /** {@inheritDoc} */ @Override public InterceptorResponse beforeServantCall(ServerSideCallContext context, InterceptionContext iContext) { Boolean flag = (Boolean) context.getTransportableCallContext().get(CONTEXT_ATTRIBUTE_TRACE_FLAG); if (flag!=null && flag){ CurrentlyTracedCall currentTrace = new CurrentlyTracedCall("SERVER_SIDE"); RunningTraceContainer.setCurrentlyTracedCall(currentTrace); currentTrace.startStep("--- NETWORK IN ---", MoskitoJourneyInterceptorStatsProducer.SKELETON); iContext.getLocalStore().put(ICONTEXT_ATTRIBUTE_STARTTIME, System.nanoTime()); } return InterceptorResponse.CONTINUE; } /** {@inheritDoc} */ @Override public InterceptorResponse afterServantCall(ServerSideCallContext context, InterceptionContext iContext) { TracedCall aTracedCall = RunningTraceContainer.getCurrentlyTracedCall(); if (!aTracedCall.callTraced()) return InterceptorResponse.CONTINUE; try{ CurrentlyTracedCall currentTrace = (CurrentlyTracedCall)aTracedCall; try{ long endTime = (Long)iContext.getLocalStore().get(ICONTEXT_ATTRIBUTE_STARTTIME); currentTrace.getCurrentStep().setDuration(System.nanoTime()-endTime); }catch(Exception e){ log.warn("Couldn't detect duration of current call "+currentTrace.getCurrentStep() +" in "+currentTrace, e); } context.getTransportableCallContext().put(CONTEXT_ATTRIBUTE_STEPBACKFROMSERVER, currentTrace.getCurrentStep()); context.getTransportableCallContext().remove(CONTEXT_ATTRIBUTE_TRACE_FLAG); currentTrace.endStep(); }finally{ RunningTraceContainer.endTrace(); } return InterceptorResponse.CONTINUE; } /** {@inheritDoc} */ @Override public InterceptorResponse beforeServiceCall(ClientSideCallContext context, InterceptionContext iContext) { TracedCall aTracedCall = RunningTraceContainer.getCurrentlyTracedCall(); if (!aTracedCall.callTraced()){ return InterceptorResponse.CONTINUE; } CurrentlyTracedCall currentTrace = (CurrentlyTracedCall)aTracedCall; currentTrace.startStep("--- NETWORK OUT ---", MoskitoJourneyInterceptorStatsProducer.NETWORK); iContext.getLocalStore().put(ICONTEXT_ATTRIBUTE_STARTTIME, System.nanoTime()); context.getTransportableCallContext().put(CONTEXT_ATTRIBUTE_TRACE_FLAG, Boolean.TRUE); return InterceptorResponse.CONTINUE; } /** {@inheritDoc} */ @Override public InterceptorResponse afterServiceCall(ClientSideCallContext context, InterceptionContext iContext) { TracedCall aTracedCall = RunningTraceContainer.getCurrentlyTracedCall(); if (!aTracedCall.callTraced()){ return InterceptorResponse.CONTINUE; } CurrentlyTracedCall currentTrace = (CurrentlyTracedCall)aTracedCall; TraceStep fromServer = (TraceStep)context.getTransportableCallContext().get(CONTEXT_ATTRIBUTE_STEPBACKFROMSERVER); if (fromServer==null){ log.warn("Warning, unexpected null TraceStep in "+currentTrace+" came back from server."); return InterceptorResponse.CONTINUE; } currentTrace.getCurrentStep().addChild(fromServer); long endTime = System.nanoTime(); try{ long startTime = (Long)iContext.getLocalStore().get(ICONTEXT_ATTRIBUTE_STARTTIME); currentTrace.getCurrentStep().setDuration(endTime-startTime); }catch(Exception e){ log.warn("Couldn't detect duration of current call "+currentTrace.getCurrentStep() +" in "+currentTrace, e); } currentTrace.endStep(); return InterceptorResponse.CONTINUE; } //for unittesting /** * Returns name of the variable for unittest. * @return */ static String testGetCONTEXT_ATTRIBUTE_TRACE_FLAGname(){ return CONTEXT_ATTRIBUTE_TRACE_FLAG; } /** * Returns name of the variable for unittest. * @return */ static String testGetCONTEXT_ATTRIBUTE_STEPBACKFROMSERVERName(){ return CONTEXT_ATTRIBUTE_STEPBACKFROMSERVER; } }