/*
* Copyright 2015 the original author or authors.
* @https://github.com/scouter-project/scouter
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package scouter.xtra.http;
import scouter.agent.error.ASYNC_SERVLET_TIMEOUT;
import scouter.agent.proxy.IHttpTrace;
import scouter.agent.trace.TraceContext;
import scouter.agent.trace.TraceContextManager;
import scouter.agent.trace.TraceMain;
import scouter.agent.trace.TransferMap;
import javax.servlet.AsyncContext;
import javax.servlet.AsyncEvent;
import javax.servlet.AsyncListener;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import static scouter.agent.AgentCommonConstant.REQUEST_ATTRIBUTE_ALL_DISPATCHED_TRACE_CONTEXT;
import static scouter.agent.AgentCommonConstant.REQUEST_ATTRIBUTE_ASYNC_DISPATCH;
import static scouter.agent.AgentCommonConstant.REQUEST_ATTRIBUTE_CALLER_TRANSFER_MAP;
import static scouter.agent.AgentCommonConstant.REQUEST_ATTRIBUTE_INITIAL_TRACE_CONTEXT;
import static scouter.agent.AgentCommonConstant.REQUEST_ATTRIBUTE_SELF_DISPATCHED;
import static scouter.agent.AgentCommonConstant.REQUEST_ATTRIBUTE_TRACE_CONTEXT;
public class HttpTrace3 extends HttpTrace implements IHttpTrace {
public void addAsyncContextListener(Object ac) {
TraceContext traceContext = TraceContextManager.getContext();
if(traceContext == null) return;
AsyncContext actx = (AsyncContext)ac;
if(actx.getRequest().getAttribute(REQUEST_ATTRIBUTE_ASYNC_DISPATCH) == null) {
actx.getRequest().setAttribute(REQUEST_ATTRIBUTE_INITIAL_TRACE_CONTEXT, traceContext);
actx.getRequest().setAttribute(REQUEST_ATTRIBUTE_TRACE_CONTEXT, traceContext);
actx.getRequest().setAttribute(REQUEST_ATTRIBUTE_ASYNC_DISPATCH, 1);
} else {
int dispatchCount = (Integer) actx.getRequest().getAttribute(REQUEST_ATTRIBUTE_ASYNC_DISPATCH);
actx.getRequest().setAttribute(REQUEST_ATTRIBUTE_TRACE_CONTEXT, traceContext);
actx.getRequest().setAttribute(REQUEST_ATTRIBUTE_ASYNC_DISPATCH, ++dispatchCount);
}
List<TraceContext> dispatchedContexts = (List<TraceContext>)actx.getRequest().getAttribute(REQUEST_ATTRIBUTE_ALL_DISPATCHED_TRACE_CONTEXT);
if(dispatchedContexts == null) {
dispatchedContexts = new ArrayList<TraceContext>();
actx.getRequest().setAttribute(REQUEST_ATTRIBUTE_ALL_DISPATCHED_TRACE_CONTEXT, dispatchedContexts);
}
if(!dispatchedContexts.contains(traceContext)) {
dispatchedContexts.add(traceContext);
}
actx.addListener(new AsyncListener() {
@Override
public void onComplete(AsyncEvent asyncEvent) throws IOException {
// System.out.println("[scouter][asynccontext]onComplete:count: " + asyncEvent.getSuppliedRequest().getAttribute(REQUEST_ATTRIBUTE_ASYNC_DISPATCH) + " => " + this.toString());
// System.out.println("[scouter][asynccontext]onComplete:thread: " + Thread.currentThread().getName());
List<TraceContext> traceContextList = (List<TraceContext>) asyncEvent.getSuppliedRequest().getAttribute(REQUEST_ATTRIBUTE_ALL_DISPATCHED_TRACE_CONTEXT);
Iterator<TraceContext> iter = traceContextList.iterator();
while(iter.hasNext()) {
TraceContext ctx = iter.next();
TraceMain.endHttpServiceFinal(ctx, asyncEvent.getSuppliedRequest(), asyncEvent.getSuppliedResponse(), ctx.asyncThrowable);
TraceContextManager.completeDeferred(ctx);
}
}
@Override
public void onTimeout(AsyncEvent asyncEvent) throws IOException {
// System.out.println("[scouter][asynccontext]onTimeout:count:" + asyncEvent.getSuppliedRequest().getAttribute(REQUEST_ATTRIBUTE_ASYNC_DISPATCH) + " => " + this.toString());
// System.out.println("[scouter][asynccontext]onTimeout:thread: " + Thread.currentThread().getName());
List<TraceContext> traceContextList = (List<TraceContext>) asyncEvent.getSuppliedRequest().getAttribute(REQUEST_ATTRIBUTE_ALL_DISPATCHED_TRACE_CONTEXT);
Iterator<TraceContext> iter = traceContextList.iterator();
while(iter.hasNext()) {
TraceContext ctx = iter.next();
ctx.asyncThrowable = new ASYNC_SERVLET_TIMEOUT("exceed async servlet timeout! : " + asyncEvent.getAsyncContext().getTimeout() + "ms");
}
}
@Override
public void onError(AsyncEvent asyncEvent) throws IOException {
// System.out.println("[scouter][asynccontext]onError:count:" + asyncEvent.getSuppliedRequest().getAttribute(REQUEST_ATTRIBUTE_ASYNC_DISPATCH) + " => " + this.toString());
// System.out.println("[scouter][asynccontext]onError:thread: " + Thread.currentThread().getName());
List<TraceContext> traceContextList = (List<TraceContext>) asyncEvent.getSuppliedRequest().getAttribute(REQUEST_ATTRIBUTE_ALL_DISPATCHED_TRACE_CONTEXT);
Iterator<TraceContext> iter = traceContextList.iterator();
while(iter.hasNext()) {
TraceContext ctx = iter.next();
ctx.asyncThrowable = asyncEvent.getThrowable();
}
}
@Override
public void onStartAsync(AsyncEvent asyncEvent) throws IOException {
// System.out.println("[scouter][asynccontext]onStartAsync:count:" + asyncEvent.getSuppliedRequest().getAttribute(REQUEST_ATTRIBUTE_ASYNC_DISPATCH) + " => " + this.toString());
// System.out.println("[scouter][asynccontext]onStartAsync:thread: " + Thread.currentThread().getName());
}
});
}
public TraceContext getTraceContextFromAsyncContext(Object oAsyncContext) {
AsyncContext asyncContext = (AsyncContext) oAsyncContext;
TraceContext currentTraceContext = (TraceContext)asyncContext.getRequest().getAttribute(REQUEST_ATTRIBUTE_TRACE_CONTEXT);
return currentTraceContext;
}
public void setDispatchTransferMap(Object oAsyncContext, long gxid, long caller, long callee, byte xType) {
AsyncContext asyncContext = (AsyncContext) oAsyncContext;
asyncContext.getRequest().setAttribute(REQUEST_ATTRIBUTE_CALLER_TRANSFER_MAP, new TransferMap.ID(gxid, caller, callee, xType));
}
public void setSelfDispatch(Object oAsyncContext, boolean self) {
AsyncContext asyncContext = (AsyncContext) oAsyncContext;
asyncContext.getRequest().setAttribute(REQUEST_ATTRIBUTE_SELF_DISPATCHED, self);
}
public boolean isSelfDispatch(Object oAsyncContext) {
AsyncContext asyncContext = (AsyncContext) oAsyncContext;
return Boolean.TRUE.equals(asyncContext.getRequest().getAttribute(REQUEST_ATTRIBUTE_SELF_DISPATCHED));
}
}