# LatencyCollector.java

    package org.apache.synapse.transport.nhttp.util;

    import org.apache.http.protocol.HttpContext;
    import org.apache.synapse.transport.nhttp.NhttpConstants;

    public class LatencyCollector {

        private long backendLatency = 0;
        private long latency = 0;

        private long serverDecodeLatency = 0;

        private long clientEncodeLatency = 0;

        private long clientDecodeLatency = 0;

        private long serverEncodeLatency = 0;

        private long serverWorkerQueuedTime = 0;

        private long clientWorkerQueuedTime = 0;

        private long serverWorkerLatency = 0;

        private long clientWorkerLatency = 0;

        public LatencyCollector(HttpContext context, boolean isS2S) {
            Object o1, o2, o3, o4;
            o1 = context.getAttribute(NhttpConstants.REQ_ARRIVAL_TIME);
            o2 = context.getAttribute(NhttpConstants.REQ_DEPARTURE_TIME);
            if (isS2S) {
                o3 = context.getAttribute(NhttpConstants.RES_HEADER_ARRIVAL_TIME);
                o4 = context.getAttribute(NhttpConstants.RES_TO_CLIENT_WRITE_START_TIME);
            } else {
                o3 = context.getAttribute(NhttpConstants.RES_ARRIVAL_TIME);
                o4 = context.getAttribute(NhttpConstants.RES_DEPARTURE_TIME);
            }
            if (o1 != null && o2 != null && o3 != null && o4 != null) {
                long tReqArrival = (Long) o1;
                long tReqDeparture = (Long) o2;
                long tResArrival = (Long) o3;
                long tResDeparture = (Long) o4;

                backendLatency = (tResArrival - tReqDeparture);
                latency = (tResDeparture - tReqArrival) - backendLatency;
            }
            o1 = context.getAttribute(NhttpConstants.REQ_FROM_CLIENT_READ_START_TIME);
            o2 = context.getAttribute(NhttpConstants.REQ_FROM_CLIENT_READ_END_TIME);
            long reqestFromClientReadEndTime = 0;
            if (o1 != null && o2 != null) {
                reqestFromClientReadEndTime = (Long) o2;
                serverDecodeLatency = reqestFromClientReadEndTime - (Long) o1;
            }
            o1 = context.getAttribute(NhttpConstants.REQ_TO_BACKEND_WRITE_START_TIME);
            o2 = context.getAttribute(NhttpConstants.REQ_TO_BACKEND_WRITE_END_TIME);
            if (o1 != null && o2 != null) {
                clientEncodeLatency = (Long) o2 - (Long) o1;
            }
            o1 = context.getAttribute(NhttpConstants.RES_FROM_BACKEND_READ_START_TIME);
            o2 = context.getAttribute(NhttpConstants.RES_FROM_BACKEND_READ_END_TIME);
            long responseFromBEReadEndTime = 0;
            if (o1 != null && o2 != null) {
                responseFromBEReadEndTime = (Long) o2;
                clientDecodeLatency = responseFromBEReadEndTime - (Long) o1;
            }
            o1 = context.getAttribute(NhttpConstants.RES_TO_CLIENT_WRITE_START_TIME);
            o2 = context.getAttribute(NhttpConstants.RES_TO_CLIENT_WRITE_END_TIME);
            if (o1 != null && o2 != null) {
                serverEncodeLatency = (Long) o2 - (Long) o1;
            }
            long serverWorkerStartTime = 0;
            o1 = context.getAttribute(NhttpConstants.SERVER_WORKER_START_TIME);
            o2 = context.getAttribute(NhttpConstants.SERVER_WORKER_INIT_TIME);
            if (o1 != null && o2 != null) {
                serverWorkerStartTime = (Long) o1;
                serverWorkerQueuedTime = serverWorkerStartTime - (Long) o2;
            }
            o1 = context.getAttribute(NhttpConstants.CLIENT_WORKER_START_TIME);
            o2 = context.getAttribute(NhttpConstants.CLIENT_WORKER_INIT_TIME);
            long clientWorkerStartTime = 0;
            if (o1 != null && o2 != null) {
                clientWorkerStartTime = (Long) o1;
                clientWorkerQueuedTime = clientWorkerStartTime - (Long) o2;
            }
            o1 = context.getAttribute(NhttpConstants.REQ_TO_BACKEND_WRITE_START_TIME);
            o2 = context.getAttribute(NhttpConstants.SERVER_WORKER_START_TIME);
            if (o1 != null && o2 != null) {
                serverWorkerLatency = (Long) o1 - (Long) o2;
            }
            o1 = context.getAttribute(NhttpConstants.RES_TO_CLIENT_WRITE_START_TIME);
            o2 = context.getAttribute(NhttpConstants.CLIENT_WORKER_START_TIME);
            if (o1 != null && o2 != null) {
                clientWorkerLatency = (Long) o1 - (Long) o2;
            }
            if (clientWorkerQueuedTime > 0) {
                if (responseFromBEReadEndTime > clientWorkerStartTime) {
                    if (!isS2S) {
                        backendLatency = backendLatency - clientWorkerQueuedTime;
                    }
                    clientDecodeLatency = clientDecodeLatency - clientWorkerQueuedTime;
                }
            }
            if (serverWorkerQueuedTime > 0) {
                if (reqestFromClientReadEndTime > serverWorkerStartTime) {
                    serverDecodeLatency = serverDecodeLatency - serverWorkerQueuedTime;
                }
            }
        }

        public long getBackendLatency() {
            return backendLatency;
        }

        public long getLatency() {
            return latency;
        }

        public long getServerDecodeLatency() {
            return serverDecodeLatency;
        }

        public long getServerEncodeLatency() {
            return serverEncodeLatency;
        }

        public long getClientEncodeLatency() {
            return clientEncodeLatency;
        }

        public long getClientDecodeLatency() {
            return clientDecodeLatency;
        }

        public long getServerWorkerQueuedTime() {
            return serverWorkerQueuedTime;
        }

        public long getClientWorkerQueuedTime() {
            return clientWorkerQueuedTime;
        }

        public long getServerWorkerLatency() {
            return serverWorkerLatency;
        }

        public long getClientWorkerLatency() {
            return clientWorkerLatency;
        }

        public static void clearTimestamps(HttpContext context) {
            if (context == null) {
                return;
            }
            context.removeAttribute(NhttpConstants.REQ_ARRIVAL_TIME);
            context.removeAttribute(NhttpConstants.REQ_DEPARTURE_TIME);
            context.removeAttribute(NhttpConstants.RES_HEADER_ARRIVAL_TIME);
            context.removeAttribute(NhttpConstants.RES_TO_CLIENT_WRITE_START_TIME);
            context.removeAttribute(NhttpConstants.RES_ARRIVAL_TIME);
            context.removeAttribute(NhttpConstants.RES_DEPARTURE_TIME);
            context.removeAttribute(NhttpConstants.REQ_FROM_CLIENT_READ_START_TIME);
            context.removeAttribute(NhttpConstants.REQ_FROM_CLIENT_READ_END_TIME);
            context.removeAttribute(NhttpConstants.REQ_TO_BACKEND_WRITE_START_TIME);
            context.removeAttribute(NhttpConstants.REQ_TO_BACKEND_WRITE_END_TIME);
            context.removeAttribute(NhttpConstants.RES_FROM_BACKEND_READ_START_TIME);
            context.removeAttribute(NhttpConstants.RES_FROM_BACKEND_READ_END_TIME);
            context.removeAttribute(NhttpConstants.RES_TO_CLIENT_WRITE_END_TIME);
            context.removeAttribute(NhttpConstants.SERVER_WORKER_START_TIME);
            context.removeAttribute(NhttpConstants.SERVER_WORKER_INIT_TIME);
            context.removeAttribute(NhttpConstants.CLIENT_WORKER_START_TIME);
            context.removeAttribute(NhttpConstants.CLIENT_WORKER_INIT_TIME);
        }

    }