/tags/1.1/src/main/java/flowersinthesand/example/HttpChatServlet.java
Java | 152 lines | 114 code | 27 blank | 11 comment | 7 complexity | 45a34ad8e71183c04ce505718940f3d0 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.http.HttpServlet; 18import javax.servlet.http.HttpServletRequest; 19import javax.servlet.http.HttpServletResponse; 20 21import com.google.gson.Gson; 22 23public class HttpChatServlet extends HttpServlet { 24 25 private static final long serialVersionUID = -8823775068689773674L; 26 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 } catch (InterruptedException e) { 49 done = true; 50 } 51 } 52 } 53 }); 54 55 @Override 56 public void init(ServletConfig config) throws ServletException { 57 super.init(config); 58 notifier.start(); 59 } 60 61 @Override 62 public void destroy() { 63 messages.clear(); 64 asyncContexts.clear(); 65 notifier.interrupt(); 66 } 67 68 /* HTTP Streaming powered by Servlet 3.0 */ 69 private Map<String, AsyncContext> asyncContexts = new ConcurrentHashMap<String, AsyncContext>(); 70 71 // GET method is used to open stream 72 @Override 73 protected void doGet(HttpServletRequest request, HttpServletResponse response) 74 throws ServletException, IOException { 75 // Wrong access 76 if ("websocket".equalsIgnoreCase(request.getHeader("Upgrade"))) { 77 response.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED); 78 return; 79 } 80 81 response.setCharacterEncoding("utf-8"); 82 83 // Content-Type header 84 response.setContentType("text/plain"); 85 86 // Access-Control-Allow-Origin header 87 response.setHeader("Access-Control-Allow-Origin", "*"); 88 89 PrintWriter writer = response.getWriter(); 90 91 // Id 92 final String id = UUID.randomUUID().toString(); 93 writer.print(id); 94 writer.print(';'); 95 96 // Padding 97 for (int i = 0; i < 1024; i++) { 98 writer.print(' '); 99 } 100 writer.print(';'); 101 writer.flush(); 102 103 final AsyncContext ac = request.startAsync(); 104 ac.setTimeout(5 * 60 * 1000); 105 ac.addListener(new AsyncListener() { 106 public void onComplete(AsyncEvent event) throws IOException { 107 asyncContexts.remove(id); 108 } 109 110 public void onTimeout(AsyncEvent event) throws IOException { 111 asyncContexts.remove(id); 112 } 113 114 public void onError(AsyncEvent event) throws IOException { 115 asyncContexts.remove(id); 116 } 117 118 public void onStartAsync(AsyncEvent event) throws IOException { 119 120 } 121 }); 122 asyncContexts.put(id, ac); 123 } 124 125 // POST method is used to handle data sent by user through the stream 126 @Override 127 protected void doPost(HttpServletRequest request, HttpServletResponse response) 128 throws ServletException, IOException { 129 request.setCharacterEncoding("utf-8"); 130 131 if ("close".equals(request.getParameter("metadata.type"))) { 132 AsyncContext ac = asyncContexts.get(request.getParameter("metadata.id")); 133 if (ac != null) { 134 ac.complete(); 135 } 136 137 return; 138 } 139 140 // Handles data sent from a client 141 Map<String, String> data = new LinkedHashMap<String, String>(); 142 data.put("username", request.getParameter("username")); 143 data.put("message", request.getParameter("message")); 144 145 try { 146 messages.put(new Gson().toJson(data)); 147 } catch (InterruptedException e) { 148 throw new IOException(e); 149 } 150 } 151 152}