/**
* Copyright 2012 Comcast Corporation
*
* 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.comcast.cmb.common.controller;
import com.comcast.cmb.common.util.Util;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.codec.binary.Base64;
import org.apache.log4j.Logger;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;
import org.jfree.chart.ChartUtilities;
import org.json.JSONObject;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.security.MessageDigest;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Vector;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
/**
* Test servlet for endpoint
* @author bwolf, michael
*
*/
public class EndpointServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
// keeps last n messages per endpoint
private static ConcurrentHashMap<String, List<EndpointMessage>> messageMap = new ConcurrentHashMap<String, List<EndpointMessage>>();
// keeps endpoint stats
private static ConcurrentHashMap<String, EndpointMetrics> metricsMap = new ConcurrentHashMap<String, EndpointMetrics>();
// keeps config information to model certain error behavior
//private static Map<String, EndpointFailureConfiguration> failureConfigMap = new ConcurrentHashMap<String, EndpointFailureConfiguration>();
// for each endpoint message a set of message hashes to help identify duplicates
private static ConcurrentHashMap<String, Map<String, Boolean>> messageHashes = new ConcurrentHashMap<String, Map<String, Boolean>>();
// for each endpoint keeps number of duplciates received (no record = no dups, 1 = 1 dup, ...)
private static ConcurrentHashMap<String, AtomicInteger> messageDuplicates = new ConcurrentHashMap<String, AtomicInteger>();
private static AtomicInteger globalMessageCounter = new AtomicInteger(0);
private final static int MAX_MSG_PER_USER = 100;
private final static String VERSION = CMBControllerServlet.VERSION;
private static Logger logger = Logger.getLogger(EndpointServlet.class);
private static final Random rand = new Random();
/*private class EndpointFailureConfiguration {
public int numFailuresBeforeSuccess = 10;
public int currentFailureCounter = 0;
public int httpErrorCode = 404;
}*/
private class EndpointMessage {
public String host;
public String id;
public String recvOn;
public String url;
public String method;
public String msg;
public String httpHeader;
//public boolean failure = false;
}
private class EndpointMetrics {
public EndpointMetrics(EndpointMessage msg) {
startTime = new Date();
endTime = new Date();
lastMessageTime = new Date();
messageCount = 1;
minWaveLength = Long.MAX_VALUE;
minLatency = Long.MAX_VALUE;
lastMessage = msg;
}
public Date startTime;
public Date endTime;
public long messageCount;
public long minWaveLength;
public long maxWaveLength;
public long averageWaveLength;
public long totalWaveLength;
public long lastWaveLength;
public long messagesPerSecond;
public long minLatency;
public long maxLatency;
public long averageLatency;
public long totalLatency;
public long lastLatency;
public Date lastMessageTime;
public EndpointMessage lastMessage;
public List<Integer> timeSeries = new ArrayList<Integer>();
}
private String hashMessage(String message) {
try {
MessageDigest digest = MessageDigest.getInstance("MD5");
digest.update(message.getBytes("UTF-8"));
byte[] hash = digest.digest();
return Base64.encodeBase64URLSafeString(hash);
} catch (Exception e) {
logger.error("event=hashing_failed", e);
}
return null;
}
@Override
public void init() throws ServletException {
super.init();
try {
Util.initLog4jTest();
} catch (Exception e) {
throw new ServletException(e);
}
}
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String pathInfo = request.getPathInfo();
if (pathInfo == null) {
doHelp(request, response);
return;
}
//logger.info("pathInfo="+pathInfo+" ip="+request.getRemoteAddr());
if (pathInfo.toLowerCase().startsWith("/recv")) {
doReceiveMessage(request, response);
} else if (pathInfo.toLowerCase().startsWith("/help")) {
doHelp(request, response);
//} else if (pathInfo.toLowerCase().startsWith("/config")) {
//doConfig(request, response);
} else if (pathInfo.toLowerCase().startsWith("/clear")) {
doClear(request, response);
} else if (pathInfo.toLowerCase().startsWith("/nop")) {
doAlmostNothing(request, response);
} else if (pathInfo.toLowerCase().startsWith("/log")) {
doLogMessage(request, response);
} else if (pathInfo.toLowerCase().startsWith("/info")) {
doDisplayMessages(request, response);
} else if (pathInfo.toLowerCase().startsWith("/token")) {
doGetToken(request, response);
} else if (pathInfo.toLowerCase().startsWith("/metrics")) {
doMetrics(request, response);
} else if (pathInfo.toLowerCase().startsWith("/chart")) {
doChart(request, response);
} else if (pathInfo.toLowerCase().startsWith("/list")) {
doList(request, response);
} else {
doHelp(request, response);
}
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
String pathInfo = request.getPathInfo();
if (pathInfo == null) {
doHelp(request, response);
return;
}
//logger.info("pathInfo="+pathInfo+" ip="+request.getRemoteAddr());
if (pathInfo.toLowerCase().startsWith("/recv")) {
doReceiveMessage(request, response);
} else if (pathInfo.toLowerCase().startsWith("/help")) {
doHelp(request, response);
//} else if (pathInfo.toLowerCase().startsWith("/config")) {
//doConfig(request, response);
} else if (pathInfo.toLowerCase().startsWith("/clear")) {
doClear(request, response);
} else if (pathInfo.toLowerCase().startsWith("/nop")) {
doAlmostNothing(request, response);
} else if (pathInfo.toLowerCase().startsWith("/log")) {
doLogMessage(request, response);
} else if (pathInfo.toLowerCase().startsWith("/info")) {
doDisplayMessages(request, response);
} else if (pathInfo.toLowerCase().startsWith("/token")) {
doGetToken(request, response);
} else if (pathInfo.toLowerCase().startsWith("/metrics")) {
doMetrics(request, response);
} else if (pathInfo.toLowerCase().startsWith("/chart")) {
doChart(request, response);
} else if (pathInfo.toLowerCase().startsWith("/list")) {
doList(request, response);
} else {
doHelp(request, response);
}
}
protected void doHelp(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
StringBuffer sb = new StringBuffer();
sb.append("<h3>EndPoint Help - V " + VERSION + "</h3>");
sb.append("<b>/recv/id</b> - receive message and calculate metrics on the fly by test id (can be used for up to 2000 msg/sec)<br/>");
sb.append("<b>/recv/id?errorCode=<errorCode>&chance=<0-1></b> - occasionally respond with an error<br/>");
sb.append("<b>/recv/id?delayMS=<delayMS>&chance=<0-1></b> - occasionally respond with a delay<br/>");
sb.append("<b>/recv/id?numResponseBytes=<numResponseBytes>&chance=<0-1></b> - occasionally respond with an error<br/>");
sb.append("<b>/log/id</b> - receive and do basic logging for message by test id<br/>");
sb.append("<b>/nop/id</b> - just receive and globally count messages by test id<br/>");
sb.append("<b><a href=\"clear\">/clear</a></b> - clear all messages, logs and state information<br/>");
sb.append("<b>/info/id</b> - list recent messages returning http 200 by test id<br/>");
sb.append("<b>/token/id</b> - obtain sns token by test id<br/>");
sb.append("<b>/metrics/id</b> - list metrics for test by id<br/>");
sb.append("<b>/chart/id</b> - render chart for test by id<br/>");
sb.append("<b><a href=\"list\">/list</a></b> - list information for all test runs<br/>");
sb.append("<b>/help</b> - this help<br/>");
sb.append("<b>/config/id?errorCount=10&statusCode=404</b> - set number of failures and error code before successful receipt of messages begins by test id<br/>");
doOutput(200, response, "Help", sb.toString());
}
/*protected void doConfig(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String pathInfo = request.getPathInfo();
String id = pathInfo.substring(pathInfo.lastIndexOf("/")+1);
EndpointFailureConfiguration failureConfig = new EndpointFailureConfiguration();
failureConfigMap.put(id, failureConfig);
if (request.getParameter("errorCount") != null) {
failureConfig.numFailuresBeforeSuccess = Integer.parseInt(request.getParameter("errorCount"));
}
if (request.getParameter("statusCode") != null) {
failureConfig.httpErrorCode = Integer.parseInt(request.getParameter("statusCode"));
}
doRawOutput(200, response, "OK");
}*/
protected void doClear(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
messageMap = new ConcurrentHashMap<String, List<EndpointMessage>>();
metricsMap = new ConcurrentHashMap<String, EndpointMetrics>();
//failureConfigMap = new ConcurrentHashMap<String, EndpointFailureConfiguration>();
globalMessageCounter = new AtomicInteger(0);
messageHashes = new ConcurrentHashMap<String, Map<String, Boolean>>();
messageDuplicates = new ConcurrentHashMap<String, AtomicInteger>();
doRawOutput(200, response, "OK");
}
protected void doAlmostNothing(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
globalMessageCounter.incrementAndGet();
doRawOutput(200, response, "OK");
}
protected void doLogMessage(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
globalMessageCounter.incrementAndGet();
String msg=parseMessage(request).msg;
if (msg.length()>30){
msg=msg.substring(0,29);
}
logger.info("event=Endpoint_dolog_Message url="+request.getRequestURI()+ " msg="+msg+"..." + " ts="+System.currentTimeMillis());
doRawOutput(200, response, "OK");
}
protected void doGetToken(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String pathInfo = request.getPathInfo();
String id = pathInfo.substring(pathInfo.lastIndexOf("/")+1);
if (id.toLowerCase().startsWith("token")) {
doOutput(404, response, "EndPoint - GetToken", "Please provide an id");
return;
}
List<EndpointMessage> messages = getMessages(id);
if (messages == null || messages.size() == 0) {
doOutput(404, response, "EndPoint - GetToken", "Cannot find token for id="+id);
return;
}
for (EndpointMessage message : messages) {
try {
JSONObject json = new JSONObject(message.msg);
String token = json.getString("Token");
if (token == null) {
continue;
}
doOutput(200, response, "EndPoint - GetToken", token);
return;
} catch (Exception ex) {
continue;
}
}
doOutput(404, response, "EndPoint - GetToken", "Cannot find token for id="+id);
}
private synchronized void addMessage(EndpointMessage msg) {
// add message
messageMap.putIfAbsent(msg.id, new Vector<EndpointMessage>(MAX_MSG_PER_USER));
List<EndpointMessage> messages = messageMap.get(msg.id);
if (messages.size() == MAX_MSG_PER_USER) {
messages.remove(MAX_MSG_PER_USER - 1); //remove the oldest message
}
messages.add(0, msg);
// add metrics
metricsMap.putIfAbsent(msg.id, new EndpointMetrics(msg));
EndpointMetrics metrics = metricsMap.get(msg.id);
metrics.endTime = new Date();
metrics.messageCount++;
metrics.lastWaveLength = metrics.endTime.getTime() - metrics.lastMessageTime.getTime();
metrics.lastMessageTime = metrics.endTime;
metrics.lastMessage = msg;
metrics.totalWaveLength += metrics.lastWaveLength;
if (metrics.lastWaveLength < metrics.minWaveLength) {
metrics.minWaveLength = metrics.lastWaveLength;
}
if (metrics.lastWaveLength > metrics.maxWaveLength) {
metrics.maxWaveLength = metrics.lastWaveLength;
}
if (metrics.messageCount > 1) {
metrics.averageWaveLength = metrics.totalWaveLength / (metrics.messageCount - 1);
}
if (metrics.endTime.getTime() > metrics.startTime.getTime()) {
metrics.messagesPerSecond = 1000 * metrics.messageCount / (metrics.endTime.getTime() - metrics.startTime.getTime());
}
String tokens[] = msg.msg.split(";");
if (tokens.length >= 2) {
try {
Date sentTime = new Date(Long.parseLong(tokens[1]));
metrics.lastLatency = (new Date()).getTime() - sentTime.getTime();
metrics.totalLatency += metrics.lastLatency;
} catch (Exception ex) {
logger.error("exception", ex);
}
}
if (metrics.messageCount > 0) {
metrics.averageLatency = metrics.totalLatency / metrics.messageCount;
}
if (metrics.lastLatency < metrics.minLatency) {
metrics.minLatency = metrics.lastLatency;
}
if (metrics.lastLatency > metrics.maxLatency) {
metrics.maxLatency = metrics.lastLatency;
}
int idx = (int)(metrics.endTime.getTime() - metrics.startTime.getTime())/1000;
while (metrics.timeSeries.size()-1 < idx) {
metrics.timeSeries.add(new Integer(0));
}
metrics.timeSeries.set(idx, metrics.timeSeries.get(idx) + 1);
// check for dups
String message = null;
if (msg.msg.contains("\"MessageId\":")) {
message = msg.msg.substring(0, msg.msg.indexOf("\"MessageId\":"));
} else {
message = msg.msg;
}
String messageHash = hashMessage(message);
messageHashes.putIfAbsent(msg.id, new ConcurrentHashMap<String, Boolean>());
ConcurrentHashMap<String, Boolean> hashSet = (ConcurrentHashMap<String, Boolean>)messageHashes.get(msg.id);
if (hashSet.putIfAbsent(messageHash, true) != null) {
if (messageDuplicates.putIfAbsent(msg.id, new AtomicInteger(1)) != null) {
messageDuplicates.get(msg.id).incrementAndGet();
}
}
}
protected void doChart(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String pathInfo = request.getPathInfo();
String id = pathInfo.substring(pathInfo.lastIndexOf("/")+1);
EndpointMetrics metrics = metricsMap.get(id);
if (metrics != null) {
byte b[] = generateChart(metrics, id);
response.setContentLength(b.length);
response.setContentType("image/jpeg");
response.getOutputStream().write(b);
response.flushBuffer();
} else {
doOutput(404, response, "EndPoint - Chart", "Page not found");
}
}
protected void doMetrics(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String pathInfo = request.getPathInfo();
String id = pathInfo.substring(pathInfo.lastIndexOf("/")+1);
EndpointMetrics metrics = metricsMap.get(id);
if (metrics != null) {
StringBuilder sb = new StringBuilder();
sb.append("<table>");
sb.append("<tr><td>Start Time:</td><td>" + metrics.startTime + "</td></tr>");
sb.append("<tr><td>End Time:</td><td>" + metrics.endTime + "</td></tr>");
sb.append("<tr><td><b>Messages Per Second:</b></td><td><b>" + metrics.messagesPerSecond + "</b></td></tr>");
sb.append("<tr><td><b>Message Count:</b></td><td><b>" + metrics.messageCount + "</b></td></tr>");
sb.append("<tr><td><b>Avergae Latency:</b></td><td><b>" + metrics.averageLatency + "</b></td></tr>");
sb.append("<tr><td>Last Latency:</td><td>" + metrics.lastLatency + "</td></tr>");
sb.append("<tr><td>Max Latency:</td><td>" + metrics.maxLatency + "</td></tr>");
sb.append("<tr><td>Min Latency:</td><td>" + metrics.minLatency + "</td></tr>");
sb.append("<tr><td>Total Latency:</td><td>" + metrics.totalLatency + "</td></tr>");
sb.append("<tr><td>Avergae Wave Length:</td><td>" + metrics.averageWaveLength + "</td></tr>");
sb.append("<tr><td>Last Wave Length:</td><td>" + metrics.lastWaveLength + "</td></tr>");
sb.append("<tr><td>Max Wave Length:</td><td>" + metrics.maxWaveLength + "</td></tr>");
sb.append("<tr><td>Min Wave Length:</td><td>" + metrics.minWaveLength + "</td></tr>");
sb.append("<tr><td>Total Wave Length:</td><td>" + metrics.totalWaveLength + "</td></tr>");
sb.append("<tr><td>Last Receive Time:</td><td>" + metrics.lastMessageTime + "</td></tr>");
sb.append("<tr><td>Last Messsage:</td><td>" + metrics.lastMessage.msg + "</td></tr>");
sb.append("<tr><td>Time Series:</td><td>" + metrics.timeSeries + "</td></tr>");
sb.append("</table>");
doOutput(200, response, "EndPoint - Metrics", sb.toString());
} else {
doOutput(404, response, "EndPoint - Metrics", "Page not found");
}
}
protected void doList(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
Iterator<String> iter = metricsMap.keySet().iterator();
StringBuilder sb = new StringBuilder();
if (globalMessageCounter.get() > 0) {
sb.append("<b>Global Message Count: " + globalMessageCounter.get() + "</b><br/>");
}
if (metricsMap.size() == 0) {
sb.append("no messages<br/>");
} else {
sb.append("<table>");
sb.append("<tr><th>Row</th><th>ID</th><th>Metrics</th><th>Messages</th><th>Chart</th><th>Message Count</th><th>Last Message Received</th><th>Duplicates</th></tr>");
int rowNum = 1;
while (iter.hasNext()) {
String id = iter.next();
EndpointMetrics metrics = metricsMap.get(id);
sb.append("<tr>");
sb.append("<td>" + rowNum + "</td>");
sb.append("<td>" + id + "</td>");
sb.append("<td><a href=\"metrics/" + id + "\">metrics</a></td>");
sb.append("<td><a href=\"info/" + id + "\">messages</a></td>");
sb.append("<td><a href=\"chart/" + id + "\">chart</a></td>");
sb.append("<td>"+(metrics.messageCount-1)+"</td>");
sb.append("<td>"+metrics.lastMessageTime+"</td>");
sb.append("<td>"+(messageDuplicates.containsKey(id)?messageDuplicates.get(id):"")+"</td></tr>");
rowNum++;
}
sb.append("</table>");
}
doOutput(200, response, "EndPoint - List", sb.toString());
}
private List<EndpointMessage> getMessages(String id) {
return messageMap.get(id);
}
private EndpointMessage parseMessage(HttpServletRequest request) throws IOException {
EndpointMessage msg = new EndpointMessage();
String pathInfo = request.getPathInfo();
msg.id = pathInfo.substring(pathInfo.lastIndexOf("/")+1);
SimpleDateFormat fmt = new SimpleDateFormat("yy-MM-dd HH:mm:ss");
msg.host = request.getRemoteAddr() + "/" + request.getRemoteHost();
msg.recvOn = fmt.format(new Date());
msg.url = request.getRequestURL().toString();
msg.method = request.getMethod();
msg.msg = "";
if (msg.method.equals("POST")) {
BufferedReader reader = request.getReader();
String line;
while ((line = reader.readLine()) != null) {
msg.msg += line;
}
}
return msg;
}
protected void doReceiveMessage(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
globalMessageCounter.incrementAndGet();
EndpointMessage msg = parseMessage(request);
// obey error behavior only after first message (typically subscription confirmation request) was received successfully
if (request.getParameter("errorCode") != null && messageMap.containsKey(msg.id)) {
int errorCode = Integer.parseInt(request.getParameter("errorCode"));
double chance = 1.0;
if (request.getParameter("chance") != null) {
chance = Double.parseDouble(request.getParameter("chance"));
}
if (rand.nextDouble() <= chance) {
doOutput(errorCode, response, "Failed", "Failed");
return;
}
}
if (request.getParameter("delayMS") != null && messageMap.containsKey(msg.id)) {
long delayMS = Integer.parseInt(request.getParameter("delayMS"));
double chance = 1.0;
if (request.getParameter("chance") != null) {
chance = Double.parseDouble(request.getParameter("chance"));
}
if (rand.nextDouble() <= chance) {
try {
Thread.sleep(delayMS);
} catch (Exception ex) {
throw new ServletException(ex);
}
}
}
if (request.getParameter("numResponseBytes") != null && messageMap.containsKey(msg.id)) {
int numResponseBytes = Integer.parseInt(request.getParameter("numResponseBytes"));
double chance = 1.0;
if (request.getParameter("chance") != null) {
chance = Double.parseDouble(request.getParameter("chance"));
}
if (rand.nextDouble() <= chance) {
char[] bytes = new char[numResponseBytes];
Arrays.fill(bytes, 'A');
doRawOutput(200, response, bytes);
return;
}
}
/*if (failureConfigMap.containsKey(msg.id)) {
EndpointFailureConfiguration failureConfig = failureConfigMap.get(msg.id);
logger.info("[doReceiveMessage] currentFailureCounter="+failureConfig.currentFailureCounter+" numFailuresBeforeSuccess="+failureConfig.numFailuresBeforeSuccess);
if (failureConfig.currentFailureCounter < failureConfig.numFailuresBeforeSuccess) {
failureConfig.currentFailureCounter++;
msg.failure = true;
logger.info("[doReceiveMessage] event=failedResponse");
doOutput(failureConfig.httpErrorCode, response, "Failed", "Failed");
return;
}
}*/
Enumeration<String> headerNames = request.getHeaderNames();
String header = "";
while(headerNames.hasMoreElements()) {
String headerName = (String)headerNames.nextElement();
header += headerName + ": " + request.getHeader(headerName) + "\n";
}
msg.httpHeader = header;
addMessage(msg);
//logger.info("event=received_message status_code=200 msg_id=" + msg.id);
doOutput(200, response, "Ok", "Ok");
}
private String formatMessage(String str) {
//Escape the "<" and ">" characters
String fmtMsg = str.replace("<", "<");
fmtMsg = fmtMsg.replace(">", ">");
//pretty print json
try {
JSONObject json = new JSONObject(fmtMsg);
fmtMsg = json.toString(2);
} catch (Exception ex) {
//not a json string
}
return fmtMsg;
}
protected void doDisplayMessages(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String pathInfo = request.getPathInfo();
String id = pathInfo.substring(pathInfo.lastIndexOf("/")+1);
if (id.toLowerCase().startsWith("info")) {
doOutput(404, response, "EndPoint - Display Message", "Please provide an id");
return;
}
List<EndpointMessage> messages = getMessages(id);
if (messages == null || messages.size() == 0) {
doOutput(200, response, "EndPoint - Display Messages", "No messages");
return;
}
String showLastStr = request.getParameter("showLast");
boolean onlyShowLast = (showLastStr != null && showLastStr.equals("true"));
String output = "<table border=\"1\">";
synchronized (messages) {
for (EndpointMessage msg : messages) {
output += "<tr><td>Time Recv: "+msg.recvOn+"<br/>";
output += "Url: "+msg.url+"<br/>";
output += "Method: "+msg.method+"<br/>";
output += "Host: "+msg.host+"<br/>";
output += "<b>Header</b><br/>";
output += msg.httpHeader.replace("\n", "<br/>");
/*if (msg.failure) {
output += "FAILED (HTTP " + failureConfigMap.get(msg.id).httpErrorCode + ")<br/>";
}*/
if (msg.msg != null && msg.msg.length() > 0) {
output += "<pre>"+formatMessage(msg.msg)+"</pre><br/>";
}
output += "</td></tr>";
if (onlyShowLast) {
doRawOutput(200, response, msg.msg);
return;
}
}
}
output += "</table>";
doOutput(200, response, "EndPoint - Display Messages", output);
}
protected void doOutput(int httpCode, HttpServletResponse response, String title, String body) throws IOException {
response.setContentType("text/html");
response.setStatus(httpCode);
PrintWriter out = response.getWriter();
out.println("<html>");
out.println("<head><title>"+title+"</title></head><body>");
out.println(body);
out.println("</body></html>");
}
protected void doRawOutput(int httpCode, HttpServletResponse response, String msg) throws IOException {
response.setContentType("text/plain");
response.setStatus(httpCode);
PrintWriter out = response.getWriter();
out.print(msg);
}
protected void doRawOutput(int httpCode, HttpServletResponse response, char[] bytes) throws IOException {
response.setContentType("text/plain");
response.setStatus(httpCode);
PrintWriter out = response.getWriter();
out.print(bytes);
}
private byte[] generateChart(EndpointMetrics metric, String id) throws IOException {
XYSeries series = new XYSeries("Test Run");
for (int i=0; i<metric.timeSeries.size(); i++) {
series.add(i, metric.timeSeries.get(i));
}
XYSeriesCollection dataset = new XYSeriesCollection(series);
JFreeChart chart = ChartFactory.createXYBarChart(
"Start: " + metric.startTime + " End: " + metric.endTime + " Message Count: " + metric.messageCount,
"Test Second",
false,
"Number of Messages",
dataset,
PlotOrientation.VERTICAL,
true,
true,
false
);
//File file = new File(getServletContext().getRealPath("WEB-INF" + "/" + id + ".jpeg"));
//ChartUtilities.saveChartAsJPEG(file, chart, 1600, 400);
//byte b[] = Files.toByteArray(file);
//return b;
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ChartUtilities.writeChartAsJPEG(bos, chart, 2400, 400);
return bos.toByteArray();
}
}