content: /*
   * Copyright 1999-2012 Alibaba Group.
   *  
   * 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 com.alibaba.cobar.manager.web.ajax;
  
  import static com.alibaba.cobar.manager.util.ConstantDefine.TYPE_COMMAND;
  import static com.alibaba.cobar.manager.util.ConstantDefine.TYPE_CONNECTION;
  import static com.alibaba.cobar.manager.util.ConstantDefine.TYPE_DATABASES;
  import static com.alibaba.cobar.manager.util.ConstantDefine.TYPE_DATANODES;
  import static com.alibaba.cobar.manager.util.ConstantDefine.TYPE_DATASOURCES;
  import static com.alibaba.cobar.manager.util.ConstantDefine.TYPE_PROCESSOR_STATUS;
  import static com.alibaba.cobar.manager.util.ConstantDefine.TYPE_SERVER_STATUS;
  import static com.alibaba.cobar.manager.util.ConstantDefine.TYPE_THREAD_POOL;
  
  import java.io.IOException;
  import java.io.OutputStream;
  import java.util.ArrayList;
  import java.util.HashMap;
  import java.util.List;
  import java.util.Map;
  
  import javax.servlet.ServletException;
  import javax.servlet.http.HttpServletRequest;
  import javax.servlet.http.HttpServletResponse;
  
  import net.sf.json.JSONArray;
  import net.sf.json.JSONObject;
  
  import org.apache.commons.beanutils.PropertyUtilsBean;
  import org.springframework.beans.factory.InitializingBean;
  import org.springframework.web.HttpRequestHandler;
  
  import com.alibaba.cobar.manager.dao.CobarAdapterDAO;
  import com.alibaba.cobar.manager.dataobject.cobarnode.CommandStatus;
  import com.alibaba.cobar.manager.dataobject.cobarnode.ConnectionStatus;
  import com.alibaba.cobar.manager.dataobject.cobarnode.DataNodesStatus;
  import com.alibaba.cobar.manager.dataobject.cobarnode.DataSources;
  import com.alibaba.cobar.manager.dataobject.cobarnode.ProcessorStatus;
  import com.alibaba.cobar.manager.dataobject.cobarnode.ServerStatus;
  import com.alibaba.cobar.manager.dataobject.cobarnode.ThreadPoolStatus;
  import com.alibaba.cobar.manager.service.CobarAccesser;
  import com.alibaba.cobar.manager.service.XmlAccesser;
  import com.alibaba.cobar.manager.util.FormatUtil;
  import com.alibaba.cobar.manager.util.ListSortUtil;
  import com.alibaba.cobar.manager.util.MathUtil;
  
  /**
   * (created at 2010-8-27)
   * 
   * @author <a href="mailto:shuo.qius@alibaba-inc.com">QIU Shuo</a>
   * @author haiqing.zhuhq 2011-9-1
   */
  public class CobarNodeInstantPerfValueAjax implements HttpRequestHandler, InitializingBean {
  
      private XmlAccesser xmlAccesser;
      private CobarAccesser cobarAccesser;
  
      private static final int NET_IN = 1;
      private static final int NET_OUT = 2;
      private static final int CONNECTION = 3;
      private static final int REQUEST_COUNT = 4;
  
      public void setCobarAccesser(CobarAccesser cobarAccesser) {
          this.cobarAccesser = cobarAccesser;
      }
  
      public void setXmlAccesser(XmlAccesser xmlAccesser) {
          this.xmlAccesser = xmlAccesser;
      }
  
      @Override
      public void afterPropertiesSet() throws Exception {
          if (null == xmlAccesser) {
              throw new IllegalArgumentException("property 'xmlAccesser' is null!");
          }
          if (null == cobarAccesser) {
              throw new IllegalArgumentException("property 'cobarAccesser' is null!");
          }
      }
  
      private long groupBy(List<ProcessorStatus> list, int type) {
          long result = 0;
          switch (type) {
          case NET_IN:
              for (ProcessorStatus p : list) {
                  result += p.getNetIn();
              }
              break;
          case NET_OUT:
              for (ProcessorStatus p : list) {
                  result += p.getNetOut();
              }
              break;
          case CONNECTION:
              for (ProcessorStatus p : list) {
                  result += p.getConnections();
              }
              break;
          case REQUEST_COUNT:
              for (ProcessorStatus p : list) {
                  result += p.getRequestCount();
              }
              break;
          default:
              throw new IllegalArgumentException("invalid parameter");
          }
          return result;
      }
  
      private long groupByCList(List<CommandStatus> list, int type) {
          long result = 0;
          switch (type) {
          case REQUEST_COUNT:
              for (CommandStatus p : list) {
                  result += p.getQuery();
              }
              break;
          default:
              throw new IllegalArgumentException("invalid parameter");
          }
          return result;
      }
  
      /**
       * Processor Tab
       * 
       * @param params
       * @return
       */
      private List<Map<String, Object>> listProcessorStatus(AjaxParams params) {
          long timestamp = 0;
  
          CobarAdapterDAO perfAccesser = cobarAccesser.getAccesser(params.getCobarNodeId());
          if (!perfAccesser.checkConnection()) {
              return null;
          }
  
          List<Map<String, Object>> returnList = new ArrayList<Map<String, Object>>();
  
          List<ProcessorStatus> list = perfAccesser.listProccessorStatus();
          long a[] = new long[] { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
          for (ProcessorStatus e : list) {
              a[0] += e.getNetIn();
              a[1] += e.getNetOut();
              a[2] += e.getRequestCount();
              a[3] += e.getrQueue();
              a[4] += e.getwQueue();
              a[5] += e.getFreeBuffer();
              a[6] += e.getTotalBuffer();
              a[7] += e.getConnections();
              a[8] += e.getBc_count();
              timestamp = e.getSampleTimeStamp();
  
              Map<String, Object> map = new HashMap<String, Object>();
              map.put("processorId", e.getProcessorId());
              map.put("netIn", FormatUtil.formatStore(e.getNetIn()));
              map.put("netOut", FormatUtil.formatStore(e.getNetOut()));
              map.put("requestCount", FormatUtil.formatNumber(e.getRequestCount()));
              map.put("rQueue", e.getrQueue());
              map.put("wQueue", e.getwQueue());
              map.put("freeBuffer", e.getFreeBuffer());
              map.put("totalBuffer", e.getTotalBuffer());
              map.put("connections", e.getConnections());
              map.put("bc_count", e.getBc_count());
              returnList.add(map);
          }
  
          Map<String, Object> total = new HashMap<String, Object>();
          total.put("processorId", "TOTAL");
          total.put("netIn", FormatUtil.formatStore(a[0]));
          total.put("netOut", FormatUtil.formatStore(a[1]));
          total.put("requestCount", FormatUtil.formatNumber(a[2]));
          total.put("rQueue", a[3]);
          total.put("wQueue", a[4]);
          total.put("freeBuffer", a[5]);
          total.put("totalBuffer", a[6]);
          total.put("connections", a[7]);
          total.put("bc_count", a[8]);
          total.put("sampleTimeStamp", timestamp);
          total.put("netInC", a[0]);
          total.put("netOutC", a[1]);
          total.put("requestCountC", a[2]);
          returnList.add(total);
  
          return returnList;
      }
  
      /**
       * ThreadPool Tab
       * 
       * @param params
       * @return
       */
      private List<Map<String, Object>> listThreadPool(AjaxParams params) {
          CobarAdapterDAO perfAccesser = cobarAccesser.getAccesser(params.getCobarNodeId());
          if (!perfAccesser.checkConnection()) {
              return null;
          }
  
          List<ThreadPoolStatus> pools = perfAccesser.listThreadPoolStatus();
          List<Map<String, Object>> returnList = new ArrayList<Map<String, Object>>();
          for (ThreadPoolStatus t : pools) {
              Map<String, Object> map = new HashMap<String, Object>();
  
              map.put("threadPoolName", t.getThreadPoolName());
              map.put("poolSize", t.getPoolSize());
              map.put("activeSize", t.getActiveSize());
              map.put("taskQueue", t.getTaskQueue());
              map.put("completedTask", FormatUtil.formatNumber(t.getCompletedTask()));
              map.put("totalTask", FormatUtil.formatNumber(t.getTotalTask()));
  
              returnList.add(map);
          }
  
          return returnList;
      }
  
      /**
       * Command Tab
       * 
       * @param params
       * @return
       */
      private List<Map<String, Object>> listCommand(AjaxParams params) {
          CobarAdapterDAO perfAccesser = cobarAccesser.getAccesser(params.getCobarNodeId());
          if (!perfAccesser.checkConnection()) {
              return null;
          }
          List<CommandStatus> list = perfAccesser.listCommandStatus();
          List<Map<String, Object>> returnList = new ArrayList<Map<String, Object>>();
  
          // the last element is total count
          long a[] = new long[] { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
          for (CommandStatus l : list) {
              a[0] += l.getQuery();
              a[1] += l.getStmtPrepared();
              a[2] += l.getStmtExecute();
              a[3] += l.getStmtClose();
              a[4] += l.getPing();
              a[5] += l.getQuit();
              a[6] += l.getOther();
              a[7] += l.getInitDB();
              a[8] += l.getKill();
  
              Map<String, Object> map = new HashMap<String, Object>();
              map.put("processorId", l.getProcessorId());
              map.put("stmtPrepared", FormatUtil.formatNumber(l.getStmtPrepared()));
              map.put("stmtExecute", FormatUtil.formatNumber(l.getStmtExecute()));
              map.put("query", FormatUtil.formatNumber(l.getQuery()));
              map.put("stmtClose", FormatUtil.formatNumber(l.getStmtClose()));
              map.put("ping", FormatUtil.formatNumber(l.getPing()));
              map.put("quit", FormatUtil.formatNumber(l.getQuit()));
              map.put("other", FormatUtil.formatNumber(l.getOther()));
              map.put("kill", FormatUtil.formatNumber(l.getKill()));
              map.put("initDB", FormatUtil.formatNumber(l.getInitDB()));
              returnList.add(map);
          }
  
          Map<String, Object> map = new HashMap<String, Object>();
          map.put("processorId", "Total");
          map.put("stmtPrepared", FormatUtil.formatNumber(a[1]));
          map.put("stmtExecute", FormatUtil.formatNumber(a[2]));
          map.put("query", FormatUtil.formatNumber(a[0]));
          map.put("stmtClose", FormatUtil.formatNumber(a[3]));
          map.put("ping", FormatUtil.formatNumber(a[4]));
          map.put("quit", FormatUtil.formatNumber(a[5]));
          map.put("other", FormatUtil.formatNumber(a[6]));
          map.put("kill", FormatUtil.formatNumber(a[8]));
          map.put("initDB", FormatUtil.formatNumber(a[7]));
          returnList.add(map);
  
          return returnList;
      }
  
      /**
       * Connection Tab
       * 
       * @param params
       * @return
       */
      private List<Map<String, Object>> listConnection(AjaxParams params) {
          CobarAdapterDAO perfAccesser = cobarAccesser.getAccesser(params.getCobarNodeId());
          if (!perfAccesser.checkConnection()) {
              return null;
          }
          List<ConnectionStatus> list = perfAccesser.listConnectionStatus();
          if (null != list) {
              ListSortUtil.sortConnections(list);
          }
          List<Map<String, Object>> returnList = new ArrayList<Map<String, Object>>();
          for (ConnectionStatus c : list) {
              Map<String, Object> map = new HashMap<String, Object>();
              map.put("processor", c.getProcessor());
              map.put("id", c.getId());
              map.put("host", c.getHost());
              map.put("port", c.getPort());
              map.put("local_port", c.getLocal_port());
              map.put("schema", c.getSchema());
              map.put("charset", c.getCharset());
              map.put("netIn", FormatUtil.formatStore(c.getNetIn()));
              map.put("netOut", FormatUtil.formatStore(c.getNetOut()));
              map.put("aliveTime", FormatUtil.formatTime(c.getAliveTime() * 1000, 2));
              map.put("attempsCount", FormatUtil.formatNumber(c.getAttempsCount()));
              map.put("recvBuffer", FormatUtil.formatStore(c.getRecvBuffer()));
              map.put("sendQueue", c.getSendQueue());
              map.put("channel", c.getChannel());
              returnList.add(map);
          }
          return returnList;
      }
  
      @SuppressWarnings({ "unchecked" })
      private List<Map<String, Object>> listDatanode(AjaxParams params) {
          CobarAdapterDAO perfAccesser = cobarAccesser.getAccesser(params.getCobarNodeId());
          if (!perfAccesser.checkConnection()) {
              return null;
          }
          PropertyUtilsBean util = new PropertyUtilsBean();
          List<DataNodesStatus> list = perfAccesser.listDataNodes();;
          if (null != list) {
              ListSortUtil.sortDataNodesByPoolName(list);
          }
          List<Map<String, Object>> returnList = new ArrayList<Map<String, Object>>();
          for (DataNodesStatus c : list) {
              Map<String, Object> map = null;
              try {
                  map = util.describe(c);
              } catch (Exception e1) {
                  throw new RuntimeException(e1);
              }
              map.remove("class");
              map.remove("executeCount");
              map.put("executeCount", FormatUtil.formatNumber(c.getExecuteCount()));
              map.remove("recoveryTime");
              if (-1 != c.getRecoveryTime()) {
                  map.put("recoveryTime", FormatUtil.formatTime(c.getRecoveryTime() * 1000, 2));
              } else {
                  map.put("recoveryTime", c.getRecoveryTime());
              }
              returnList.add(map);
          }
          return returnList;
      }
  
      private Map<String, Object> getServerStatus(AjaxParams params) {
          JSONArray array = params.getArray();
  
          JSONObject jobject = array.getJSONObject(0);
  
          CobarAdapterDAO perfAccesser = cobarAccesser.getAccesser(params.getCobarNodeId());
          if (!perfAccesser.checkConnection()) {
              Map<String, Object> map = new HashMap<String, Object>();
              map.put("uptime", 0);
              map.put("usedMemory", 0);
              map.put("maxMemory", 0);
              map.put("totalMemory", 0);
              map.put("connectionCount", 0);
              map.put("status", "ERROR");
              map.put("version", "UNKNOWN");
              map.put("starttime", 0);
  
              map.put("netInC", 0);
              map.put("netOutC", 0);
              map.put("requestCountC", 0);
              map.put("sampleTimeStamp", System.currentTimeMillis());
              map.put("netIn_deriv", 0);
              map.put("netOut_deriv", 0);
              map.put("reCount_deriv", 0);
  
              return map;
          }
          ServerStatus ss = perfAccesser.getServerStatus();
          Map<String, Object> map = new HashMap<String, Object>();
          map.put("uptime", ss.getUptime());
          map.put("usedMemory", FormatUtil.formatStore(ss.getUsedMemory()));
          map.put("maxMemory", FormatUtil.formatStore(ss.getMaxMemory()));
          map.put("totalMemory", FormatUtil.formatStore(ss.getTotalMemory()));
  
          List<ProcessorStatus> list = perfAccesser.listProccessorStatus();
          List<CommandStatus> cmdList = perfAccesser.listCommandStatus();
  
          long netIn = groupBy(list, NET_IN);
          long netOut = groupBy(list, NET_OUT);
          long requestCount = groupByCList(cmdList, REQUEST_COUNT);
          long connectionCount = groupBy(list, CONNECTION);
          long timestamp = list.get(list.size() - 1).getSampleTimeStamp();
  
          long o_netIn = jobject.getLong("netIn");
          long o_netOut = jobject.getLong("netOut");
          long o_requestCount = jobject.getLong("requestCount");
          long o_timestamp = jobject.getLong("sampleTimeStamp");
  
          map.put("netInC", netIn);
          map.put("netOutC", netOut);
          map.put("requestCountC", requestCount);
          map.put("sampleTimeStamp", timestamp);
  
          map.put("netIn_deriv",
                  FormatUtil.formatNetwork((long) MathUtil.getDerivate(netIn, o_netIn, timestamp, o_timestamp, 1000.0)));
          map.put("netOut_deriv",
                  FormatUtil.formatNetwork((long) MathUtil.getDerivate(netOut, o_netOut, timestamp, o_timestamp, 1000.0)));
          map.put("reCount_deriv", FormatUtil.formatNumber((long) MathUtil.getDerivate(requestCount,
                                                                                       o_requestCount,
                                                                                       timestamp,
                                                                                       o_timestamp,
                                                                                       1000.0)));
  
          map.put("version", FormatUtil.formatVersion(perfAccesser.getVersion()));
          map.put("starttime", perfAccesser.getStartUpTime().getFormatTime());
  
          map.put("connectionCount", connectionCount);
          map.put("status", ss.getStatus());
  
          return map;
      }
  
      @Override
      public void handleRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException,
              IOException {
          AjaxParams params = new AjaxParams(request);
          CobarAdapterDAO perfAccesser = cobarAccesser.getAccesser(params.getCobarNodeId());
          JSONArray array = null;
          String jsonRst = null;
          String st = params.getValueType();
          if (null == st || st.equals("")) {
              throw new IllegalArgumentException("parameter 'cobarControlValueType' is unknown: " + st);
          }
          int type = typeMap.get(st);
          switch (type) {
          case TYPE_SERVER_STATUS:
              jsonRst = JSONObject.fromObject(getServerStatus(params)).toString(2);
              break;
          case TYPE_PROCESSOR_STATUS:
              List<Map<String, Object>> listProcessor = listProcessorStatus(params);
              array = JSONArray.fromObject(listProcessor);
              jsonRst = array.toString(2);
              break;
          case TYPE_THREAD_POOL:
              List<Map<String, Object>> listThreadpool = listThreadPool(params);
              array = JSONArray.fromObject(listThreadpool);
              jsonRst = array.toString(2);
              break;
          case TYPE_COMMAND:
              List<Map<String, Object>> listCommand = listCommand(params);
              array = JSONArray.fromObject(listCommand);
              jsonRst = array.toString(2);
              break;
          case TYPE_DATANODES:
              List<Map<String, Object>> listDatanode = listDatanode(params);
              array = JSONArray.fromObject(listDatanode);
              jsonRst = array.toString(2);
              break;
          case TYPE_DATABASES:
              List<String> listDatabase = null;
              if (perfAccesser.checkConnection()) {
                  listDatabase = perfAccesser.listDataBases();
              }
              array = JSONArray.fromObject(listDatabase);
              jsonRst = array.toString(2);
              break;
          case TYPE_DATASOURCES:
              List<DataSources> listDatasource = null;
              if (perfAccesser.checkConnection()) {
                  listDatasource = perfAccesser.listDataSources();
              }
              array = JSONArray.fromObject(listDatasource);
              jsonRst = array.toString(2);
              break;
          case TYPE_CONNECTION:
              List<Map<String, Object>> listConnection = listConnection(params);
              array = JSONArray.fromObject(listConnection);
              jsonRst = array.toString(2);
              break;
          default:
              throw new IllegalArgumentException("parameter 'cobarNodeInstantPerfValueType' is known: "
                                                 + params.getValueType());
          }
          perfAccesser = null;
  
          response.setHeader("Content-Type", "text/json; charset=utf-8");
          OutputStream out = response.getOutputStream();
          out.write(jsonRst.getBytes("utf-8"));
          out.flush();
      }
  
      private static final Map<String, Integer> typeMap = new HashMap<String, Integer>();
      static {
          typeMap.put("serverStatus", TYPE_SERVER_STATUS);
          typeMap.put("processorStatus", TYPE_PROCESSOR_STATUS);
          typeMap.put("threadPoolStatus", TYPE_THREAD_POOL);
          typeMap.put("command", TYPE_COMMAND);
          typeMap.put("datanodes", TYPE_DATANODES);
          typeMap.put("connection", TYPE_CONNECTION);
          typeMap.put("databases", TYPE_DATABASES);
          typeMap.put("datasources", TYPE_DATASOURCES);
      }
  }
  