/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

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