at.tugraz.ist.akm.webservice.requestprocessor.interceptor.HttpClientBackLog.java Source code

Java tutorial

Introduction

Here is the source code for at.tugraz.ist.akm.webservice.requestprocessor.interceptor.HttpClientBackLog.java

Source

/*
 * Copyright 2012 software2012team23
 *
 * 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 at.tugraz.ist.akm.webservice.requestprocessor.interceptor;

import java.net.InetAddress;
import java.text.DateFormat;
import java.text.DecimalFormat;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import my.org.apache.http.Header;
import my.org.apache.http.HttpInetConnection;
import my.org.apache.http.HttpRequest;
import my.org.apache.http.protocol.ExecutionContext;
import my.org.apache.http.protocol.HTTP;
import my.org.apache.http.protocol.HttpContext;
import android.annotation.SuppressLint;
import at.tugraz.ist.akm.trace.LogClient;

public class HttpClientBackLog {
    private LogClient mLog = new LogClient(HttpClientBackLog.class.getCanonicalName());
    private DateFormat mTimeFormatter = DateFormat.getTimeInstance();

    protected int mMaxClientCapacity = 64;
    protected long mExpiresAfterMs = 60 * 1000;
    protected int mGCMaxClientsAtOnce = 5;
    protected int mGCMinClientCount = mMaxClientCapacity / 3;
    protected int mOnWriteAccessGCInvocation = (int) (0.12 * mMaxClientCapacity);

    private int mWriteAccessCount = 0;

    @SuppressLint("UseSparseArrays")
    private HashMap<Integer, Long> mClientBacklog = new HashMap<Integer, Long>();

    public boolean isAuthExpired(HttpRequest httpRequest, HttpContext httpContext) {

        return isExpired(getClientHash(httpRequest, httpContext));
    }

    protected boolean isExpired(int clientHash) {
        Long clientExpirationTimestamp = mClientBacklog.get(clientHash);
        if (null == clientExpirationTimestamp) {
            return true;
        }
        return ((clientExpirationTimestamp.longValue()) < (System.currentTimeMillis()));
    }

    private int getClientHash(HttpRequest httpRequest, HttpContext httpContext) {
        HttpInetConnection connection = (HttpInetConnection) httpContext
                .getAttribute(ExecutionContext.HTTP_CONNECTION);
        InetAddress inetAddress = connection.getRemoteAddress();

        Header userAgentHeader = httpRequest.getFirstHeader(HTTP.USER_AGENT);

        if (userAgentHeader != null) {
            String agentString = userAgentHeader.getValue();
            return (inetAddress.getHostAddress() + agentString).hashCode();
        }
        return inetAddress.getHostAddress().hashCode();
    }

    public void memorizeClient(HttpRequest httpRequest, HttpContext httpContext) {
        memorize(getClientHash(httpRequest, httpContext));

    }

    public void forgetClient(HttpRequest httpRequest, HttpContext httpContext) {
        forget(getClientHash(httpRequest, httpContext));
    }

    protected boolean forget(int clientHash) {
        Long expiration = mClientBacklog.remove(clientHash);
        boolean removed = false;
        if (null != expiration) {
            mLog.debug("forgetting client [" + clientHash + "] that expires at ["
                    + mTimeFormatter.format(expiration.longValue()) + "]");
            removed = true;
        } else {
            mLog.debug("no clent [" + clientHash + "] found to forget");
        }

        return removed;
    }

    protected void memorize(int clientHash) {
        memorize(clientHash, System.currentTimeMillis() + mExpiresAfterMs);
    }

    protected void memorize(int clientHash, long timestamp) {
        long nowStamp = System.currentTimeMillis();
        String now = mTimeFormatter.format(nowStamp);
        String then = mTimeFormatter.format(timestamp);

        mWriteAccessCount++;
        if (null != mClientBacklog.put(clientHash, timestamp)) {
            mLog.debug("client [" + clientHash + "] update at [" + now + "] expires at [" + then + "] in ["
                    + (timestamp - nowStamp) + "]ms");
        } else {
            mLog.debug("new client [" + clientHash + "] memorized at [" + now + "] expires at [" + then + "] in ["
                    + (timestamp - nowStamp) + "]ms");
            if (mClientBacklog.size() > mMaxClientCapacity) {
                mLog.debug("warning, container size [" + mClientBacklog.size() + "] bigger than designated ["
                        + mMaxClientCapacity + "]");
            }
        }

        if (mWriteAccessCount >= mOnWriteAccessGCInvocation) {
            gc();
            mWriteAccessCount = 0;
        }
    }

    protected int gc() {
        String reason = null;
        boolean writeAccessReason = false, softLimitReason = false, maxCapacityReason = false;
        DecimalFormat decimalFormatter = new DecimalFormat("#.##");

        if (mClientBacklog.size() < mMaxClientCapacity) {
            reason = "GC_SOFT_LIMIT";
            softLimitReason = true;
        }
        if (mClientBacklog.size() < mGCMinClientCount) {
            reason = "GC_WRITE_ACCESS";
            softLimitReason = false;
            writeAccessReason = true;
        } else {
            reason = "GC_MAX_CAPACITY";
            maxCapacityReason = true;
        }

        double usage = (100.0 * mClientBacklog.size()) / (1.0 * mMaxClientCapacity);

        mLog.debug(reason + ": backlog usage " + decimalFormatter.format(usage) + "% [" + mClientBacklog.size()
                + "] of [" + mMaxClientCapacity + "] soft limit [" + mGCMinClientCount + "] expiration MS ["
                + mExpiresAfterMs + "] invocation every [" + mOnWriteAccessGCInvocation + "] write access");

        int freed = 0;
        if (writeAccessReason) {
            return 0;
        } else if (softLimitReason) {
            freed = tryFreeAtLeast(mGCMaxClientsAtOnce);
        } else if (maxCapacityReason) {
            freed = sweepMap();
            if (0 == freed) {
                mLog.debug("failed to free memory; container grows...");
            }
        } else {
            mLog.error("serious error freeing client backlog");
            freed = 0;
        }

        usage = (100.0 * mClientBacklog.size()) / (1.0 * mMaxClientCapacity);

        mLog.debug(reason + ": freed [" + freed + "] usage " + decimalFormatter.format(usage) + "% ["
                + mClientBacklog.size() + "] of [" + mMaxClientCapacity + "] soft limit [" + mGCMinClientCount
                + "]");

        return freed;
    }

    private int tryFreeAtLeast(int targetCount) {
        int freed = 0;
        Iterator<Map.Entry<Integer, Long>> iter = mClientBacklog.entrySet().iterator();

        while (iter.hasNext()) {
            Map.Entry<Integer, Long> entry = iter.next();
            if (entry.getValue() < System.currentTimeMillis()) {
                iter.remove();
                freed++;
                if (freed >= targetCount) {
                    break;
                }
            }
        }
        return freed;
    }

    private int sweepMap() {
        int freed = 0;
        Iterator<Map.Entry<Integer, Long>> iter = mClientBacklog.entrySet().iterator();

        while (iter.hasNext()) {
            Map.Entry<Integer, Long> entry = iter.next();
            if (entry.getValue() < System.currentTimeMillis()) {
                iter.remove();
                freed++;
            }
        }
        return freed;
    }

    public int size() {
        return mClientBacklog.size();
    }

}