FileDocCategorySizeDatePackage
AgentImpl.javaAPI DocGlassfish v2 API34043Fri May 04 22:24:18 BST 2007package com.sun.enterprise.admin.monitor.callflow

AgentImpl

public class AgentImpl extends Object implements Agent
This class implements a call flow agent, which collects call flow data and sends it to data store, for later querying and analysis. It is possible to filter the requests for which call flow data is gathered, based on caller host IP address, and caller id (user name).
author
Ram Jeyaraman, Harpreet Singh, Nazrul Islam, Siraj Ghaffar
date
March 21, 2005

Fields Summary
private static final Logger
logger
Static definitions.
private static final ThreadLocal
threadLocal
private static Agent
__singletonAgent
Instance variables.
private AtomicBoolean
storeData
private int
dataWriterThreadCount
private String
callerIPAddressFilter
private String
callerPrincipalFilter
private AsyncHandlerIntf
asyncHandler
private DbAccessObject
dbAccessObject
private boolean
traceOn
private List
listeners
private boolean
perfImpl
Constructors Summary
private AgentImpl()


      
    	traceOn	= TraceOnHelper.isTraceOn();
    
Methods Summary
public voidaddRequestInfo(RequestInfo requestInfo, java.lang.String value)

	try {
	    if(!getStoreData())
		return;
	    ThreadLocalState tls = threadLocal.get();
	    if (traceOn) {
		logger.log(
			Level.INFO, tls.getRequestId() + ", addRequestInfo()");
	    }
	    if (tls.getInitialized()) {
		logger.log(
			Level.FINE,
			"callflow.add_request_info_disallowed");
		return;
	    }
	    if (requestInfo == RequestInfo.CALLER_IP_ADDRESS) {
		tls.getRequestData().setCallerIPAddress(value);
	    } else if (requestInfo == RequestInfo.REMOTE_USER) {
		tls.getRequestData().setRemoteUser(value);
	    }
	} catch	(Exception e) {
	    logger.log(
		    Level.WARNING,
		    "callflow.add_request_info_operation_failed", e);
	}
    
public voidclearData()

	if (getStoreData() == false){
	    dbAccessObject.clearData();
	} else {
	    logger.log(
		    Level.WARNING,
		    "callflow.turn_off_callflow_before_clearData");
	}
    
public booleandeleteRequestIds(java.lang.String[] requestIds)

	return dbAccessObject.deleteRequestIds(requestIds);
    
public voidejbMethodEnd(CallFlowInfo info)


	try {
	    if (!getStoreData())
		return;

	    ThreadLocalState tls = threadLocal.get();

	    if (traceOn) {
		logger.log(Level.INFO, tls.getRequestId() + ", ejbMethodEnd()");
	    }

	    // Notify listeners.

	    boolean listenersPresent = false;
	    long otherStartTime	= System.nanoTime();
	    if (listeners.isEmpty() == false) {
		listenersPresent = true;
		synchronized (listeners) {
		    for	(Listener listener : listeners)	{
			listener.ejbMethodEnd(
				tls.getRequestId(), info.getException());
		    }
		}
	    }
	    long otherEndTime =	System.nanoTime();

	    // Store data.

	    if (tls.getStoreData()) {
		storeMethodEndData(
			tls.getRequestId(), info.getException(), tls.getFlowStack(),
			listenersPresent, otherStartTime, otherEndTime);
	    }

	    // Clear relevant thread local state.

	    tls.setMethodName(null);
	    tls.setApplicationName(null);
	    tls.setModuleName(null);
	    tls.setComponentName(null);
	    tls.setComponentType(null);
	    tls.setTransactionId(null);
	    tls.setSecurityId(null);

	} catch	(Exception e) {
	    logger.log(
		    Level.WARNING,
		    "callflow.ejb_method_end_operation_failed",	e);
	}
    
