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.*;
  
  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.apache.log4j.Logger;
  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.ProcessorStatus;
  import com.alibaba.cobar.manager.dataobject.cobarnode.ServerStatus;
  import com.alibaba.cobar.manager.dataobject.xml.CobarDO;
  import com.alibaba.cobar.manager.service.CobarAccesser;
  import com.alibaba.cobar.manager.service.XmlAccesser;
  import com.alibaba.cobar.manager.util.ConstantDefine;
  import com.alibaba.cobar.manager.util.FormatUtil;
  import com.alibaba.cobar.manager.util.MathUtil;
  import com.alibaba.cobar.manager.util.Pair;
  
  /**
   * @author wenfeng.cenwf 2011-3-8
   * @author haiqing.zhuhq 2011-7-14
   */
  public class ClusterInstantPerfValueAjax implements HttpRequestHandler, InitializingBean {
      private XmlAccesser xmlAccesser;
      private CobarAccesser cobarAccesser;
      private static final Logger logger = Logger.getLogger(ClusterInstantPerfValueAjax.class);
  
      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 groupByPList(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;
      }
  
      private List<Pair<Long, Integer>> listCobarMemoryUsage(AjaxParams params) {
          List<Pair<Long, Integer>> result = new ArrayList<Pair<Long, Integer>>();
          List<CobarDO> nodes = xmlAccesser.getCobarDAO().getCobarList(params.getClusterId(), ConstantDefine.ACTIVE);
          for (CobarDO node : nodes) {
              CobarAdapterDAO perfAccesser = cobarAccesser.getAccesser(node.getId());
              if (!perfAccesser.checkConnection()) {
                  StringBuilder sb = new StringBuilder("listCobarMemoryUsage: cobar connect error for Name:");
                  sb.append(node.getName()).append(" Host:").append(node.getHost());
                  logger.error(sb.toString());
                  continue;
              }
              ServerStatus ss = perfAccesser.getServerStatus();
              int memoryUsage = 0;
              if (ss.getTotalMemory() != 0) memoryUsage = Math.round(ss.getUsedMemory() * 100 / ss.getTotalMemory());
              result.add(new Pair<Long, Integer>(node.getId(), memoryUsage));
          }
          return result;
      }
  
      @SuppressWarnings("unchecked")
      private List<Map<String, Object>> getClusterThroughput(AjaxParams params) {
          List<Map<String, Object>> result = new ArrayList<Map<String, Object>>();
  
          JSONArray array = params.getArray();
          JSONObject json = null;
          Map<Long, JSONObject> cobarRequest = new HashMap<Long, JSONObject>();
  
          for (int i = 0; i < array.size(); i++) {
              JSONObject js = array.getJSONObject(i);
              if ("cluster".equals(js.getString("flag"))) {
                  json = js;
              } else if ("cobar".equals(js.getString("flag"))) {
                  cobarRequest.put(js.getLong("id"), js);
              }
          }
  
          PropertyUtilsBean util = new PropertyUtilsBean();
  
          long clusterId = params.getClusterId();
          List<CobarDO> nodes = xmlAccesser.getCobarDAO().getCobarList(clusterId, ConstantDefine.ACTIVE);
          AjaxResult cluster = new AjaxResult();
          cluster.setId(clusterId);
          cluster.setFlag("cluster");
  
          long timestamp = 0;
          for (CobarDO node : nodes) {
              CobarAdapterDAO perfAccesser = cobarAccesser.getAccesser(node.getId());
              if (!perfAccesser.checkConnection()) {
                  StringBuilder sb = new StringBuilder("getClusterThroughput: cobar connect error for Name:");
                  sb.append(node.getName()).append(" Host:").append(node.getHost());
                  logger.error(sb.toString());
                  continue;
              }
  
              AjaxResult re = new AjaxResult();
              List<ProcessorStatus> list = perfAccesser.listProccessorStatus();
              List<CommandStatus> cmdList = perfAccesser.listCommandStatus();
  
              long cobarNetIn = groupByPList(list, NET_IN);
              long cobarNetOut = groupByPList(list, NET_OUT);
              long cobarRequestCount = groupByCList(cmdList, REQUEST_COUNT);
  
              cluster.addRequest(cobarRequestCount);
              cluster.addNetIn(cobarNetIn);
              cluster.addNetOut(cobarNetOut);
  
              re.setId(node.getId());
              re.setFlag("cobar");
              re.setNetIn(cobarNetIn);
              re.setNetOut(cobarNetOut);
              re.setConnection(groupByPList(list, CONNECTION));
              re.setRequest(cobarRequestCount);
  
              timestamp = list.get(list.size() - 1).getSampleTimeStamp();
              re.setTimestamp(timestamp);
  
              JSONObject jsonTmp = cobarRequest.get(node.getId());
              if (jsonTmp != null) {
                  re.setNetIn_deriv(FormatUtil.formatNetwork(Math.round(MathUtil.getDerivate(cobarNetIn,
                                                                                             jsonTmp.getLong("netIn"),
                                                                                             timestamp,
                                                                                             jsonTmp.getLong("timestamp"),
                                                                                             1000.0))));
                  re.setNetOut_deriv(FormatUtil.formatNetwork(Math.round(MathUtil.getDerivate(cobarNetOut,
                                                                                              jsonTmp.getLong("netOut"),
                                                                                              timestamp,
                                                                                              jsonTmp.getLong("timestamp"),
                                                                                              1000.0))));
                  re.setRequest_deriv(FormatUtil.formatNumber(Math.round(MathUtil.getDerivate(cobarRequestCount,
                                                                                              jsonTmp.getLong("reCount"),
                                                                                              timestamp,
                                                                                              jsonTmp.getLong("timestamp"),
                                                                                              1000.0))));
              }
  
              Map<String, Object> map = null;
              try {
                  map = util.describe(re);
              } catch (Exception e) {
                  logger.error(e);
                  throw new RuntimeException(e);
              }
              if (null != map) {
                  result.add(map);
              }
          }
          cluster.setTimestamp(timestamp);
          if (null != json && json.getLong("netIn") != -1) {
              long o_tiemstamp = json.getLong("timestamp");
              cluster.setNetIn_deriv(FormatUtil.formatNetwork(Math.round(MathUtil.getDerivate(cluster.getNetIn(),
                                                                                              json.getLong("netIn"),
                                                                                              timestamp,
                                                                                              o_tiemstamp,
                                                                                              1000.0))));
              cluster.setNetOut_deriv(FormatUtil.formatNetwork(Math.round(MathUtil.getDerivate(cluster.getNetOut(),
                                                                                               json.getLong("netOut"),
                                                                                               timestamp,
                                                                                               o_tiemstamp,
                                                                                               1000.0))));
              cluster.setRequest_deriv(FormatUtil.formatNumber(Math.round(MathUtil.getDerivate(cluster.getRequest(),
                                                                                               json.getLong("reCount"),
                                                                                               timestamp,
                                                                                               o_tiemstamp,
                                                                                               1000.0))));
          }
          Map<String, Object> m = null;
          try {
              m = util.describe(cluster);
          } catch (Exception e) {
              logger.error(e);
              throw new RuntimeException(e);
          }
          if (null != m) {
              result.add(m);
          }
  
          return result;
      }
  
      private AjaxResult getClusterInfo(AjaxParams params) {
          JSONArray array = params.getArray();
          long clusterId = params.getClusterId();
  
          JSONObject json = null;
          if (array.size() > 0) {
              json = array.getJSONObject(0);
          }
  
          AjaxResult rs = new AjaxResult();
          rs.setId(clusterId);
  
          List<CobarDO> nodes = xmlAccesser.getCobarDAO().getCobarList(clusterId);
          rs.setTotal(nodes.size());
          for (CobarDO cobar : nodes) {
              if (ConstantDefine.IN_ACTIVE.equals(cobar.getStatus())) {
                  continue;
              }
              CobarAdapterDAO perfAccesser = cobarAccesser.getAccesser(cobar.getId());
              if (!perfAccesser.checkConnection()) {
                  rs.addError(1);
                  StringBuilder sb = new StringBuilder("getClusterInfo : cobar connect error for [ Name:");
                  sb.append(cobar.getName()).append(" Host:").append(cobar.getHost()).append(" ]");
                  logger.error(sb.toString());
                  continue;
              }
              rs.addActive(1);
              rs.setSchema(perfAccesser.listDataBases().size());
              List<ProcessorStatus> list = perfAccesser.listProccessorStatus();
              rs.addNetIn(groupByPList(list, NET_IN));
              rs.addNetOut(groupByPList(list, NET_OUT));
  
              rs.addConnection(groupByPList(list, CONNECTION));
              rs.setTimestamp(list.get(list.size() - 1).getSampleTimeStamp());
  
              List<CommandStatus> commandList = perfAccesser.listCommandStatus();
              rs.addRequest(groupByCList(commandList, REQUEST_COUNT));
          }
  
          if (json != null && json.getLong("netIn") != -1) {
              long o_tiemstamp = json.getLong("timestamp");
              rs.setNetIn_deriv(FormatUtil.formatNetwork(Math.round(MathUtil.getDerivate(rs.getNetIn(),
                                                                                         json.getLong("netIn"),
                                                                                         rs.getTimestamp(),
                                                                                         o_tiemstamp,
                                                                                         1000.0))));
              rs.setNetOut_deriv(FormatUtil.formatNetwork(Math.round(MathUtil.getDerivate(rs.getNetOut(),
                                                                                          json.getLong("netOut"),
                                                                                          rs.getTimestamp(),
                                                                                          o_tiemstamp,
                                                                                          1000.0))));
              rs.setRequest_deriv(FormatUtil.formatNumber(Math.round(MathUtil.getDerivate(rs.getRequest(),
                                                                                          json.getLong("reCount"),
                                                                                          rs.getTimestamp(),
                                                                                          o_tiemstamp,
                                                                                          1000.0))));
          }
  
          return rs;
      }
  
      private List<Pair<Long, String>> getStatus(AjaxParams params) {
          List<Pair<Long, String>> result = new ArrayList<Pair<Long, String>>();
          List<CobarDO> nodes = xmlAccesser.getCobarDAO().getCobarList(params.getClusterId(), ConstantDefine.ACTIVE);
          for (CobarDO node : nodes) {
              if (ConstantDefine.IN_ACTIVE.equals(node.getStatus())) {
                  result.add(new Pair<Long, String>(node.getId(), ConstantDefine.IN_ACTIVE));
                  continue;
              }
  
              CobarAdapterDAO perfAccesser = cobarAccesser.getAccesser(node.getId());
              if (!perfAccesser.checkConnection()) {
                  StringBuilder sb = new StringBuilder("getStatus: cobar connect error for Name:");
                  sb.append(node.getName()).append(" Host:").append(node.getHost());
                  logger.error(sb.toString());
                  result.add(new Pair<Long, String>(node.getId(), ConstantDefine.ERROR));
              } else {
                  result.add(new Pair<Long, String>(node.getId(), ConstantDefine.ACTIVE));
              }
          }
          return result;
      }
  
      @SuppressWarnings("unchecked")
      @Override
      public void handleRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException,
              IOException {
          AjaxParams params = new AjaxParams(request);
          String jsonRst = null;
          String st = params.getValueType();
          if (null == st || st.equals("")) {
              throw new IllegalArgumentException("parameter 'cobarControlValueType' is unknown: " + st);
          }
          int type = valueTypeMap.get(st);
          PropertyUtilsBean util = new PropertyUtilsBean();
  
          switch (type) {
          case TYPE_COBAR_MEMORY_USAGE:
              List<Pair<Long, Integer>> mList = listCobarMemoryUsage(params);
              JSONArray mArray = JSONArray.fromObject(mList);
              jsonRst = mArray.toString(2);
              break;
          case TYPE_CLUSTER_THROUGHPUT_INFO:
              List<Map<String, Object>> list1 = getClusterThroughput(params);
              JSONArray arrayMap = JSONArray.fromObject(list1);
              jsonRst = arrayMap.toString(2);
              break;
          case TYPE_CLUSTER_INFO:
              AjaxResult rs = getClusterInfo(params);
              Map<String, Object> map = null;
              try {
                  map = util.describe(rs);
              } catch (Exception e) {
                  logger.error(e);
                  throw new RuntimeException(e);
              }
              jsonRst = JSONObject.fromObject(map).toString(2);
              break;
          case TYPE_STATUS:
              List<Pair<Long, String>> sList = getStatus(params);
              JSONArray sArray = JSONArray.fromObject(sList);
              jsonRst = sArray.toString(2);
              break;
          default:
              throw new IllegalArgumentException("parameter 'ValueType' is known: " + params.getValueType());
          }
          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> valueTypeMap = new HashMap<String, Integer>();
      static {
          valueTypeMap.put("cobarServerLevelMemoryUsage", TYPE_COBAR_MEMORY_USAGE);
          valueTypeMap.put("cobarClusterLevelThroughput", TYPE_CLUSTER_THROUGHPUT_INFO);
          valueTypeMap.put("indexInfo", TYPE_INDEX);
          valueTypeMap.put("clusterInfo", TYPE_CLUSTER_INFO);
          valueTypeMap.put("status", TYPE_STATUS);
      }
  
      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;
  
  }
  