content: package net.csdn.modules.controller;
  
  import com.google.inject.Inject;
  import net.csdn.annotation.FDesc;
  import net.csdn.annotation.MDesc;
  import net.csdn.annotation.Param;
  import net.csdn.annotation.rest.At;
  import net.csdn.annotation.rest.BasicInfo;
  import net.csdn.common.collect.Tuple3;
  import net.csdn.common.logging.CSLogger;
  import net.csdn.common.logging.Loggers;
  import net.csdn.common.settings.Settings;
  import org.joda.time.DateTime;
  
  import java.lang.annotation.Annotation;
  import java.lang.reflect.Method;
  import java.util.ArrayList;
  import java.util.HashMap;
  import java.util.List;
  import java.util.Map;
  import java.util.concurrent.ConcurrentHashMap;
  import java.util.concurrent.atomic.AtomicLong;
  
  /**
   * 4/9/14 WilliamZhu(allwefantasy@gmail.com)
   */
  
  public class API {
  
      class AvgTime {
          AtomicLong timeStart;
          AtomicLong nowTimeRange;
          AtomicLong lastTimeRange;
          AtomicLong count;
  
          AvgTime(AtomicLong timeStart, AtomicLong nowTimeRange, AtomicLong lastTimeRange, AtomicLong count) {
              this.timeStart = timeStart;
              this.nowTimeRange = nowTimeRange;
              this.lastTimeRange = lastTimeRange;
              this.count = count;
          }
      }
  
      private Settings settings;
      private CSLogger logger = Loggers.getLogger(API.class);
      /*
        在特定internal 时间内的QPS
       */
      private ConcurrentHashMap<Method, Tuple3<AtomicLong/*时间戳*/, AtomicLong/*当前interval时间内正在累积的访问数*/, AtomicLong/*上一个interval计算出的结果QPS*/>> APIQPS = new ConcurrentHashMap<Method, Tuple3<AtomicLong, AtomicLong, AtomicLong>>();
      private ConcurrentHashMap<Method, AvgTime> APIAVGTIME = new ConcurrentHashMap<Method, AvgTime>();
      /*
        每个API 从系统启动开始，各个http状态码数目
       */
      private ConcurrentHashMap<Method, ConcurrentHashMap<Integer, AtomicLong>> APISTATUS = new ConcurrentHashMap<Method, ConcurrentHashMap<Integer, AtomicLong>>();
  
  
      private Long SystemStartTime = 0l;
      private boolean forceAPICheck = false;
  
  
      private int internal = 1000;
      private int averageTimeInternal = 1000;
  
      @Inject
      public API(Settings settings) {
          this.settings = settings;
          this.internal = settings.getAsInt("application.api.qps.internal", 1000);
          this.averageTimeInternal = settings.getAsInt("application.api.qps.average-time-internal", 1000);
          this.forceAPICheck = settings.getAsBoolean("application.api.strict.check", false);
          this.SystemStartTime = System.currentTimeMillis();
      }
  
      /*
       controller初始化时需要调用该方法
       */
      public void addPath(Method api) {
          APIQPS.putIfAbsent(api, new Tuple3<AtomicLong, AtomicLong, AtomicLong>(new AtomicLong(SystemStartTime), new AtomicLong(), new AtomicLong()));
          APIAVGTIME.putIfAbsent(api, new AvgTime(new AtomicLong(SystemStartTime), new AtomicLong(), new AtomicLong(), new AtomicLong()));
          APISTATUS.putIfAbsent(api, new ConcurrentHashMap<Integer, AtomicLong>());
      }
  
      /*
        校验API是否填写各种说明
       */
      public boolean validateAPI() {
          if (forceAPICheck) {
              return true;
          }
          return true;
      }
  
  
      /*
       收集每个API的详细信息
       */
      public Map<Method, APIDesc> collectAPIInfoes() {
          Map<Method, APIDesc> APIDescs = new HashMap<Method, APIDesc>();
          for (Method method : APIQPS.keySet()) {
              At path = method.getAnnotation(At.class);
              MDesc mDesc = method.getAnnotation(MDesc.class);
              BasicInfo basicInfo = method.getAnnotation(BasicInfo.class);
  
              APIDesc apiDesc = new APIDesc();
              apiDesc.path = path.path()[0];
              apiDesc.desc = mDesc != null ? mDesc.value() : "";
              apiDesc.qps = APIQPS.get(method).v3().get();
              apiDesc.avgTime = APIAVGTIME.get(method).lastTimeRange.get();
              apiDesc.paramDesces = createParamDescs(method);
              List<ResponseStatus> responseStatuses = new ArrayList<ResponseStatus>();
              for (Map.Entry<Integer, AtomicLong> item : APISTATUS.get(method).entrySet()) {
                  ResponseStatus responseStatus = new ResponseStatus();
                  responseStatus.status = item.getKey();
                  responseStatus.count = item.getValue().get();
                  responseStatuses.add(responseStatus);
              }
              apiDesc.responseStatuses = responseStatuses;
              APIDescs.put(method, apiDesc);
          }
          return APIDescs;
      }
  
      private List<ParamDesc> createParamDescs(Method method) {
          List<ParamDesc> paramDescs = new ArrayList<ParamDesc>();
          Annotation[][] paramAnnoes = method.getParameterAnnotations();
          Class[] types = method.getParameterTypes();
          for (int i = 0; i < paramAnnoes.length; i++) {
              Annotation[] paramAnno = paramAnnoes[i];
              if (paramAnno.length == 0) continue;
              ParamDesc paramDesc = new ParamDesc();
              for (Annotation item : paramAnno) {
                  if (item instanceof FDesc) {
                      paramDesc.desc = ((FDesc) item).value();
                  }
                  if (item instanceof Param) {
                      paramDesc.name = ((Param) item).value();
                  }
              }
              paramDesc.ptype = types[i].getName();
              paramDescs.add(paramDesc);
          }
          return paramDescs;
      }
  
      public boolean enable() {
          return (settings.getAsBoolean("application.api.qps.enable", false));
      }
  
      /*
        QPS 统计
       */
      public synchronized void qpsIncrement(Method api) {
          if (!enable() || api == null) return;
          long now = System.currentTimeMillis();
          Tuple3<AtomicLong, AtomicLong, AtomicLong> info = APIQPS.get(api);
          if (now - info.v1().get() > internal) {
              info.v3().set(info.v2().get());
              info.v2().set(0);
              info.v1().set(now);
          } else {
              info.v2().incrementAndGet();
          }
  
      }
  
      public synchronized void averageTimeIncrement(Method api, long time) {
          if (!enable() || api == null) return;
          long now = System.currentTimeMillis();
          AvgTime info = APIAVGTIME.get(api);
          info.count.incrementAndGet();
          if (now - info.timeStart.get() > averageTimeInternal) {
              if (info.count.get() == 0) {
                  info.lastTimeRange.set(0);
              } else {
                  info.lastTimeRange.set(info.nowTimeRange.get() / info.count.get());
              }
              info.nowTimeRange.set(0);
              info.timeStart.set(now);
          } else {
              info.nowTimeRange.addAndGet(time);
          }
  
      }
  
      /*
        状态码统计
       */
      public synchronized void statusIncrement(Method api, int status) {
          if (!enable() || api == null) return;
          ConcurrentHashMap<Integer, AtomicLong> chm = APISTATUS.get(api);
          if (!chm.containsKey(status)) {
              chm.put(status, new AtomicLong());
          }
          chm.get(status).incrementAndGet();
      }
  
      public String systemStartTime() {
          return new DateTime(SystemStartTime).toString("yyyy-MM-dd HH-mm-ss S");
      }
  
  }
  