public voidejbMethodStart(CallFlowInfo info)


	try {
	    if (!getStoreData())
		return;

	    ThreadLocalState tls = threadLocal.get();

	    if (traceOn) {
		logger.log(
			Level.INFO, tls.getRequestId() + ", ejbMethodStart()");
	    }

	    String requestId = tls.getRequestId();
	    String methodName =	info.getMethod().toString();
	    ComponentType componentType	= info.getComponentType();
	    String applicationName = info.getApplicationName();
	    String moduleName =	info.getModuleName();
	    String componentName = info.getComponentName();
	    String transactionId = info.getTransactionId();
	    String securityId =	info.getCallerPrincipal();

	    // Notify listeners.

	    boolean listenersPresent = false;
	    long otherStartTime	= System.nanoTime();
	    if (listeners.isEmpty() == false) {
		listenersPresent = true;
		synchronized (listeners) {
		    for	(Listener listener : listeners)	{
			listener.ejbMethodStart(
				requestId, methodName, applicationName,
				moduleName, componentName, componentType,
				securityId, transactionId);
		    }
		}
	    }
	    long otherEndTime =	System.nanoTime();

	    // Store data.

	    if (tls.getStoreData()) {
		storeMethodStartData(
			tls.getRequestId(), info.getMethod().toString(),
			info.getComponentType(), info.getApplicationName(),
			info.getModuleName(), info.getComponentName(),
			Thread.currentThread().getName(), info.getTransactionId(),
			info.getCallerPrincipal(), tls.getFlowStack(),
			ContainerTypeOrApplicationType.EJB_APPLICATION,
			listenersPresent, otherStartTime, otherEndTime);
	    }

	    // Update thread local state.

	    tls.setMethodName(methodName);
	    tls.setApplicationName(applicationName);
	    tls.setModuleName(moduleName);
	    tls.setComponentName(componentName);
	    tls.setComponentType(componentType.toString());
	    tls.setTransactionId(transactionId);
	    tls.setSecurityId(securityId);

	} catch	(Exception e) {
	    logger.log(
		    Level.WARNING,
		    "callflow.ejb_method_start_operation_failed", e);
	}
    
public voidenableGrizzly(boolean enable)

	List<GrizzlyConfig> grizzlies =	GrizzlyConfig.getGrizzlyConfigInstances();
	for (GrizzlyConfig grizzly: grizzlies){
	    grizzly.setEnableCallFlow(true);
	}

    
public voidendTime()

	try {
	    if (!getStoreData())
		return;
	    ThreadLocalState tls = threadLocal.get();
	    if (traceOn) {
		logger.log(Level.INFO, tls.getRequestId() + ", endTime()");
	    }
	    if (tls.getStoreData()) {
		storeEndTimeData(tls.getRequestId(), tls.getFlowStack());
	    }
	} catch	(Exception e) {
	    logger.log(
		    Level.WARNING,
		    "callflow.end_time_operation_failed", e);
	}
    
public voidentityManagerMethodEnd()

	try {
	    if (!getStoreData())
		return;

	    ThreadLocalState tls = threadLocal.get();

	    if (traceOn) {
		logger.log(Level.INFO, tls.getRequestId() +
			", entityManagerMethodEnd()");
	    }

	    // Notify listeners.

	    boolean listenersPresent = false;
	    long otherStartTime	= System.nanoTime();
	    if (listeners.isEmpty() == false) {
		listenersPresent = true;
		synchronized (listeners) {
		    for	(Listener listener : listeners)	{
			listener.entityManagerMethodEnd(tls.getRequestId());
		    }
		}
	    }
	    long otherEndTime =	System.nanoTime();

	    // Store data.

	    if (tls.getStoreData()) {
		storeMethodEndData(
			tls.getRequestId(), null, tls.getFlowStack(),
			listenersPresent, otherStartTime, otherEndTime);
	    }
	} catch	(Exception e) {
	    logger.log(
		    Level.WARNING,
		    "callflow.ejb_method_end_operation_failed",	e);
	}


    
