/* vim: set ts=2 et sw=2 cindent fo=qroca: */
package com.globant.katari.core.ping;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Date;
import java.util.List;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
/** Servlet that runs a smoke test to check if the application has started
* successfully.
*
* It loads a bean from the spring web application context. By default this
* bean is called 'katari.pingServices'. This bean is a list of PingService
* implementations. This servlet pings each service and reports the results in
* plain text to the web client.
*
* The output includes lines of the form:
*
* Testing "service name': status'.
*
* with a last line of the form:
*
* Application started successfully.
*
* or
*
* Application startup failed.
*
* This allows the user to simply grep for the the output to run a quick test
* to check if the application is running.
*
* Given that some tests can be relatively expensive, and the page is not
* secured, this servlet caches the result of the pings for 30 seconds.
*/
public class PingServlet extends HttpServlet {
/** The version id for this serializable class.
*/
private static final long serialVersionUID = 1;
/** The number of milliseconds that the ping result is cached for.
*/
private static final long CACHE_TIMEOUT_MILLIS = 30000;
/** The last time the ping operations where called, or the epoch if never
* called.
*/
private Date lastCalled = new Date(0);
/** The result of the last call to the ping operations, null if never called.
*/
private String lastResult = null;
/** This method checks the application status.
*
* @param request The HTTP request we are processing.
*
* @param response The HTTP response we are processing.
*
* @throws IOException in case of error writing to the client.
*/
protected final void service(final HttpServletRequest request,
final HttpServletResponse response) throws IOException {
response.setContentType("text/plain");
if (lastCalled.getTime() + CACHE_TIMEOUT_MILLIS < new Date().getTime()) {
lastResult = doPingServices().toString();
lastCalled = new Date();
}
PrintWriter out = response.getWriter();
try {
out.println(lastResult);
} finally {
if (out != null) {
out.close();
}
}
}
/** Executes all the ping services and generates a StringBuilder with the
* result.
*
* @return a StringBuilder with the result of executing all ping operations
* in the ping services.
*/
private StringBuilder doPingServices() {
boolean isOk = true;
StringBuilder output = new StringBuilder();
List<PingService> services = getPingServices();
if (services == null) {
output.append("Loading spring context: FAIL\n");
} else {
output.append("Loading spring context: SUCCESS\n");
for (final PingService service : services) {
PingResult result = service.ping();
output.append(result.getMessage() + "\n");
if (!result.isOk()) {
isOk = false;
}
}
}
if (isOk) {
output.append("Application started successfully");
} else {
output.append("Application startup failed");
}
return output;
}
/** Gets the ping service from the spring web application context.
*
* @return the list of ping services or null if an error ocurred.
*/
@SuppressWarnings("unchecked")
private List<PingService> getPingServices() {
List<PingService> services = null;
WebApplicationContext context = WebApplicationContextUtils
.getWebApplicationContext(getServletContext());
if (context != null) {
services = (List<PingService>) context.getBean("katari.pingServices");
}
return services;
}
}