/*******************************************************************************
* Copyright 2014 Miami-Dade County
*
* 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 org.sharegov.cirm.stats;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import mjson.Json;
/**
* CirmClusterStatistics provides all data and history for each server and an aggregated cluster data history.
*
* @author Thomas Hilpold
*/
public class CirmClusterStatistics implements ICirmClusterStatistics {
public final static String DEFAULT_CONFIG_JSON = "/CirmClusterStatistics.json";
private final List<CirmServerStatistics> allServerDataHistory = new ArrayList<>();
private final CirmServerStatistics clusterDataHistory = new CirmServerStatistics(CLUSTER_NAME);
public CirmClusterStatistics() throws Exception {
this(readConfig());
}
/**
* Configuration is an array of objects with properties:
* serverName String a human consumable server name
* serverStatsJsonUrl String the full url to retrieve the json from
* jsonStatsArrayProperty String the property which holds the array (e.g. "stats-all")
*
* @param configuration
*/
public CirmClusterStatistics(Json configuration) {
if (!configuration.isArray()) throw new IllegalArgumentException("Config must be array");
initialize(configuration);
}
final static synchronized Json readConfig() throws Exception {
InputStream is = CirmClusterStatistics.class.getResource(DEFAULT_CONFIG_JSON).openStream();
BufferedReader bfr = new BufferedReader(new InputStreamReader(is));
StringBuffer json = new StringBuffer(1000);
String line;
while ((line = bfr.readLine()) != null)
{
json.append(line + "\r\n");
}
bfr.close();
return Json.read(json.toString());
}
final void initialize(Json configuration) {
for (Json serverConfig : configuration.asJsonList()) {
if (!serverConfig.has("serverName")) throw new IllegalArgumentException("no servername in " + serverConfig.toString());
if (!serverConfig.has("serverStatsJsonUrl")) throw new IllegalArgumentException("no serverStatsJsonUrl in " + serverConfig.toString());
if (!serverConfig.has("jsonStatsArrayProperty")) throw new IllegalArgumentException("no jsonStatsArrayProperty in " + serverConfig.toString());
String serverName = serverConfig.at("serverName").asString();
String serverStatsJsonUrlStr = serverConfig.at("serverStatsJsonUrl").asString();
String jsonStatsArrayProperty = serverConfig.at("jsonStatsArrayProperty").asString();
URL serverStatsJsonUrl;
try {
serverStatsJsonUrl = new URL(serverStatsJsonUrlStr);
} catch (MalformedURLException ex) {
throw new IllegalArgumentException("Invalid serverStatsJsonUrl " +ex + " in "+ serverStatsJsonUrlStr);
}
CirmServerStatistics dhp = new CirmServerStatistics(serverName, serverStatsJsonUrl, jsonStatsArrayProperty);
allServerDataHistory.add(dhp);
}
}
/**
* Updates all server data histories and the cluster history with the exact same timestamp.
*/
@Override
public void updateAll() {
Date now = new Date();
for (CirmServerStatistics p : allServerDataHistory) {
try {
p.updateFromUrl(now);
System.out.println("Update succeeded " + p.getServerName());
} catch (Exception e)
{
e.printStackTrace();
System.err.println("update failed at time " + now + " for server " + p.getServerName());
}
}
System.out.println("updateAll took " + (((System.currentTimeMillis() - now.getTime()) / 10) /100.0f) + " seconds");
updateCluster(now);
}
protected void updateCluster(Date now) {
CirmStatistics clusterNowStats = new CirmStatistics();
for (CirmServerStatistics p : allServerDataHistory) {
CirmStatistics pStats = p.getStatsAt(now);
if (pStats != null) {
for (Map.Entry<CirmStatistics.StatsKey, CirmStatistics.StatsValue> statsKeyValue : pStats.getStatistics().entrySet()) {
CirmStatistics.StatsKey cur = statsKeyValue.getKey();
CirmStatistics.StatsValue clusterValue = clusterNowStats.getEntry(cur.getComponent(), cur.getAction(), cur.gettype());
clusterValue.aggregate(statsKeyValue.getValue());
}
} else {
System.err.println("ClusterStats updateCluster not accurate as no information for server " + p.getServerName() + " at " + now
+ " could be aggregated");
}
}
clusterDataHistory.update(now, clusterNowStats);
}
@Override
public CirmStatistics getLastClusterStatistics() {
if (clusterDataHistory.getLastUpdateTime() == null) {
return null;
} else {
return clusterDataHistory.getStatsAt(clusterDataHistory.getLastUpdateTime());
}
}
@Override
public List<DateStatsValuePair> getClusterHistoryForKey(CirmStatistics.StatsKey key) {
return clusterDataHistory.getHistoryForKey(key);
}
@Override
public int getNrOfServers() {
return allServerDataHistory.size();
}
@Override
public CirmServerStatistics getDataHistoryByName(String serverOrClusterName) {
CirmServerStatistics result = null;
if (CirmClusterStatistics.CLUSTER_NAME.equals(serverOrClusterName)) {
result = getClusterDataHistory();
} else {
for (int i = 0; i < getNrOfServers() && result == null; i++) {
CirmServerStatistics cur = getServerDataHistory(i);
if (cur.getServerName().equals(serverOrClusterName)){
result = cur;
}
}
}
return result;
}
@Override
public CirmServerStatistics getClusterDataHistory() {
return clusterDataHistory;
}
@Override
public CirmServerStatistics getServerDataHistory(int serverIndex) {
return allServerDataHistory.get(serverIndex);
}
@Override
public CirmStatistics getLastServerStatistics(int serverIndex) {
CirmServerStatistics serverData = allServerDataHistory.get(serverIndex);
if (serverData.getLastUpdateTime() == null) return null;
return serverData.getStatsAt(serverData.getLastUpdateTime());
}
@Override
public List<DateStatsValuePair> getServerHistoryForKey(int serverIndex, CirmStatistics.StatsKey key) {
CirmServerStatistics serverData = allServerDataHistory.get(serverIndex);
return serverData.getHistoryForKey(key);
}
}