package com.redhat.gss.comet; import java.util.ArrayList; import java.util.List; import java.io.IOException; import java.io.PrintWriter; import java.io.InputStream; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServlet; import javax.servlet.ServletException; import org.jboss.logging.Logger; import org.jboss.servlet.http.HttpEventServlet; import org.jboss.servlet.http.HttpEvent; public class ChatServlet extends HttpServlet implements HttpEventServlet { protected ArrayList<HttpServletResponse> connections = new ArrayList<HttpServletResponse>(); protected MessageSender messageSender = null; private Logger log = Logger.getLogger(this.getClass()); public void init() throws ServletException { messageSender = new MessageSender(); Thread messageSenderThread = new Thread(messageSender, "MessageSender[" + getServletContext().getContextPath() + "]"); messageSenderThread.setDaemon(true); messageSenderThread.start(); } public void destroy() { connections.clear(); messageSender.stop(); messageSender = null; } public void event(HttpEvent event) throws IOException, ServletException { event.setTimeout(30000); HttpServletRequest request = event.getHttpServletRequest(); HttpServletResponse response = event.getHttpServletResponse(); if (event.getType() == HttpEvent.EventType.BEGIN) { log.info("Stack trace", new Exception("stack trace")); log.info("Begin for session: " + request.getSession(true).getId()); PrintWriter writer = response.getWriter(); writer.println("<!doctype html public \"-//w3c//dtd html 4.0 transitional//en\">"); writer.println("<head><title>JSP Chat</title></head><body bgcolor=\"#FFFFFF\">"); writer.flush(); synchronized(connections) { connections.add(response); } } else if (event.getType() == HttpEvent.EventType.ERROR) { log.info("Error for session: " + request.getSession(true).getId()); synchronized(connections) { connections.remove(response); } event.close(); } else if (event.getType() == HttpEvent.EventType.END || event.getType() == HttpEvent.EventType.TIMEOUT) { log.info("End for session: " + request.getSession(true).getId()); synchronized(connections) { connections.remove(response); } PrintWriter writer = response.getWriter(); writer.println("</body></html>"); event.close(); } else if (event.getType() == HttpEvent.EventType.READ) { InputStream is = request.getInputStream(); byte[] buf = new byte[512]; do { int n = is.read(buf); //can throw an IOException if (n > 0) { String s = new String(buf, 0, n) ; String session = request.getSession(true).getId(); log.info("Read " + n + " bytes: " + s + " for session: " + session); messageSender.send(session, s); } else if (n < 0) { log.error("Didn't read anything from the stream"); return; } } while (is.available() > 0); } else { log.info("Other event: " + event.getType()); } } 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) { synchronized (messages) { messages.add("[" + user + "]: " + message); 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(); } // Send any pending message on all the open connections for (int i = 0; i < connections.size(); i++) { try { PrintWriter writer = connections.get(i).getWriter(); for (int j = 0; j < pendingMessages.length; j++) { writer.println(pendingMessages[j] + "<br>"); } writer.flush(); } catch (IOException e) { log.info("IOExeption sending message", e); } } } } } } }