public voidentityManagerMethodStart(EntityManagerMethod entityManagerMethod)

	try {
	    if (!getStoreData())
		return;

	    ThreadLocalState tls = threadLocal.get();

	    if (traceOn) {
		logger.log(
			Level.INFO, tls.getRequestId() +
			", entityManagerMethodStart()");
	    }

	    // Notify listeners.

	    boolean listenersPresent = false;
	    long otherStartTime	= System.nanoTime();
	    if (listeners.isEmpty() == false) {
		listenersPresent = true;
		synchronized (listeners) {
		    for	(Listener listener : listeners)	{
			listener.entityManagerMethodStart(
				tls.getRequestId(), entityManagerMethod,
				tls.getApplicationName(),
				tls.getModuleName(), tls.getComponentName(),
				ComponentType.JPA, tls.getSecurityId());
		    }
		}
	    }
	    long otherEndTime =	System.nanoTime();

	    // Store data.
	    if (tls.getStoreData()) {
		storeMethodStartData(
			tls.getRequestId(), entityManagerMethod.toString(), ComponentType.JPA,
			tls.getApplicationName(), tls.getModuleName(),
			tls.getComponentName(),	Thread.currentThread().getName(),
			null, tls.getSecurityId(), tls.getFlowStack(),
			ContainerTypeOrApplicationType.JAVA_PERSISTENCE,
			listenersPresent, otherStartTime, otherEndTime);
	    }
	} catch	(Exception e) {
	    logger.log(
		    Level.WARNING,
		    "callflow.web_method_start_operation_failed", e);
	}


    
public voidentityManagerQueryEnd()

	try {
	    if (!getStoreData())
		return;

	    ThreadLocalState tls = threadLocal.get();

	    if (traceOn) {
		logger.log(Level.INFO, tls.getRequestId() + ", entityManagerQueryEnd()");
	    }

	    // Notify listeners.

	    boolean listenersPresent = false;
	    long otherStartTime	= System.nanoTime();
	    if (listeners.isEmpty() == false) {
		listenersPresent = true;
		synchronized (listeners) {
		    for	(Listener listener : listeners)	{
			listener.entityManagerQueryEnd(tls.getRequestId());
		    }
		}
	    }
	    long otherEndTime =	System.nanoTime();

	    // Store data.
	    if (tls.getStoreData()) {
		storeMethodEndData(
			tls.getRequestId(), null, tls.getFlowStack(),
			listenersPresent, otherStartTime, otherEndTime);
	    }
	} catch	(Exception e) {
	    logger.log(
		    Level.WARNING,
		    "callflow.ejb_method_end_operation_failed",	e);
	}
    
public voidentityManagerQueryStart(EntityManagerQueryMethod queryMethod)

	try {
	    if (!getStoreData())
		return;

	    ThreadLocalState tls = threadLocal.get();

	    if (traceOn) {
		logger.log(
			Level.INFO, tls.getRequestId() +
			", entityManagerQuerytart()");
	    }

	    // Notify listeners.

	    boolean listenersPresent = false;
	    long otherStartTime	= System.nanoTime();
	    if (listeners.isEmpty() == false) {
		listenersPresent = true;
		synchronized (listeners) {
		    for	(Listener listener : listeners)	{
			listener.entityManagerQueryStart(
				tls.getRequestId(), queryMethod, tls.getApplicationName(),
				tls.getModuleName(), tls.getComponentName(),
				ComponentType.JPA, tls.getSecurityId());
		    }
		}
	    }
	    long otherEndTime =	System.nanoTime();
	    // Store data.
	    if (tls.getStoreData()) {
		storeMethodStartData(
			tls.getRequestId(), queryMethod.toString(), ComponentType.JPA,
			tls.getApplicationName(), tls.getModuleName(),
			tls.getComponentName(),	Thread.currentThread().getName(),
			null, tls.getSecurityId(), tls.getFlowStack(),
			ContainerTypeOrApplicationType.JAVA_PERSISTENCE,
			listenersPresent, otherStartTime, otherEndTime);
	    }
	} catch	(Exception e) {
	    // XXX change the warning method
	    logger.log(
		    Level.WARNING,
		    "callflow.web_method_start_operation_failed", e);
	}

    
public java.util.ListgetCallStackForRequest(java.lang.String requestId)

	return dbAccessObject.getCallStackInformation(requestId);
    
public java.lang.StringgetCallerIPFilter()

	return this.callerIPAddressFilter;
    
public java.lang.StringgetCallerPrincipalFilter()

	return this.callerPrincipalFilter;
    
public static AgentgetInstance()

    	return __singletonAgent;
    
public java.util.MapgetPieInformation(java.lang.String requestID)

	return dbAccessObject.getPieInformation(requestID);
    
