package net.spy.diggwatch; import java.io.IOException; import java.util.Collection; import java.util.Enumeration; import java.util.HashSet; import javax.servlet.ServletConfig; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.UnavailableException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.google.inject.Inject; import com.google.inject.Injector; import com.google.inject.name.Named; import net.spy.digg.Event; import net.spy.jwebkit.xml.XMLOutputServlet; /** * Base REST servlet stuff. */ public abstract class BaseDiggServlet extends XMLOutputServlet { protected @Inject DiggInterface di; protected @Inject @Named("tree.version") String treeVersion; private String etagBase=null; @Override public void init(ServletConfig conf) throws ServletException { super.init(conf); ServletContext servletContext = conf.getServletContext(); Injector injector = (Injector) servletContext.getAttribute(ContextListener.INJECTOR_NAME); if (injector == null) { throw new UnavailableException("No guice injector found"); } injector.injectMembers(this); etagBase = treeVersion.split(" ")[0]; } @Override protected final void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { String pi=req.getPathInfo(); if(pi == null || pi.trim().length() == 0 || pi.equals("/")) { getLogger().info("No path info"); res.sendRedirect("/diggwatch/"); } else { assert pi.startsWith("/"); String path=pi.substring(1).trim(); @SuppressWarnings("unchecked") // generic enum Enumeration<String> etagsEnum = req.getHeaders("If-None-Match"); Collection<String> eTags=new HashSet<String>(); // I generally hate reinventing for loops, but I needed the @suppress while(etagsEnum.hasMoreElements()) { eTags.add(etagsEnum.nextElement()); } try { String eTag=getEtag(path); if(eTag == null) { processPath(path, req, res); } else { eTag = etagBase + "-" + eTag; if(eTags.contains(eTag)) { res.setStatus(HttpServletResponse.SC_NOT_MODIFIED); } else { res.setHeader("ETag", eTag); processPath(path, req, res); } } } catch(Exception e) { throw new ServletException("Error processing path " + path, e); } } } /** * Compute an etag from the given ordered collection of events. */ protected String getEtagFromEvents(Collection<? extends Event> events) { String rv="0"; if(!events.isEmpty()) { Event event=events.iterator().next(); rv=event.getTimestamp() / 1000 + "-" + event.getEventId(); } return rv; } /** * Process the given path. */ protected abstract void processPath(String path, HttpServletRequest req, HttpServletResponse res) throws Exception; /** * Get the etag for the given path. */ protected abstract String getEtag(String path) throws Exception; }