package org.xins.server;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.TimeZone;
import javax.servlet.http.HttpServletResponse;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.xins.common.collections.InvalidPropertyValueException;
import org.xins.common.collections.MissingRequiredPropertyException;
import org.xins.common.manageable.BootstrapException;
import org.xins.common.spec.FunctionSpec;
import org.xins.common.spec.InvalidSpecificationException;
import org.xins.common.text.DateConverter;
public class StatisticsInterceptor extends Interceptor {
protected Map<String, FunctionStatistics> statistics = new LinkedHashMap<String, FunctionStatistics>();
protected long _lastStatisticsReset;
@Override
protected void bootstrapImpl(Map<String, String> properties)
throws MissingRequiredPropertyException,
InvalidPropertyValueException,
BootstrapException {
_lastStatisticsReset = getApi().getStartupTimestamp();
try {
Map<String, FunctionSpec> functions = getApi().getAPISpecification().getFunctions();
for (String functionName: functions.keySet()) {
statistics.put(functionName, new FunctionStatistics());
}
} catch (InvalidSpecificationException ex) {
}
}
@Override
public FunctionResult afterFunctionCall(FunctionRequest functionRequest, FunctionResult xinsResult, HttpServletResponse httpResponse) {
String functionName = functionRequest.getFunctionName();
FunctionStatistics statistic = statistics.get(functionName);
if (statistic != null) {
long start = (Long) functionRequest.getBackpack().get(BackpackConstants.START);
statistic.recordCall(start, xinsResult);
}
return xinsResult;
}
protected FunctionResult getStatistics(boolean detailed, String functionName) {
FunctionResult builder = new FunctionResult();
TimeZone timeZone = getApi().getTimeZone();
builder.param("startup", DateConverter.toDateString(timeZone, getApi().getStartupTimestamp()));
builder.param("lastReset", DateConverter.toDateString(timeZone, _lastStatisticsReset));
builder.param("now", DateConverter.toDateString(timeZone, System.currentTimeMillis()));
Runtime rt = Runtime.getRuntime();
builder.param("availableProcessors", String.valueOf(rt.availableProcessors()));
Element heap = builder.getDataElementBuilder().createElement("heap");
long free = rt.freeMemory();
long total = rt.totalMemory();
heap.setAttribute("used", String.valueOf(total - free));
heap.setAttribute("free", String.valueOf(free));
heap.setAttribute("total", String.valueOf(total));
long max = rt.maxMemory();
heap.setAttribute("max", String.valueOf(max));
double percentageUsed = (total - free) / (double) max;
heap.setAttribute("percentageUsed", String.valueOf((int) (percentageUsed * 100)));
builder.getDataElement().appendChild(heap);
for (Map.Entry<String, FunctionStatistics> stat : statistics.entrySet()) {
String statFunctionName = stat.getKey();
if (functionName != null && !functionName.equals(statFunctionName)) {
continue;
}
FunctionStatistics stats = stat.getValue();
Element functionElem = builder.getDataElementBuilder().createElement("function");
functionElem.setAttribute("name", statFunctionName);
Document functionDoc = functionElem.getOwnerDocument();
Element successful = stats.getSuccessfulElement();
functionElem.appendChild(functionDoc.importNode(successful, true));
if (stats.hasNotModified()) {
Element notModified = stats.getNotModifiedElement();
functionElem.appendChild(functionDoc.importNode(notModified, true));
}
Element[] unsuccessful = stats.getUnsuccessfulElement(detailed);
for(int j = 0; j < unsuccessful.length; j++) {
functionElem.appendChild(functionDoc.importNode(unsuccessful[j], true));
}
builder.getDataElement().appendChild(functionElem);
}
return builder;
}
protected FunctionResult resetStatistics() {
_lastStatisticsReset = System.currentTimeMillis();
for (FunctionStatistics stat : statistics.values()) {
stat.resetStatistics();
}
return API.SUCCESSFUL_RESULT;
}
public Map<String, FunctionStatistics> getStatistics() {
return statistics;
}
}