public java.util.ListgetRequestInformation()

	// flush AsyncHandlerQ's so that if asyncThread	is awake, we get
	// freshly cooked informtion
	if (asyncHandler != null)
	    this.asyncHandler.flush();
	return dbAccessObject.getRequestInformation();
    
public booleangetStoreData()

        return this.storeData.get();
    
public ThreadLocalDatagetThreadLocalData()
Data accessors.

	return (ThreadLocalData) threadLocal.get();
    
private voidinitialize()
Called only from startTime method. startTime is the first trap point that is called after all the request information such as callerIPAddress and remoteUser is supplied by the container. Upon being called, this method initializes the request thread local state. Even though this method may be called several times by various startTime invocations, only the first call for this request succeeds in initializing the thread local state. Note, the trap point call sequence has a specific order: { requestStart, addRequestInfo*, (startTime, (webMethodStart|ejbMethodStart))*, ((ejbMethodEnd|webMethodEnd), endTime)*, requestEnd } The startTime is the first trap point to be called after all the request information is supplied via addRequestInfo method.


	ThreadLocalState tls = threadLocal.get();
	if (tls.getInitialized()) {
	    return;
	}

	// Check filters.

	RequestData requestData	= tls.getRequestData();
	String callerIPAddress = requestData.getCallerIPAddress();
	String remoteUser = requestData.getRemoteUser();
	boolean	filtered = false;

	if ((this.callerIPAddressFilter	!= null) &&
		!(this.callerIPAddressFilter.equals(callerIPAddress))) {
	    filtered = true;
	}

	if ((this.callerPrincipalFilter	!= null) &&
		!(this.callerPrincipalFilter.equals(remoteUser))) {
	    filtered = true;
	}

	// Allow storing the data, iff the call	is not filtered	and
	// storeData flag is turned on.
	tls.setStoreData(!filtered && getStoreData());

	// Create asychronous data asyncHandler	iff there is atleast one thread
	// whose storeData flag	is set.
	if (!perfImpl){
	    if (!filtered && getStoreData())	{
		synchronized (asyncHandler) {
		    if (dataWriterThreadCount == 0) {
			this.asyncHandler.enable();
		    }
		    dataWriterThreadCount++;
		}
	    }
	}

	// Note, this flag has to be set before	the delayed write.
	// Otherwise, this will	result in unterminated recursion,
	// due to the startTime() method call.
	tls.setInitialized(true);

	// Notify listeners.

	boolean	listenersPresent = false;
	long otherStartTime = System.nanoTime();
	if (listeners.isEmpty()	== false) {
	    listenersPresent = true;
	    synchronized (listeners) {
		for (Listener listener : listeners) {
		    listener.requestStart(
			    tls.getRequestId(),	requestData.getRequestType(),
			    callerIPAddress, remoteUser);
		}
	    }
	}
	long otherEndTime = System.nanoTime();

	// Store data (delayed write).

	if (tls.getStoreData())	{
	    storeRequestStartData(
		    tls.getRequestId(),	requestData.getRequestStartTime(),
		    requestData.getRequestStartTimeMillis(),
		    requestData.getRequestType(), callerIPAddress, remoteUser,
		    tls.getFlowStack(),	listenersPresent, otherStartTime,
		    otherEndTime);
	}
    
public booleanisEnabled()

	return storeData.get();
    
public voidregisterListener(Listener listener)
Support for notification.

	if (listeners.contains(listener) == false) {
	    listeners.add(listener);
	}
    
