package org.madore.damlengine; import java.util.regex.Pattern; import java.util.regex.Matcher; import java.util.Properties; import java.util.Enumeration; import java.io.IOException; import java.io.OutputStream; import java.nio.file.Paths; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /* Thinkos about the mess that is tomcat: * - Make sure that /usr/share/java/postgresql-jdbc3.jar (or whatever * contains the class org.postgresql.Driver) is symlinked from * /var/lib/tomcat7/common (or some path listed in the common.loader * property of the catalina.properties file). Similarly, * xercesImpl.jar and probably xml-resolver.jar need to be linked. * - The following parameters need to be defined in tags * inside the block: base_path, template_path, pghost, * pgport, dbname, pguser and pgpass or pgpassfile. */ public class WeblogServlet extends HttpServlet { private static final long serialVersionUID = 2014100704L; @Override public void init(ServletConfig cfg) throws ServletException { super.init(cfg); // Important! synchronized ( DamlEngine.class ) { if ( DamlEngine.appProps == null ) { DamlEngine.runAsServlet = true; DamlEngine.appProps = new Properties(); for (Enumeration e = cfg.getInitParameterNames() ; e.hasMoreElements() ; ) { String k = e.nextElement(); DamlEngine.appProps.setProperty(k, cfg.getInitParameter(k)); } if ( DamlEngine.appProps.getProperty("base_path") != null ) DamlEngine.basePath = Paths.get(DamlEngine.appProps.getProperty("base_path")); if ( DamlEngine.basePath == null ) DamlEngine.basePath = Paths.get(getServletContext().getRealPath("/")); if ( DamlEngine.appProps.getProperty("template_path") != null ) DamlEngine.templatePath = Paths.get(DamlEngine.appProps.getProperty("template_path")); if ( DamlEngine.templatePath == null ) DamlEngine.templatePath = DamlEngine.basePath.resolve("templates"); } } } static abstract class RequestPath { public static RequestPath parsePath(String pathInfo) throws ServletException { Matcher matcher; if ( pathInfo == null ) return new NoSuchPath(); if ( (matcher=Pattern.compile("/(\\d{1,7})").matcher(pathInfo)).matches() ) { final int number; try { number = Integer.parseInt(matcher.group(1)); } catch (NumberFormatException e) { return new NoSuchPath(); } try { final Connection conn = WeblogDatabaseConnection.getConnection(); final PreparedStatement selSt = conn.prepareStatement("SELECT id , extract(epoch from mdate) FROM entries WHERE id=?"); selSt.setInt(1,number); final ResultSet selRes = selSt.executeQuery(); if ( selRes.next() ) { int id = selRes.getInt(1); double mdate = selRes.getDouble(2); if ( id != number ) throw new ServletException("this cannot happen"); long lastModified = (long)(mdate*1000); long thisLastModified; try { // Attempts to detect when *this* class was last modified. thisLastModified = WeblogServlet.class.getResource("WeblogServlet.class").openConnection().getLastModified(); } catch (Exception e) { thisLastModified = 0; } if ( thisLastModified > lastModified ) lastModified = thisLastModified; // O'Reilly recommends not using milliseconds part: lastModified = (lastModified/1000)*1000; return new SingleBlogEntryPath(number, lastModified); } else return new NoSuchPath(); } catch (SQLException e) { throw new ServletException(e); } } return new NoSuchPath(); } } static final class NoSuchPath extends RequestPath { } static final class SingleBlogEntryPath extends RequestPath { public int number; public long lastModified; public SingleBlogEntryPath(int number, long lastModified) { this.number = number; this.lastModified = lastModified; } } @Override public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { final RequestPath rp = RequestPath.parsePath(request.getPathInfo()); if ( rp instanceof NoSuchPath ) { response.sendError(HttpServletResponse.SC_NOT_FOUND); return; } if ( ! (rp instanceof SingleBlogEntryPath) ) throw new ServletException("this cannot happen"); final int number = ((SingleBlogEntryPath)rp).number; response.setContentType("text/html; charset=utf-8"); response.setCharacterEncoding("UTF-8"); OutputStream out = response.getOutputStream(); try { WeblogSelect.fullProcess(new Context.WeblogSingleSelectionContext(number), out); } catch (Exception e) { throw new ServletException("exception during WeblogSelect.fullProcess()", e); } } @Override public long getLastModified(HttpServletRequest request) { final RequestPath rp; try { rp = RequestPath.parsePath(request.getPathInfo()); } catch (Exception e) { return -1; } if ( rp instanceof SingleBlogEntryPath ) { final long lastModified = ((SingleBlogEntryPath)rp).lastModified; return lastModified; } return -1; } }