summaryrefslogtreecommitdiffstats
path: root/org/madore/damlengine
diff options
context:
space:
mode:
Diffstat (limited to 'org/madore/damlengine')
-rw-r--r--org/madore/damlengine/Context.java6
-rw-r--r--org/madore/damlengine/DamlEngine.java30
-rw-r--r--org/madore/damlengine/TodoWXrefAttr.java2
-rw-r--r--org/madore/damlengine/TodoWeblogIndexSelectElement.java2
-rw-r--r--org/madore/damlengine/TodoWeblogSelectionElement.java2
-rw-r--r--org/madore/damlengine/TodoWrefAttr.java2
-rw-r--r--org/madore/damlengine/WeblogDatabaseConnection.java84
-rw-r--r--org/madore/damlengine/WeblogSelect.java9
-rw-r--r--org/madore/damlengine/WeblogServlet.java163
-rw-r--r--org/madore/damlengine/WeblogSummary.java7
-rw-r--r--org/madore/damlengine/cmdlines2
11 files changed, 261 insertions, 48 deletions
diff --git a/org/madore/damlengine/Context.java b/org/madore/damlengine/Context.java
index 9249fe5..c1f0dce 100644
--- a/org/madore/damlengine/Context.java
+++ b/org/madore/damlengine/Context.java
@@ -68,6 +68,12 @@ public class Context implements Cloneable {
public WeblogSelectionContext wsc;
+ public static class DynamicContext {
+ public long modTime;
+ }
+
+ public DynamicContext dc;
+
public static class EntryContext {
public String year;
public String month;
diff --git a/org/madore/damlengine/DamlEngine.java b/org/madore/damlengine/DamlEngine.java
index a0299ad..4826cf1 100644
--- a/org/madore/damlengine/DamlEngine.java
+++ b/org/madore/damlengine/DamlEngine.java
@@ -81,8 +81,10 @@ public final class DamlEngine {
}
public static final class IncantDOM {
- static DOMImplementation domi;
+ static ThreadLocal<DOMImplementation> pdomi
+ = new ThreadLocal<DOMImplementation>();
public static DOMImplementation getDOMI() {
+ DOMImplementation domi = pdomi.get();
if ( domi == null ) {
DOMImplementationSource source
= new DOMImplementationSourceImpl();
@@ -90,6 +92,7 @@ public final class DamlEngine {
if ( domi == null )
throw new MissingResourceException("failed to obtain DOM implementation",
"org.w3c.dom.ls.DOMImplementationLS", "");
+ pdomi.set(domi);
}
return domi;
}
@@ -112,20 +115,28 @@ public final class DamlEngine {
}
public static void processDocument(Document doc,
- Context.WeblogSelectionContext wsc) {
+ Context.WeblogSelectionContext wsc,
+ Context.DynamicContext dc) {
TodoDeque todoDeque = new TodoDeque();
Context ctx = new Context(doc);
ctx.wsc = wsc;
+ ctx.dc = dc;
todoDeque.registerAtEnd(new RootTodo(ctx));
todoDeque.dispatchLoop();
}
+ public static void processDocument(Document doc,
+ Context.WeblogSelectionContext wsc) {
+ processDocument(doc, wsc, null);
+ }
+
public static void processDocument(Document doc) {
- processDocument(doc, null);
+ processDocument(doc, null, null);
}
public static void fullProcess(InputStream in, OutputStream out,
- Context.WeblogSelectionContext wsc)
+ Context.WeblogSelectionContext wsc,
+ Context.DynamicContext dc)
throws Exception {
final DOMImplementationLS domils
@@ -139,7 +150,7 @@ public final class DamlEngine {
LSInput input = domils.createLSInput();
input.setByteStream(in);
Document doc = par.parse(input);
- processDocument(doc, wsc);
+ processDocument(doc, wsc, dc);
doc.normalizeDocument();
Unparser unparser
= new Unparser(doc, new OutputStreamWriter(out, "UTF-8"),
@@ -148,11 +159,18 @@ public final class DamlEngine {
}
+ public static void fullProcess(InputStream in, OutputStream out,
+ Context.WeblogSelectionContext wsc)
+ throws Exception {
+ fullProcess(in, out, wsc, null);
+ }
+
public static void fullProcess(InputStream in, OutputStream out)
throws Exception {
- fullProcess(in, out, null);
+ fullProcess(in, out, null, null);
}
+ public static boolean runAsServlet = false;
public static Properties appProps;
public static Path basePath;
public static Path templatePath;
diff --git a/org/madore/damlengine/TodoWXrefAttr.java b/org/madore/damlengine/TodoWXrefAttr.java
index 130ba53..bb1c861 100644
--- a/org/madore/damlengine/TodoWXrefAttr.java
+++ b/org/madore/damlengine/TodoWXrefAttr.java
@@ -26,7 +26,7 @@ public class TodoWXrefAttr extends TodoAttr {
if ( ctx.wsc == null )
throw new IllegalStateException("wxref attribute encountered with no weblog selection state");
int prev = ctx.wsc.sel.first() - 1;
- WeblogSummary sum = WeblogSummary.getSummary();
+ WeblogSummary sum = WeblogSummary.getSummary(ctx.dc);
if ( sum != null && sum.entries != null
&& sum.entries.containsKey(new Integer(prev)) ) {
WeblogSummary.EntrySummary ent
diff --git a/org/madore/damlengine/TodoWeblogIndexSelectElement.java b/org/madore/damlengine/TodoWeblogIndexSelectElement.java
index 004e330..21ed367 100644
--- a/org/madore/damlengine/TodoWeblogIndexSelectElement.java
+++ b/org/madore/damlengine/TodoWeblogIndexSelectElement.java
@@ -29,7 +29,7 @@ public final class TodoWeblogIndexSelectElement extends TodoDefaultElement {
@Override
public void handleNodeOnly() {
- WeblogSummary wsum = WeblogSummary.getSummary();
+ WeblogSummary wsum = WeblogSummary.getSummary(ctx.dc);
if ( wsum == null || wsum.entries == null ) {
throw new IllegalStateException("weblog-index-select element encountered with no weblog summary available");
}
diff --git a/org/madore/damlengine/TodoWeblogSelectionElement.java b/org/madore/damlengine/TodoWeblogSelectionElement.java
index 637bc85..9d557d4 100644
--- a/org/madore/damlengine/TodoWeblogSelectionElement.java
+++ b/org/madore/damlengine/TodoWeblogSelectionElement.java
@@ -159,7 +159,7 @@ public final class TodoWeblogSelectionElement extends TodoDefaultElement {
case SINGLE_TITLE:
if ( ! ( ctx.wsc instanceof Context.WeblogSingleSelectionContext ) )
throw new IllegalStateException("weblog-selection-single-title element encountered while not in weblog single entry selection state");
- WeblogSummary wsum = WeblogSummary.getSummary();
+ WeblogSummary wsum = WeblogSummary.getSummary(ctx.dc);
if ( wsum == null || wsum.entries == null )
throw new IllegalStateException("failed to obtain weblog summary for weblog-selection-single-title");
WeblogSummary.EntrySummary esum
diff --git a/org/madore/damlengine/TodoWrefAttr.java b/org/madore/damlengine/TodoWrefAttr.java
index aeb8bb2..b707a95 100644
--- a/org/madore/damlengine/TodoWrefAttr.java
+++ b/org/madore/damlengine/TodoWrefAttr.java
@@ -42,7 +42,7 @@ public class TodoWrefAttr extends TodoAttr {
}
String targetFile;
String targetStdDir = (ctx.gc.uriToTop==null)?"":(ctx.gc.uriToTop+"weblog/");
- WeblogSummary wsum = WeblogSummary.getSummary();
+ WeblogSummary wsum = WeblogSummary.getSummary(ctx.dc);
WeblogSummary.EntrySummary esum;
// Get entry for target link from weblog summary
if ( wsum != null && wsum.entries != null )
diff --git a/org/madore/damlengine/WeblogDatabaseConnection.java b/org/madore/damlengine/WeblogDatabaseConnection.java
index 900f3a0..16d0973 100644
--- a/org/madore/damlengine/WeblogDatabaseConnection.java
+++ b/org/madore/damlengine/WeblogDatabaseConnection.java
@@ -15,73 +15,88 @@ public final class WeblogDatabaseConnection {
throw new AssertionError("WeblogDatabaseConnection cannot be instantiated");
}
- public static Connection conn;
+ public static ThreadLocal<Connection> pconn
+ = new ThreadLocal<Connection>();
public static Connection getConnection()
throws SQLException {
+ Connection conn = pconn.get();
if ( conn == null ) {
- String dbHost = System.getenv("DAMLENGINE_PGHOST");
+ String dbHost = null;
+ if ( ! DamlEngine.runAsServlet )
+ dbHost = System.getenv("DAMLENGINE_PGHOST");
if ( dbHost == null )
dbHost = DamlEngine.appProps.getProperty("pghost");
- if ( dbHost == null )
+ if ( dbHost == null && ! DamlEngine.runAsServlet )
dbHost = System.getenv("PGHOST");
if ( dbHost == null )
dbHost = "localhost";
- String dbPort = System.getenv("DAMLENGINE_PGPORT");
+ String dbPort = null;
+ if ( ! DamlEngine.runAsServlet )
+ dbPort = System.getenv("DAMLENGINE_PGPORT");
if ( dbPort == null )
dbPort = DamlEngine.appProps.getProperty("pgport");
- if ( dbPort == null )
+ if ( dbPort == null && ! DamlEngine.runAsServlet )
dbPort = System.getenv("PGPORT");
if ( dbPort == null )
dbPort = "5432";
- String dbName = System.getenv("DAMLENGINE_DBNAME");
+ String dbName = null;
+ if ( ! DamlEngine.runAsServlet )
+ dbName = System.getenv("DAMLENGINE_DBNAME");
if ( dbName == null )
dbName = DamlEngine.appProps.getProperty("dbname");
if ( dbName == null )
dbName = "weblog";
- String dbUser = System.getenv("DAMLENGINE_PGUSER");
+ String dbUser = null;
+ if ( ! DamlEngine.runAsServlet )
+ dbUser = System.getenv("DAMLENGINE_PGUSER");
if ( dbUser == null )
dbUser = DamlEngine.appProps.getProperty("pguser");
- if ( dbUser == null )
+ if ( dbUser == null && ! DamlEngine.runAsServlet )
dbUser = System.getenv("PGUSER");
- if ( dbUser == null )
+ if ( dbUser == null && ! DamlEngine.runAsServlet )
dbUser = System.getenv("USER");
if ( dbUser == null )
dbUser = System.getProperty("user.name");
if ( dbUser == null )
dbUser = dbName;
- String dbPass = System.getenv("DAMLENGINE_PGPASSWORD");
+ String dbPass = null;
+ if ( ! DamlEngine.runAsServlet )
+ dbPass = System.getenv("DAMLENGINE_PGPASSWORD");
if ( dbPass == null )
dbPass = DamlEngine.appProps.getProperty("pgpassword");
- if ( dbPass == null )
+ if ( dbPass == null && ! DamlEngine.runAsServlet )
dbPass = System.getenv("PGPASSWORD");
- if ( dbPass == null )
- try {
- String dbPassFile = System.getenv("DAMLENGINE_PGPASSFILE");
- if ( dbPassFile == null )
- dbPassFile = DamlEngine.appProps.getProperty("pgpassfile");
- if ( dbPassFile == null )
- dbPassFile = System.getenv("PGPASSFILE");
- if ( dbPassFile == null )
- dbPassFile = System.getProperty("user.home")
- + "/.pgpass";
+ if ( dbPass == null ) {
+ String dbPassFile = null;
+ if ( ! DamlEngine.runAsServlet )
+ dbPassFile = System.getenv("DAMLENGINE_PGPASSFILE");
+ if ( dbPassFile == null )
+ dbPassFile = DamlEngine.appProps.getProperty("pgpassfile");
+ if ( dbPassFile == null && ! DamlEngine.runAsServlet )
+ dbPassFile = System.getenv("PGPASSFILE");
+ if ( dbPassFile == null && ! DamlEngine.runAsServlet )
+ dbPassFile = System.getProperty("user.home")
+ + "/.pgpass";
+ if ( dbPassFile != null ) try {
BufferedReader buf
= new BufferedReader(new InputStreamReader(new FileInputStream(dbPassFile)));
- String line;
- while ( ( line = buf.readLine() ) != null ) {
- String[] elts = line.split(":");
- if ( elts.length == 5
- && ( elts[0].equals("*") || elts[0].equals(dbHost) )
- && ( elts[1].equals("*") || elts[1].equals(dbPort) )
- && ( elts[2].equals("*") || elts[2].equals(dbName) )
- && ( elts[3].equals("*") || elts[3].equals(dbUser) ) ) {
- dbPass = elts[4];
- break;
+ String line;
+ while ( ( line = buf.readLine() ) != null ) {
+ String[] elts = line.split(":");
+ if ( elts.length == 5
+ && ( elts[0].equals("*") || elts[0].equals(dbHost) )
+ && ( elts[1].equals("*") || elts[1].equals(dbPort) )
+ && ( elts[2].equals("*") || elts[2].equals(dbName) )
+ && ( elts[3].equals("*") || elts[3].equals(dbUser) ) ) {
+ dbPass = elts[4];
+ break;
+ }
}
+ } catch (IOException e) {
+ // Ignore
}
- } catch (IOException e) {
- // Ignore
- }
+ }
if ( dbPass == null )
dbPass = "";
final String dbUrl
@@ -93,6 +108,7 @@ public final class WeblogDatabaseConnection {
dbProps.setProperty("sslfactory", "org.postgresql.ssl.NonValidatingFactory");
conn = (new Driver()).connect(dbUrl, dbProps);
conn.createStatement().execute("SET TIME ZONE 0");
+ pconn.set(conn);
}
return conn;
}
diff --git a/org/madore/damlengine/WeblogSelect.java b/org/madore/damlengine/WeblogSelect.java
index a15a672..4e759cc 100644
--- a/org/madore/damlengine/WeblogSelect.java
+++ b/org/madore/damlengine/WeblogSelect.java
@@ -15,6 +15,7 @@ public final class WeblogSelect {
}
public static void fullProcess(Context.WeblogSelectionContext wsc,
+ Context.DynamicContext dc,
OutputStream out)
throws Exception {
@@ -52,8 +53,14 @@ public final class WeblogSelect {
}
DamlEngine.fullProcess(Files.newInputStream(DamlEngine.templatePath.resolve(templateResourceName)),
- out, wsc);
+ out, wsc, dc);
}
+ public static void fullProcess(Context.WeblogSelectionContext wsc,
+ OutputStream out)
+ throws Exception {
+ fullProcess(wsc, null, out);
+ }
+
}
diff --git a/org/madore/damlengine/WeblogServlet.java b/org/madore/damlengine/WeblogServlet.java
new file mode 100644
index 0000000..b68f114
--- /dev/null
+++ b/org/madore/damlengine/WeblogServlet.java
@@ -0,0 +1,163 @@
+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 <init-param> tags
+ * inside the <servlet> block: base_path, template_path, pghost,
+ * pgport, dbname, pguser and pgpass or pgpassfile.
+
+ */
+
+public class WeblogServlet extends HttpServlet {
+
+ private static final long serialVersionUID = 2014100902L;
+
+ @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<String> 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\\.(\\d{4}-\\d{2}-\\d{2})\\.(\\d{4})\\.html").matcher(pathInfo)).matches() ) {
+ final String date;
+ final int number;
+ try {
+ date = matcher.group(1);
+ number = Integer.parseInt(matcher.group(2));
+ } 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 edate=? AND id=?");
+ selSt.setString(1,date);
+ selSt.setInt(2,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 {
+ Context.DynamicContext dc = new Context.DynamicContext();
+ dc.modTime = ((SingleBlogEntryPath)rp).lastModified;
+ 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;
+ }
+}
diff --git a/org/madore/damlengine/WeblogSummary.java b/org/madore/damlengine/WeblogSummary.java
index 50ab143..4f560e8 100644
--- a/org/madore/damlengine/WeblogSummary.java
+++ b/org/madore/damlengine/WeblogSummary.java
@@ -30,6 +30,7 @@ public final class WeblogSummary {
}
public HashMap<Integer,EntrySummary> entries;
+ private long obtainedTime;
private static WeblogSummary singleton;
@@ -37,11 +38,13 @@ public final class WeblogSummary {
this.entries = new HashMap<Integer,EntrySummary>();
}
- public static WeblogSummary getSummary() {
- if ( singleton != null )
+ public static synchronized WeblogSummary getSummary(Context.DynamicContext dc) {
+ if ( singleton != null
+ && ( dc == null || singleton.obtainedTime < dc.modTime ) )
return singleton;
singleton = new WeblogSummary();
try {
+ singleton.obtainedTime = System.currentTimeMillis();
final Connection conn = WeblogDatabaseConnection.getConnection();
final PreparedStatement selSt
= conn.prepareStatement("SELECT id , edate , lang , title , title_xml , do_single_page FROM entries");
diff --git a/org/madore/damlengine/cmdlines b/org/madore/damlengine/cmdlines
index e5be081..29ecd0f 100644
--- a/org/madore/damlengine/cmdlines
+++ b/org/madore/damlengine/cmdlines
@@ -1,2 +1,2 @@
-export CLASSPATH=$HOME/java/damlengine:/usr/share/java/xercesImpl.jar:/usr/share/java/xml-resolver-1.2.jar:/usr/share/java/xml-commons-resolver-1.1.jar:/usr/share/java/postgresql-jdbc3.jar
+export CLASSPATH=$HOME/java/damlengine:/usr/share/java/xercesImpl.jar:/usr/share/java/xml-resolver-1.2.jar:/usr/share/java/xml-commons-resolver-1.1.jar:/usr/share/java/postgresql-jdbc3.jar:/usr/share/java/servlet-api-3.0.jar
java org.madore.damlengine.DamlEngine some/file.daml