package org.crosswire.community.events; import java.io.IOException; import java.io.InputStream; import java.io.PrintWriter; import java.net.URL; import java.util.ArrayList; import java.util.List; import javax.servlet.ServletException; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.catalina.CometEvent; import org.apache.catalina.CometProcessor; public class EventBus extends HttpServlet implements CometProcessor { private MessageSender messageSender = null; private static final Integer TIMEOUT = 60 * 1000; @Override public void destroy() { messageSender.running = false; messageSender = null; } @Override public void init() throws ServletException { messageSender = new MessageSender(); Thread messageSenderThread = new Thread(messageSender, "MessageSender[" + getServletContext().getContextPath() + "]"); messageSenderThread.setDaemon(true); messageSenderThread.start(); } public void event(final CometEvent event) throws IOException, ServletException { HttpServletRequest request = event.getHttpServletRequest(); HttpServletResponse response = event.getHttpServletResponse(); if (event.getEventType() == CometEvent.EventType.BEGIN) { request.setAttribute("org.apache.tomcat.comet.timeout", TIMEOUT); log("Begin for session: " + request.getSession(true).getId()); messageSender.setConnection(response); Weatherman weatherman = new Weatherman(95118, 32408); new Thread(weatherman).start(); } else if (event.getEventType() == CometEvent.EventType.ERROR) { log("Error for session: " + request.getSession(true).getId()); event.close(); } else if (event.getEventType() == CometEvent.EventType.END) { log("End for session: " + request.getSession(true).getId()); event.close(); } else if (event.getEventType() == CometEvent.EventType.READ) { throw new UnsupportedOperationException("This servlet does not accept data"); } } private class MessageSender implements Runnable { protected boolean running = true; protected final ArrayList messages = new ArrayList(); private ServletResponse connection; private synchronized void setConnection(ServletResponse connection){ this.connection = connection; notify(); } public void send(String message) { synchronized (messages) { messages.add(message); log("Message added #messages=" + messages.size()); messages.notify(); } } public void run() { while (running) { if (messages.size() == 0) { try { synchronized (messages) { messages.wait(); } } catch (InterruptedException e) { // Ignore } } String[] pendingMessages = null; synchronized (messages) { pendingMessages = messages.toArray(new String[0]); messages.clear(); } try { if (connection == null){ try{ synchronized(this){ wait(); } } catch (InterruptedException e){ // Ignore } } PrintWriter writer = connection.getWriter(); for (int j = 0; j < pendingMessages.length; j++) { final String forecast = pendingMessages[j] + "
"; writer.println(forecast); log("Writing:" + forecast); } writer.flush(); writer.close(); connection = null; log("Closing connection"); } catch (IOException e) { log("IOExeption sending message", e); } } } } private class Weatherman implements Runnable{ private final List zipCodes; private final String YAHOO_WEATHER = "http://weather.yahooapis.com/forecastrss?p="; public Weatherman(Integer... zips) { zipCodes = new ArrayList(zips.length); for (Integer zip : zips) { try { zipCodes.add(new URL(YAHOO_WEATHER + zip)); } catch (Exception e) { // dont add it if it sucks } } } public void run() { int i = 0; while (i >= 0) { int j = i % zipCodes.size(); try { URL zipUrl = zipCodes.get(j); messageSender.send(zipUrl.toString()); Thread.sleep(30000L); } catch (Exception e) { // just eat it, eat it } i++; } } } /* private void log(String msg) { System.err.println(msg); } private void log(String msg, Exception e) { System.err.println(msg + e.toString()); } */ }