package codeine.servlets.api_servlets.angular;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.log4j.Logger;
import codeine.api.MonitorStatusInfo;
import codeine.api.NodeGetter;
import codeine.api.NodeInfo;
import codeine.api.NodeWithMonitorsInfo;
import codeine.configuration.ConfigurationReadManagerServer;
import codeine.configuration.IConfigurationManager;
import codeine.jsons.nodes.NodeDiscoveryStrategy;
import codeine.jsons.peer_status.PeersProjectsStatus;
import codeine.jsons.project.ProjectJson;
import codeine.model.Constants;
import codeine.permissions.IUserWithPermissions;
import codeine.permissions.UserPermissionsGetter;
import codeine.servlet.AbstractApiServlet;
import codeine.utils.network.InetUtils;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.inject.Inject;
public class ProjectStatus2ApiServlet extends AbstractApiServlet {
private static final Logger log = Logger
.getLogger(ProjectStatus2ApiServlet.class);
private static final long serialVersionUID = 1L;
@Inject private NodeGetter nodesGetter;
@Inject private IConfigurationManager configurationManager;
@Inject private UserPermissionsGetter userPermissionsGetter;
@Inject private PeersProjectsStatus peersProjectsStatus;
@Override
protected boolean checkPermissions(HttpServletRequest request) {
return canReadProject(request);
}
@Override
protected void myGet(HttpServletRequest request, HttpServletResponse response) {
String projectName = getParameter(request, Constants.UrlParameters.PROJECT_NAME);
List<NodeWithMonitorsInfo> nodes = nodesGetter.getNodes(projectName,Constants.ALL_VERSION);
ProjectJson projectJson = configurationManager.getProjectForName(projectName);
ProjectStatusInfo projectStatusInfo = create(projectJson, nodes, request);
optimizeForUi(projectStatusInfo);
writeResponseGzipJson(projectStatusInfo, request, response);
}
private void optimizeForUi(ProjectStatusInfo projectStatusInfo) {
for (NodesForVersion nodesForVersion : projectStatusInfo.nodes_for_version) {
for (NodeWithMonitorsInfo node : nodesForVersion.nodes) {
node.collectors(null);
}
}
}
//TODO handle duplicate node and refactor to other class
private ProjectStatusInfo create(ProjectJson projectJson, List<NodeWithMonitorsInfo> nodes, HttpServletRequest request) {
Map<String, Integer> tagCount = Maps.newHashMap();
Map<String, Integer> monitorCount = Maps.newHashMap();
Map<String, NodesForVersion> nodesByVersion = Maps.newHashMap();
int totalNumberOfNodesWithAlerts = 0;
IUserWithPermissions user = userPermissionsGetter.user(request);
for (NodeWithMonitorsInfo nodeWithMonitorsInfo : nodes) {
for (String tag : nodeWithMonitorsInfo.tags()) {
Integer count = tagCount.get(tag);
if (count == null) {
count = 0;
}
tagCount.put(tag, count + 1);
}
for (String monitor : nodeWithMonitorsInfo.failed_collectors()) {
Integer count = monitorCount.get(monitor);
if (count == null) {
count = 0;
}
monitorCount.put(monitor, count + 1);
}
if (!nodeWithMonitorsInfo.status()) {
totalNumberOfNodesWithAlerts++;
}
NodesForVersion nodeStatusInfoList = nodesByVersion.get(nodeWithMonitorsInfo.version());
if (nodeStatusInfoList == null) {
nodeStatusInfoList = new NodesForVersion(nodeWithMonitorsInfo.version());
nodesByVersion.put(nodeWithMonitorsInfo.version(), nodeStatusInfoList);
}
boolean can_command = user.canCommand(projectJson.name(), nodeWithMonitorsInfo.alias());
nodeStatusInfoList.add(new NodeWithMonitorsInfoApi(nodeWithMonitorsInfo, can_command));
}
List<NodesForVersion> nodes_for_version = createNodesList(nodesByVersion, nodes, projectJson);
int totalNumberOfNodes = nodes_for_version.isEmpty() ? 0 : nodes_for_version.get(0).nodes.size();
calculatePrecent(totalNumberOfNodes, nodes_for_version);
List<CountInfo> tag_info = createSortedList(tagCount);
List<CountInfo> collectors_count = createSortedList(monitorCount);
NodesForVersion[] offlineNodes = createOfflineNodes(projectJson, nodes);
if (null != offlineNodes[0] && offlineNodes[0].nodes.size() > 0) {
nodes_for_version.add(0, offlineNodes[0]);
}
if (null != offlineNodes[1] && offlineNodes[1].nodes.size() > 0) {
nodes_for_version.add(0, offlineNodes[1]);
}
return new ProjectStatusInfo(nodes_for_version, tag_info, collectors_count, totalNumberOfNodesWithAlerts, isMoreEnabled(projectJson, nodes));
}
private boolean isMoreEnabled(ProjectJson projectJson, List<NodeWithMonitorsInfo> nodes) {
int nodesCountForMore = 100;
if (projectJson.node_discovery_startegy() == NodeDiscoveryStrategy.Configuration && !projectJson.equals(ConfigurationReadManagerServer.NODES_INTERNAL_PROJECT)) {
return projectJson.nodes_info().size() > nodesCountForMore;
}
return nodes.size() > nodesCountForMore;
}
private void calculatePrecent(int totalNumberOfNodes, List<NodesForVersion> nodes_for_version) {
for (NodesForVersion e : nodes_for_version) {
e.calculatePrecent(totalNumberOfNodes);
}
}
private List<NodesForVersion> createNodesList(Map<String, NodesForVersion> nodesByVersion, List<NodeWithMonitorsInfo> nodes, ProjectJson projectJson) {
List<NodesForVersion> $ = Lists.newArrayList();
for (Entry<String, NodesForVersion> e : nodesByVersion.entrySet()) {
$.add(e.getValue());
}
Comparator<NodesForVersion> c = new Comparator<NodesForVersion>() {
@Override
public int compare(NodesForVersion o1, NodesForVersion o2) {
return o2.nodes.size() - o1.nodes.size();
}
};
Collections.sort($, c);
return $;
}
private NodesForVersion[] createOfflineNodes(ProjectJson projectJson, List<NodeWithMonitorsInfo> nodes) {
NodesForVersion[] $ = new NodesForVersion[2];
if (projectJson.node_discovery_startegy() != NodeDiscoveryStrategy.Configuration) {
return $;
}
NodesForVersion offlineNodes = new NodesForVersion(Constants.OFFLINE_NODES);
NodesForVersion notReportedNodes = new NodesForVersion(Constants.NOT_REPORTING_NODES);
for (NodeInfo nodeInfo : projectJson.nodes_info()) {
if (notOffline(nodeInfo, nodes)) {
continue;
}
Map<String, MonitorStatusInfo> monitors = Maps.newHashMap();
String peerStatus = getPeerStatus(nodeInfo.name());
NodeWithMonitorsInfoApi nodeStatusInfo = new NodeWithMonitorsInfoApi(new NodeWithMonitorsInfo(
nodeInfo.name(), nodeInfo.alias(), projectJson.name(), monitors, peerStatus), false);
log.info("adding offline node " + nodeStatusInfo);
if (peerStatus.equals(Constants.OFFLINE_NODES)) {
offlineNodes.add(nodeStatusInfo);
} else {
notReportedNodes.add(nodeStatusInfo);
}
}
$[0] = offlineNodes;
$[1] = notReportedNodes;
return $;
}
private String getPeerStatus(String nodeName) {
for (String peer : peersProjectsStatus.peer_to_projects().keySet()) {
if (InetUtils.nameWithoutPort(peer).equals(InetUtils.nameWithoutPort(nodeName))) {
return Constants.NOT_REPORTING_NODES;
}
}
return Constants.OFFLINE_NODES;
}
private boolean notOffline(NodeInfo nodeInfo, List<NodeWithMonitorsInfo> nodes) {
for (NodeWithMonitorsInfo nodeWithMonitorsInfo : nodes) {
if (nodeWithMonitorsInfo.name().equals(nodeInfo.name())) {
return true;
}
}
return false;
}
private List<CountInfo> createSortedList(Map<String, Integer> map) {
List<CountInfo> $ = Lists.newArrayList();
for (Entry<String, Integer> e : map.entrySet()) {
$.add(new CountInfo(e.getKey(), e.getValue()));
}
Comparator<CountInfo> c = new Comparator<CountInfo>() {
@Override
public int compare(CountInfo o1, CountInfo o2) {
return o1.name.compareTo(o2.name);
}
};
Collections.sort($, c);
return $;
}
@SuppressWarnings("unused")
public static class ProjectStatusInfo {
private int any_alert_count;
private List<NodesForVersion> nodes_for_version;
private List<CountInfo> tag_info;
private List<CountInfo> collectors_count;
private boolean more_nodes_enabled;
public ProjectStatusInfo(List<NodesForVersion> nodes_for_version, List<CountInfo> tag_info, List<CountInfo> collectors_count, int any_alert_count, boolean more_nodes_enabled) {
super();
this.nodes_for_version = nodes_for_version;
this.tag_info = tag_info;
this.collectors_count = collectors_count;
this.any_alert_count = any_alert_count;
this.more_nodes_enabled = more_nodes_enabled;
}
}
@SuppressWarnings("unused")
public static class NodesForVersion {
private String version;
private List<NodeWithMonitorsInfo> nodes = Lists.newArrayList();
private int failing_nodes_count;
private int failing_nodes_precent;
private int not_failing_nodes_precent;
public NodesForVersion(String version) {
this.version = version;
}
public void calculatePrecent(int totalNumberOfNodes) {
if (totalNumberOfNodes == 0) {
return;
}
failing_nodes_precent = failing_nodes_count * 100 / totalNumberOfNodes;
not_failing_nodes_precent = (nodes.size() - failing_nodes_count) * 100 / totalNumberOfNodes;
}
public void add(NodeWithMonitorsInfo nodeStatusInfo) {
nodes.add(nodeStatusInfo);
if (!nodeStatusInfo.status()) {
failing_nodes_count++;
}
}
}
@SuppressWarnings("unused")
public static class CountInfo {
private String name;
private int count;
public CountInfo(String name, int count) {
super();
this.name = name;
this.count = count;
}
}
}