package de.tutorials.app.web.example;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@SuppressWarnings("serial")
@WebServlet(name = "service", urlPatterns = "/service")
public class ServiceServlet extends HttpServlet {
@Override
public void init(ServletConfig config) throws ServletException {
super.init(config);
//TODO for the sake of brevity ...
//normally one should store the processing state somewhere else...
getServletContext().setAttribute("processingState",new ConcurrentHashMap<String, Future<String>>());
}
@SuppressWarnings("unchecked")
private ConcurrentMap<String, Future<String>> getProcessingStateMap() {
return (ConcurrentMap<String, Future<String>>) getServletContext().getAttribute("processingState");
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String requestIds = req.getParameter("rids");
String operation = req.getParameter("op");
String callback = req.getParameter("cb");
String clientId = req.getParameter("cid");
//TODO validate parameters
if ("statusUpdate".equals(operation)) {
computeStatusUpdate(resp, requestIds, callback, clientId);
} else if ("startProcessing".equals(operation)) {
String requestId = requestIds; // we expect just a single requestId;
startNewTask(requestId, clientId);
} else if ("cancelTask".equals(operation)) {
String requestId = requestIds; // we expect just a single requestId;
cancelTask(resp, requestId, callback, clientId);
}
}
private void cancelTask(HttpServletResponse resp, String requestId, String callback, String clientId) throws IOException {
Future<String> future = getProcessingStateMap().get(requestId);
if (future != null && !future.isDone()) {
log("Cancelling Task request: " + requestId);
future.cancel(true);
getProcessingStateMap().remove(requestId);
writeStatusResponse(resp.getWriter(), requestId, "cancelled", callback,false);
}
}
private void startNewTask(String requestId, String clientId) {
log("Starting new Task request: " + requestId + " sent by: " + clientId);
ExecutorService executor = Executors.newSingleThreadExecutor();
getProcessingStateMap().put(requestId,executor.submit(newTaskWithRadomDurationMax(20, TimeUnit.SECONDS, requestId)));
executor.shutdown();
}
private void computeStatusUpdate(HttpServletResponse resp, String requestIds, String callback, String clientId) throws IOException {
if (requestIds == null || requestIds.length() == 0) {
writeStatusResponse(resp.getWriter(), "bad request", "unknown", callback, false);
return;
}
for (String requestId : requestIds.trim().split(";")) {
Future<String> future = getProcessingStateMap().get(requestId);
StringWriter s = new StringWriter();
PrintWriter out = new PrintWriter(s);
if (future == null) {
writeStatusResponse(out, requestId, "unknown", callback,false);
} else {
log("Checking for Task request: " + requestId + " done: " + future.isDone()+ " sent by: " + clientId);
if (future.isDone()) {
getProcessingStateMap().remove(requestId);
writeStatusResponse(out, requestId, "completed", callback,true);
} else {
writeStatusResponse(out, requestId, "running", callback,true);
}
}
resp.getWriter().println(s.toString());
}
}
private Callable<String> newTaskWithRadomDurationMax(final int amount, final TimeUnit timeUnit, final String requestId) {
return new Callable<String>() {
@Override
public String call() throws Exception {
log("Task request: " + requestId + " completed in Thread: "
+ Thread.currentThread());
int millisToSleepPerIteration = 1000;
long n = timeUnit.toMillis(amount) / millisToSleepPerIteration ; // divide the waiting
// time in 1 Second
// intervals, so
// that we can
// simulate
// progress...
for (int i = 0; i < n; i++) {
TimeUnit.MILLISECONDS.sleep(millisToSleepPerIteration);
log("Processing Task request: " + requestId
+ " completed in Thread: " + Thread.currentThread());
}
return requestId;
}
};
}
private void writeStatusResponse(PrintWriter out, String requestId, String status, String callback, boolean cancellable) throws IOException {
out.println("<script type='text/javascript'>parent." + callback + "('" + requestId + "','" + status + "'," + cancellable + ");</script>");
}
}