PageRenderTime 27ms CodeModel.GetById 18ms app.highlight 6ms RepoModel.GetById 1ms app.codeStats 0ms

/trunk/src/main/java/flowersinthesand/example/HttpChatServlet.java

http://jquery-stream.googlecode.com/
Java | 154 lines | 116 code | 27 blank | 11 comment | 7 complexity | 5afd4bea525eebf25efa68e287bc51dd MD5 | raw file
  1package flowersinthesand.example;
  2
  3import java.io.IOException;
  4import java.io.PrintWriter;
  5import java.util.LinkedHashMap;
  6import java.util.Map;
  7import java.util.UUID;
  8import java.util.concurrent.BlockingQueue;
  9import java.util.concurrent.ConcurrentHashMap;
 10import java.util.concurrent.LinkedBlockingQueue;
 11
 12import javax.servlet.AsyncContext;
 13import javax.servlet.AsyncEvent;
 14import javax.servlet.AsyncListener;
 15import javax.servlet.ServletConfig;
 16import javax.servlet.ServletException;
 17import javax.servlet.annotation.WebServlet;
 18import javax.servlet.http.HttpServlet;
 19import javax.servlet.http.HttpServletRequest;
 20import javax.servlet.http.HttpServletResponse;
 21
 22import com.google.gson.Gson;
 23
 24@WebServlet(urlPatterns = "/example/httpchat", asyncSupported = true)
 25public class HttpChatServlet extends HttpServlet {
 26
 27	private static final long serialVersionUID = -8823775068689773674L;
 28
 29	/* Common */
 30	private BlockingQueue<String> messages = new LinkedBlockingQueue<String>();
 31	private Thread notifier = new Thread(new Runnable() {
 32		public void run() {
 33			boolean done = false;
 34			while (!done) {
 35				try {
 36					String message = messages.take();
 37					for (AsyncContext asyncContext : asyncContexts.values()) {
 38						try {
 39							// Message
 40							PrintWriter writer = asyncContext.getResponse().getWriter();
 41							writer.print(message.length());
 42							writer.print(";");
 43							writer.print(message);
 44							writer.print(";");
 45							writer.flush();
 46						} catch (Exception e) {
 47							asyncContexts.values().remove(asyncContext);
 48						}
 49					}
 50				} catch (InterruptedException e) {
 51					done = true;
 52				}
 53			}
 54		}
 55	});
 56
 57	@Override
 58	public void init(ServletConfig config) throws ServletException {
 59		super.init(config);
 60		notifier.start();
 61	}
 62
 63	@Override
 64	public void destroy() {
 65		messages.clear();
 66		asyncContexts.clear();
 67		notifier.interrupt();
 68	}
 69
 70	/* HTTP Streaming powered by Servlet 3.0 */
 71	private Map<String, AsyncContext> asyncContexts = new ConcurrentHashMap<String, AsyncContext>();
 72
 73	// GET method is used to open stream
 74	@Override
 75	protected void doGet(HttpServletRequest request, HttpServletResponse response)
 76			throws ServletException, IOException {
 77		// Wrong access
 78		if ("websocket".equalsIgnoreCase(request.getHeader("Upgrade"))) {
 79			response.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED);
 80			return;
 81		}
 82
 83		response.setCharacterEncoding("utf-8");
 84
 85		// Content-Type header
 86		response.setContentType("text/plain");
 87
 88		// Access-Control-Allow-Origin header
 89		response.setHeader("Access-Control-Allow-Origin", "*");
 90
 91		PrintWriter writer = response.getWriter();
 92
 93		// Id
 94		final String id = UUID.randomUUID().toString();
 95		writer.print(id);
 96		writer.print(';');
 97
 98		// Padding
 99		for (int i = 0; i < 1024; i++) {
100			writer.print(' ');
101		}
102		writer.print(';');
103		writer.flush();
104
105		final AsyncContext ac = request.startAsync();
106		ac.setTimeout(5 * 60 * 1000);
107		ac.addListener(new AsyncListener() {
108			public void onComplete(AsyncEvent event) throws IOException {
109				asyncContexts.remove(id);
110			}
111
112			public void onTimeout(AsyncEvent event) throws IOException {
113				asyncContexts.remove(id);
114			}
115
116			public void onError(AsyncEvent event) throws IOException {
117				asyncContexts.remove(id);
118			}
119
120			public void onStartAsync(AsyncEvent event) throws IOException {
121
122			}
123		});
124		asyncContexts.put(id, ac);
125	}
126
127	// POST method is used to handle data sent by user through the stream
128	@Override
129	protected void doPost(HttpServletRequest request, HttpServletResponse response)
130			throws ServletException, IOException {
131		request.setCharacterEncoding("utf-8");
132
133		if ("close".equals(request.getParameter("metadata.type"))) {
134			AsyncContext ac = asyncContexts.get(request.getParameter("metadata.id"));
135			if (ac != null) {
136				ac.complete();
137			}
138
139			return;
140		}
141
142		// Handles data sent from a client
143		Map<String, String> data = new LinkedHashMap<String, String>();
144		data.put("username", request.getParameter("username"));
145		data.put("message", request.getParameter("message"));
146
147		try {
148			messages.put(new Gson().toJson(data));
149		} catch (InterruptedException e) {
150			throw new IOException(e);
151		}
152	}
153
154}