Skip to content

Instantly share code, notes, and snippets.

@john77eipe
Created August 24, 2016 09:00
Show Gist options
  • Save john77eipe/95805440a3b8f94a266bf69ee11ee67a to your computer and use it in GitHub Desktop.
Save john77eipe/95805440a3b8f94a266bf69ee11ee67a to your computer and use it in GitHub Desktop.
/**
* Basic version
* @author johne
*
*/
@WebServlet(urlPatterns = "/Weather/v1", asyncSupported = true)
public class WeatherDataStream extends HttpServlet {
private static final long serialVersionUID = 1L;
// Keeps all open connections from browsers
private Set<AsyncContext> asyncContexts = new HashSet<AsyncContext>();
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// Check that it is SSE request
if ("text/event-stream".equals(request.getHeader("Accept"))) {
log("--SSE REQUEST--");
// send streaming data to all open connections
// Set header fields
response.setContentType("text/event-stream");
response.setHeader("Cache-Control", "no-cache");
response.setHeader("Connection", "keep-alive");
response.setCharacterEncoding("UTF-8");
// Start asynchronous context and add listeners to remove it in case
// of errors
final AsyncContext ac = request.startAsync();
ac.addListener(new AsyncListener() {
@Override
public void onComplete(AsyncEvent event) throws IOException {
log("--ASYNC EVENT COMPLETE-- ");
asyncContexts.remove(event.getAsyncContext());
}
@Override
public void onError(AsyncEvent event) throws IOException {
log("--ASYNC EVENT ERROR--");
asyncContexts.remove(event.getAsyncContext());
}
@Override
public void onStartAsync(AsyncEvent event) throws IOException {
log("--ASYNC EVENT START--");
}
@Override
public void onTimeout(AsyncEvent event) throws IOException {
log("--ASYNC EVENT TIMEOUT--");
asyncContexts.remove(event.getAsyncContext());
}
});
// Put context in a map
asyncContexts.add(ac);
log("Event Registration for connection obj: "+ac.toString());
}
}
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
log("--WEATHER POST DATA RECEIVED--");
log("Current set of connections: " + asyncContexts);
WeatherToken token = new WeatherToken(request.getParameter("city"), request.getParameter("temp"));
// Sends the message to all the asyncContext's response
for (AsyncContext asyncContext : asyncContexts) {
log("Sending MSG to connection obj: " + asyncContext);
boolean errorStatus = sendMessage(asyncContext.getResponse().getWriter(), token);
if (errorStatus) {
throw new RuntimeException("Connection closed by client");
}
}
}
private boolean sendMessage(PrintWriter writer, WeatherToken token) {
writer.println("event: city");
writer.print("data: ");
writer.println(token.getType()+":"+token.getData());
writer.println(); //new line marks an event boundary
return writer.checkError(); //checkError() calls writer.flush();
}
@Override
public void destroy() {
log("--SERVLET DESTROYED--");
for(AsyncContext asyncContext: asyncContexts){
asyncContext.complete();
}
super.destroy();
}
@Override
public void init(ServletConfig config) throws ServletException {
log("--SERVLET INITIALIZED--");
super.init(config);
}
public void log(String output) {
System.out.println(LocalDateTime.now() +" [" + Thread.currentThread().getName() + "]" + output);
}
}
class WeatherToken {
private String tokenType;
private String tokenValue;
public WeatherToken(String data, String type) {
this.tokenValue = data;
this.tokenType = type;
}
public String getType() {
return tokenType;
}
public String getData() {
return tokenValue;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment