/tags/1.1.1/src/main/java/flowersinthesand/example/HttpChatServlet.java

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