PageRenderTime 49ms CodeModel.GetById 22ms RepoModel.GetById 1ms app.codeStats 0ms

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

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