public voidrequestEnd()


	try {
	    if (!getStoreData())
		return;

	    ThreadLocalState tls = threadLocal.get();

	    if (traceOn) {
		logger.log(Level.INFO, tls.getRequestId() + ", requestEnd()");
	    }

	    // Notify listeners.

	    boolean listenersPresent = false;
	    long otherStartTime	= System.nanoTime();
	    if (listeners.isEmpty() == false) {
		listenersPresent = true;
		synchronized (listeners) {
		    for	(Listener listener : listeners)	{
			listener.requestEnd(tls.getRequestId());
		    }
		}
	    }
	    long otherEndTime =	System.nanoTime();

	    // Store data.

	    if (tls.getStoreData()) {
		storeRequestEndData(
			tls.getRequestId(), tls.getFlowStack(),
			listenersPresent, otherStartTime, otherEndTime);
	    }

	    // Check if	there are any more data	writer threads.	If this	is the
	    // last one, no need for the async data asyncHandler thread.

	    if (!perfImpl){
		if (tls.getStoreData())	{
		    synchronized (asyncHandler)	{
			dataWriterThreadCount--;
			if (dataWriterThreadCount == 0)	{
			    this.asyncHandler.disable();
			}
		    }
		}
	    }

	} catch	(Exception e) {
	    logger.log(
		    Level.WARNING,
		    "callflow.request_end_operation_failed", e);
	} finally {
	    threadLocal.remove();
	}
    
public voidrequestStart(RequestType requestType)
Call flow trap points.

	try {
	    if (!getStoreData())
		return;
	    threadLocal.remove(); // sanity check
	    ThreadLocalState tls = threadLocal.get();
	    tls.getFlowStack().clear();
	    if (traceOn) {
		logger.log(Level.INFO, tls.getRequestId() + ", requestStart()");
	    }
	    // NOTE: The request start trap point
	    // data is written out during the first startTime trap point.
	    tls.getRequestData().setRequestType(requestType);
	    tls.getRequestData().setRequestStartTime(System.nanoTime());
	    tls.getRequestData().
		    setRequestStartTimeMillis(System.currentTimeMillis());
	} catch	(Exception e) {
	    logger.log(
		    Level.WARNING,
		    "callflow.request_start_operation_failed", e);
	}
    
public voidsetCallerIPFilter(java.lang.String ipAddress)

	this.callerIPAddressFilter = ipAddress;
	if ((callerIPAddressFilter != null) &&
		(callerIPAddressFilter.equals(""))) {
	    callerIPAddressFilter = null;
	}
    
public voidsetCallerPrincipalFilter(java.lang.String callerPrincipal)

	this.callerPrincipalFilter = callerPrincipal;
	if ((callerPrincipalFilter != null) &&
		(callerPrincipalFilter.equals(""))) {
	    callerPrincipalFilter = null;
	}
    
public voidsetEnable(boolean enable)
API to support AMX MBean calls.

        synchronized (this){
            if (enable) {
                asyncHandler = AsyncHandlerFactory.getInstance();
                if(perfImpl){ // perf impl
                    asyncHandler.enable();
                }
                if (getStoreData() == false){
                    boolean	result = this.dbAccessObject.enable();
                    if (result) {
                        enableGrizzly(true);
                        logger.log(Level.INFO, "callflow.enable_succeeded");
                    } else {
                        logger.log(Level.SEVERE, "callflow.enable_failed");
                        throw new RuntimeException("Callflow Enable	Failed");
                    }
                }
            } else {
                this.callerIPAddressFilter = null;
                this.callerPrincipalFilter = null;
                if (perfImpl){
                    if(asyncHandler	!= null){
                        asyncHandler.disable();
                    }
                    asyncHandler = null;
                }
                if (getStoreData() == true)	{
                    enableGrizzly(false);
                    this.dbAccessObject.disable();
                    logger.log(Level.INFO, "callflow.disable_succeeded");
                }
            }
            setStoreData(enable);
        }
   
public voidsetStoreData(boolean value)

        this.storeData.set(value);
    
public voidstartTime(ContainerTypeOrApplicationType type)

	try {
	    if (!getStoreData())
		return;
	    ThreadLocalState tls = threadLocal.get();
	    if (traceOn) {
		logger.log(Level.INFO, tls.getRequestId() + ", startTime()");
	    }
	    // Note: In	the natural callflow sequence, startTime() is the first
	    // method that is called after all the addRequestInfo() calls are
	    // complete. So, we	use the	very first startTime() operation to
	    // do the initialization, filtering, et cetera.
	    initialize(); // idempotent
	    if (tls.getStoreData()) {
		storeStartTimeData(
			tls.getRequestId(), type, tls.getFlowStack());
	    }
	} catch	(Exception e) {
	    logger.log(
		    Level.WARNING,
		    "callflow.start_time_operation_failed", e);
	}
    
