package ddth.dasp.temp; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.List; import java.util.Random; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.catalina.comet.CometEvent; import org.apache.catalina.comet.CometProcessor; public class ChatServlet extends HttpServlet implements CometProcessor { private static final long serialVersionUID = 1L; protected List<HttpServletResponse> connections = new ArrayList<HttpServletResponse>(); protected MessageSender messageSender = null; protected Thread randomMsg; public void init() throws ServletException { messageSender = new MessageSender(); Thread messageSenderThread = new Thread(messageSender, "MessageSender[" + getServletContext().getContextPath() + "]"); messageSenderThread.setDaemon(true); messageSenderThread.start(); randomMsg = new Thread() { private Random rand = new Random(); private long counter = 0; public void run() { while (!isInterrupted()) { messageSender.send("test", "Message: " + counter); counter++; try { Thread.sleep(Math.abs(rand.nextInt() % 10000)); } catch (InterruptedException e) { e.printStackTrace(); } } } }; randomMsg.setDaemon(true); randomMsg.start(); } public void destroy() { messageSender.stop(); messageSender = null; randomMsg.interrupt(); randomMsg = null; connections.clear(); } private void writeData(HttpServletResponse response, String data) throws IOException { response.getWriter().print(data); response.getWriter().flush(); // response.getWriter().close(); // response.getOutputStream().print(data); // response.getOutputStream().flush(); // response.flushBuffer(); } @Override public void event(CometEvent event) throws IOException, ServletException { HttpServletRequest request = event.getHttpServletRequest(); HttpServletResponse response = event.getHttpServletResponse(); if (event.getEventType() == CometEvent.EventType.BEGIN) { event.setTimeout(24 * 3600); log("Begin for session: " + request.getSession(true).getId()); String msg = "<!doctype html public \"-//w3c//dtd html 4.0 transitional//en\">"; msg += "<head><title>JSP Chat</title></head><body bgcolor=\"#FFFFFF\">"; msg += "<div id=\"msg\"></div>"; response.setBufferSize(0); writeData(response, msg); synchronized (connections) { connections.add(response); } } else if (event.getEventType() == CometEvent.EventType.ERROR) { log("Error [" + event.getEventSubType() + "] for session: " + request.getSession(true).getId()); synchronized (connections) { connections.remove(response); } event.close(); } else if (event.getEventType() == CometEvent.EventType.END) { log("End for session: " + request.getSession(true).getId()); synchronized (connections) { connections.remove(response); } String msg = "</body></html>"; writeData(response, msg); event.close(); } else if (event.getEventType() == CometEvent.EventType.READ) { InputStream is = request.getInputStream(); byte[] buf = new byte[512]; do { int n = is.read(buf); // can throw an IOException if (n > 0) { log("Read " + n + " bytes: " + new String(buf, 0, n) + " for session: " + request.getSession(true).getId()); } else if (n < 0) { // error(event, request, response); return; } } while (is.available() > 0); } } public class MessageSender implements Runnable { protected boolean running = true; protected ArrayList<String> messages = new ArrayList<String>(); public MessageSender() { } public void stop() { running = false; } /** * Add message for sending. */ public void send(String user, String message) { String msg = "[" + user + "]: " + message; log("Sending message: " + msg); synchronized (messages) { messages.add(msg); messages.notify(); } } public void run() { while (running) { if (messages.size() == 0) { try { synchronized (messages) { messages.wait(); } } catch (InterruptedException e) { // Ignore } } synchronized (connections) { String[] pendingMessages = null; synchronized (messages) { pendingMessages = messages.toArray(new String[0]); messages.clear(); } log("Sending " + pendingMessages.length + " messages to " + connections.size() + " clients."); // Send any pending message on all the open connections for (HttpServletResponse response : connections) { try { for (String msg : pendingMessages) { writeData(response, msg); } } catch (IOException e) { log("IOExeption sending message", e); } } } } } } }