# LatencyCollector.java

    /*
     * Copyright (c) 2005-2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
     *
     * WSO2 Inc. licenses this file to you 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 org.apache.synapse.transport.passthru.jmx;

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

    /**
     * Class responsible for collect Latency values per request
     */
    public class LatencyCollector {

        /**
         * Time between response header retrieve time and request written completion time
         */
        private long backendLatency = 0;

        /**
         * complete latency
         */
        private long latency = 0;

        /**
         * Time between req from client read end time and req from client read start time.
         */
        private long serverDecodeLatency = 0;

        /**
         * Time between req to BE write end time and req to BE write start time.
         */
        private long clientEncodeLatency = 0;

        /**
         * Time between res read end time from BE and res read start time form BE
         */
        private long clientDecodeLatency = 0;

        /**
         * Time between res write end from BE and res write start time
         */
        private long serverEncodeLatency = 0;

        /**
         * Time between SeverWorker initiated and run
         */
        private long serverWorkerQueuedTime = 0;

        /**
         * Time between SeverWorker initiated and run
         */
        private long clientWorkerQueuedTime = 0;

        /**
         * Time between SeverWorker run and  request to BE write start time
         */
        private long serverWorkerLatency = 0;

        /**
         * Time between ClientWorker run and response to Client write start time.
         */
        private long clientWorkerLatency = 0;

        public LatencyCollector(HttpContext context, boolean isS2S) {
            Object o1, o2, o3, o4;
            o1 = context.getAttribute(PassThroughConstants.REQ_ARRIVAL_TIME);
            o2 = context.getAttribute(PassThroughConstants.REQ_DEPARTURE_TIME);
            if (isS2S) {
                o3 = context.getAttribute(PassThroughConstants.RES_HEADER_ARRIVAL_TIME);
                o4 = context.getAttribute(PassThroughConstants.RES_TO_CLIENT_WRITE_START_TIME);
            } else {
                o3 = context.getAttribute(PassThroughConstants.RES_ARRIVAL_TIME);
                o4 = context.getAttribute(PassThroughConstants.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(PassThroughConstants.REQ_FROM_CLIENT_READ_START_TIME);
            o2 = context.getAttribute(PassThroughConstants.REQ_FROM_CLIENT_READ_END_TIME);
            if (o1 != null && o2 != null) {
                serverDecodeLatency = (Long) o2 - (Long) o1;
            }
            o1 = context.getAttribute(PassThroughConstants.REQ_TO_BACKEND_WRITE_START_TIME);
            o2 = context.getAttribute(PassThroughConstants.REQ_TO_BACKEND_WRITE_END_TIME);
            if (o1 != null && o2 != null) {
                clientEncodeLatency = (Long) o2 - (Long) o1;
            }
            o1 = context.getAttribute(PassThroughConstants.RES_FROM_BACKEND_READ_START_TIME);
            o2 = context.getAttribute(PassThroughConstants.RES_FROM_BACKEND_READ_END_TIME);
            if (o1 != null && o2 != null) {
                clientDecodeLatency = (Long) o2 - (Long) o1;
            }
            o1 = context.getAttribute(PassThroughConstants.RES_TO_CLIENT_WRITE_START_TIME);
            o2 = context.getAttribute(PassThroughConstants.RES_TO_CLIENT_WRITE_END_TIME);
            if (o1 != null && o2 != null) {
                serverEncodeLatency = (Long) o2 - (Long) o1;
            }
            o1 = context.getAttribute(PassThroughConstants.SERVER_WORKER_START_TIME);
            o2 = context.getAttribute(PassThroughConstants.SERVER_WORKER_INIT_TIME);
            if (o1 != null && o2 != null) {
                serverWorkerQueuedTime = (Long) o1 - (Long) o2;
            }
            o1 = context.getAttribute(PassThroughConstants.CLIENT_WORKER_START_TIME);
            o2 = context.getAttribute(PassThroughConstants.CLIENT_WORKER_INIT_TIME);
            if (o1 != null && o2 != null) {
                clientWorkerQueuedTime = (Long) o1 - (Long) o2;
            }
            o1 = context.getAttribute(PassThroughConstants.REQ_TO_BACKEND_WRITE_START_TIME);
            o2 = context.getAttribute(PassThroughConstants.SERVER_WORKER_START_TIME);
            if (o1 != null && o2 != null) {
                serverWorkerLatency = (Long) o1 - (Long) o2;
            }
            o1 = context.getAttribute(PassThroughConstants.RES_TO_CLIENT_WRITE_START_TIME);
            o2 = context.getAttribute(PassThroughConstants.CLIENT_WORKER_START_TIME);
            if (o1 != null && o2 != null) {
                clientWorkerLatency = (Long) o1 - (Long) o2;
            }
        }

        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;
        }

        /**
         * Clear all timestamps saved.
         * @param context HttpContext
         */
        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);
        }
    }