private voidstoreEndTimeData(java.lang.String requestId, com.sun.enterprise.admin.monitor.callflow.AgentImpl$FlowStack flowStack)

	asyncHandler.handleEndTime(
		requestId, System.nanoTime(), flowStack.pop());
	asyncHandler.handleStartTime(
		requestId, System.nanoTime(), flowStack.peek());
    
private voidstoreMethodEndData(java.lang.String requestId, java.lang.Throwable exception, com.sun.enterprise.admin.monitor.callflow.AgentImpl$FlowStack flowStack, boolean listenersPresent, long otherStartTime, long otherEndTime)

	asyncHandler.handleEndTime(
		requestId, System.nanoTime(), flowStack.pop());
	asyncHandler.handleMethodEnd(requestId,	System.nanoTime(), exception);
	if (listenersPresent) {
	    flowStack.push(ContainerTypeOrApplicationType.OTHER);
	    asyncHandler.handleStartTime(
		    requestId, otherStartTime,
		    ContainerTypeOrApplicationType.OTHER);
	    asyncHandler.handleEndTime(
		    requestId, otherEndTime, flowStack.pop());
	}
	asyncHandler.handleStartTime(
		requestId, System.nanoTime(), flowStack.peek());
    
private voidstoreMethodStartData(java.lang.String requestId, java.lang.String methodName, ComponentType componentType, java.lang.String applicationName, java.lang.String moduleName, java.lang.String componentName, java.lang.String threadId, java.lang.String transactionId, java.lang.String securityId, com.sun.enterprise.admin.monitor.callflow.AgentImpl$FlowStack flowStack, ContainerTypeOrApplicationType appType, boolean listenersPresent, long otherStartTime, long otherEndTime)

	asyncHandler.handleEndTime(
		requestId, System.nanoTime(), flowStack.peek());
	if (listenersPresent) {
	    flowStack.push(ContainerTypeOrApplicationType.OTHER);
	    asyncHandler.handleStartTime(
		    requestId, otherStartTime,
		    ContainerTypeOrApplicationType.OTHER);
	    asyncHandler.handleEndTime(
		    requestId, otherEndTime, flowStack.pop());
	}
	asyncHandler.handleMethodStart(
		requestId, System.nanoTime(), methodName, componentType,
		applicationName, moduleName, componentName, threadId,
		transactionId, securityId);
	flowStack.push(appType);
	asyncHandler.handleStartTime(requestId,	System.nanoTime(), appType);
    
private voidstoreRequestEndData(java.lang.String requestId, com.sun.enterprise.admin.monitor.callflow.AgentImpl$FlowStack flowStack, boolean listenersPresent, long otherStartTime, long otherEndTime)

	asyncHandler.handleEndTime(
		requestId, System.nanoTime(), flowStack.pop());
	if (listenersPresent) {
	    flowStack.push(ContainerTypeOrApplicationType.OTHER);
	    asyncHandler.handleStartTime(
		    requestId, otherStartTime,
		    ContainerTypeOrApplicationType.OTHER);
	    asyncHandler.handleEndTime(
		    requestId, otherEndTime, flowStack.pop());
	}
	asyncHandler.handleRequestEnd(requestId, System.nanoTime());
    
private voidstoreRequestStartData(java.lang.String requestId, long timeStamp, long timeStampMillis, RequestType requestType, java.lang.String callerIPAddress, java.lang.String remoteUser, com.sun.enterprise.admin.monitor.callflow.AgentImpl$FlowStack flowStack, boolean listenersPresent, long otherStartTime, long otherEndTime)
Note: This method is called lazily from startTime/initialize().

	if (requestType	== RequestType.REMOTE_WEB) {
	    flowStack.push(ContainerTypeOrApplicationType.WEB_CONTAINER);
	} else if (requestType == RequestType.REMOTE_EJB) {
	    // Remote EJBs first enter via the ORB layer.
	    flowStack.push(ContainerTypeOrApplicationType.ORB_CONTAINER);
	} else { // Timer EJB or MDB
	    flowStack.push(ContainerTypeOrApplicationType.EJB_CONTAINER);
	}
	asyncHandler.handleRequestStart(
		requestId, timeStamp, timeStampMillis,
		requestType, callerIPAddress, remoteUser);
	asyncHandler.handleStartTime(requestId,	timeStamp, flowStack.peek());
	if (listenersPresent) {
	    flowStack.push(ContainerTypeOrApplicationType.OTHER);
	    asyncHandler.handleStartTime(
		    requestId, otherStartTime,
		    ContainerTypeOrApplicationType.OTHER);
	    asyncHandler.handleEndTime(
		    requestId, otherEndTime, flowStack.pop());
	}
    
