com.taobao.tddl.common.util.CountPunisher.java Source code

Java tutorial

Introduction

Here is the source code for com.taobao.tddl.common.util.CountPunisher.java

Source

/*(C) 2007-2012 Alibaba Group Holding Limited.   
 *This program is free software; you can redistribute it and/or modify   
*it under the terms of the GNU General Public License version 2 as   
* published by the Free Software Foundation.   
* Authors:   
*   junyu <junyu@taobao.com> , shenxun <shenxun@taobao.com>,   
*   linxuan <linxuan@taobao.com> ,qihao <qihao@taobao.com>    
*/
package com.taobao.tddl.common.util;

import java.util.Map;
import java.util.Properties;
import java.util.concurrent.atomic.AtomicInteger;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.taobao.tddl.common.ConfigServerHelper;

/**
 * 
 * 
 * 
 * 
 * @author linxuan
 *
 */
public class CountPunisher {
    private static final Log log = LogFactory.getLog(CountPunisher.class);
    //private static final long defaultResetTime = 5 * 60 * 100; //5

    private final SmoothValve smoothValve;
    private final long timeWindow; //ms; 0
    private final long limit;
    private final long resetTime;

    private volatile long timeWindowBegin = 0; //0
    private volatile long punishBeginTime = Long.MAX_VALUE;
    private final AtomicInteger count = new AtomicInteger();

    /**
     * timeWindowlimitpunish, punishresetTime
     * @param smoothValve
     * @param timeWindow
     * @param limit
     */
    public CountPunisher(SmoothValve smoothValve, long timeWindow, long limit, long resetTime) {
        this.smoothValve = smoothValve;
        this.timeWindow = timeWindow;
        this.limit = limit;
        this.resetTime = resetTime;
    }

    public CountPunisher(SmoothValve smoothValve, long timeWindow, long limit) {
        this(smoothValve, timeWindow, limit, 5 * 60 * 100); //5
    }

    public void count() {
        if (timeWindow == 0) {
            return;
        }
        long now = System.currentTimeMillis();
        if (now - timeWindowBegin > timeWindow) {
            resetTimeWindow();
        }

        if (timeWindowBegin == 0) {
            timeWindowBegin = now;
        }

        if (count.incrementAndGet() >= limit) {
            punishBeginTime = now;
            smoothValve.setNotAvailable();
        }
    }

    private void resetTimeWindow() {
        timeWindowBegin = 0;
        count.set(0);
    }

    /**
     * @return truefalse
     */
    public boolean punish() {
        if (punishBeginTime == Long.MAX_VALUE || timeWindow == 0) {
            //
            return false;
        }
        if (System.currentTimeMillis() - punishBeginTime > resetTime) {
            //
            punishBeginTime = Long.MAX_VALUE;
            resetTimeWindow();
            smoothValve.setAvailable();
            return false;
        }
        return !smoothValve.smoothThroughOnInitial();
    }

    private static enum CreateProperties {
        timeWindow, limit, resetTime;
    }

    private static final String LINE_SEP = System.getProperty("line.separator");

    public static CountPunisher parse(SmoothValve smoothValve, String str) {
        str = str.replaceAll("@@@", LINE_SEP);
        str = str.replaceAll("###", LINE_SEP);
        str = str.replaceAll("$$$", LINE_SEP);
        str = str.replaceAll(";;;", LINE_SEP);
        Properties p = ConfigServerHelper.parseProperties(str, "[CountPunisher Properties]");
        if (p == null) {
            log.warn("Empty tddlconfig");
            return null;
        }
        try {
            long timeWindow = -1;
            long limit = -1;
            long resetTime = -1;
            for (Map.Entry<Object, Object> entry : p.entrySet()) {
                String key = ((String) entry.getKey()).trim();
                String value = ((String) entry.getValue()).trim();
                switch (CreateProperties.valueOf(key)) {
                case timeWindow:
                    timeWindow = Long.parseLong(value);
                    break;
                case limit:
                    limit = Long.parseLong(value);
                    break;
                case resetTime:
                    resetTime = Long.parseLong(value);
                    break;
                default:
                    break;
                }
            }
            if (timeWindow == -1 || limit == -1) {
                log.error("CountPunisher Properties incomplete");
                return null;
            }
            if (resetTime == -1) {
                return new CountPunisher(smoothValve, timeWindow, limit);
            } else {
                return new CountPunisher(smoothValve, timeWindow, limit, resetTime);
            }
        } catch (Exception e) {
            log.error("parse CountPunisher Properties failed", e);
            return null;
        }
    }

    @Override
    public String toString() {
        return new StringBuilder("exceed ").append(limit).append(" in ").append(timeWindow)
                .append("ms, and will reset in ").append(resetTime).append("ms").toString();
    }

    public static void main(String[] args) {
        {
            SmoothValve smoothValve = new SmoothValve(20);
            String config = "CountPunisherProperties=limit=20\\r\\ntimeWindow=3000";
            Properties p = ConfigServerHelper.parseProperties(config, "[tddlConfigListener]");
            String punisherConfig = p.getProperty("CountPunisherProperties");
            CountPunisher countPunisher = CountPunisher.parse(smoothValve, punisherConfig);
            System.out.println(countPunisher);
        }
        {
            SmoothValve smoothValve = new SmoothValve(20);
            String config = "CountPunisherProperties=limit=20@@@timeWindow=3000";
            Properties p = ConfigServerHelper.parseProperties(config, "[tddlConfigListener]");
            String punisherConfig = p.getProperty("CountPunisherProperties");
            CountPunisher countPunisher = CountPunisher.parse(smoothValve, punisherConfig);
            System.out.println(countPunisher);
        }
        {
            SmoothValve smoothValve = new SmoothValve(20);
            String config = "CountPunisherProperties=limit=20;;;timeWindow=3000";
            Properties p = ConfigServerHelper.parseProperties(config, "[tddlConfigListener]");
            String punisherConfig = p.getProperty("CountPunisherProperties");
            CountPunisher countPunisher = CountPunisher.parse(smoothValve, punisherConfig);
            System.out.println(countPunisher);
        }
    }

}