private voidstoreStartTimeData(java.lang.String requestId, ContainerTypeOrApplicationType type, com.sun.enterprise.admin.monitor.callflow.AgentImpl$FlowStack flowStack)

	asyncHandler.handleEndTime(
		requestId, System.nanoTime(), flowStack.peek());
	flowStack.push(type);
	asyncHandler.handleStartTime(requestId,	System.nanoTime(), type);
    
public voidunregisterListener(Listener listener)

	listeners.remove(listener);
    
public voidwebMethodEnd(java.lang.Throwable exception)


	try {
	    if (!getStoreData())
		return;

	    ThreadLocalState tls = threadLocal.get();

	    if (traceOn) {
		logger.log(Level.INFO, tls.getRequestId() + ", webMethodEnd()");
	    }

	    // Notify listeners.

	    boolean listenersPresent = false;
	    long otherStartTime	= System.nanoTime();
	    if (listeners.isEmpty() == false) {
		listenersPresent = true;
		synchronized (listeners) {
		    for	(Listener listener : listeners)	{
			listener.webMethodEnd(tls.getRequestId(), exception);
		    }
		}
	    }
	    long otherEndTime =	System.nanoTime();

	    // Store data.

	    if (tls.getStoreData()) {
		storeMethodEndData(
			tls.getRequestId(), exception, tls.getFlowStack(),
			listenersPresent, otherStartTime, otherEndTime);
	    }

	    // Clear relevant thread local state.

	    tls.setMethodName(null);
	    tls.setApplicationName(null);
	    tls.setModuleName(null);
	    tls.setComponentName(null);
	    tls.setComponentType(null);
	    tls.setTransactionId(null);
	    tls.setSecurityId(null);

	} catch	(Exception e) {
	    logger.log(
		    Level.WARNING,
		    "callflow.web_method_end_operation_failed",	e);
	}
    
public voidwebMethodStart(java.lang.String methodName, java.lang.String applicationName, java.lang.String moduleName, java.lang.String componentName, ComponentType componentType, java.lang.String callerPrincipal)


	try {
	    if (!getStoreData())
		return;

	    ThreadLocalState tls = threadLocal.get();

	    if (traceOn) {
		logger.log(
			Level.INFO, tls.getRequestId() + ", webMethodStart()");
	    }

	    // Notify listeners.

	    boolean listenersPresent = false;
	    long otherStartTime	= System.nanoTime();
	    if (listeners.isEmpty() == false) {
		listenersPresent = true;
		synchronized (listeners) {
		    for	(Listener listener : listeners)	{
			listener.webMethodStart(
				tls.getRequestId(), methodName,	applicationName,
				moduleName, componentName, componentType,
				callerPrincipal);
		    }
		}
	    }
	    long otherEndTime =	System.nanoTime();

	    // Store data.

	    if (tls.getStoreData()) {
		storeMethodStartData(
			tls.getRequestId(), methodName,	componentType,
			applicationName, moduleName,
			componentName, Thread.currentThread().getName(),
			null, callerPrincipal, tls.getFlowStack(),
			ContainerTypeOrApplicationType.WEB_APPLICATION,
			listenersPresent, otherStartTime, otherEndTime);
	    }

	    // Update thread local state.

	    tls.setMethodName(methodName);
	    tls.setApplicationName(applicationName);
	    tls.setModuleName(moduleName);
	    tls.setComponentName(componentName);
	    tls.setComponentType(componentType.toString());
	    tls.setTransactionId(null);
	    tls.setSecurityId(callerPrincipal);

	} catch	(Exception e) {
	    logger.log(
		    Level.WARNING,
		    "callflow.web_method_start_operation_failed", e);
	}