From 19bba048f2d2c87362713a7d33d478809b583845 Mon Sep 17 00:00:00 2001 From: jrandom <jrandom> Date: Mon, 5 Dec 2005 06:14:15 +0000 Subject: [PATCH] 2005-12-05 jrandom * Added an RDF and XML thread export to Syndie, reachable at .../threadnav/rdf or .../threadnav/xml, accepting the parameters count=$numThreads and offset=$threadIndex. If the $numThreads is -1, it displays all threads. --- .../src/net/i2p/syndie/sml/HTMLRenderer.java | 7 + .../src/net/i2p/syndie/web/BaseServlet.java | 3 + .../net/i2p/syndie/web/ThreadNavServlet.java | 144 ++++++++++++++++++ apps/syndie/jsp/web.xml | 9 ++ history.txt | 8 +- 5 files changed, 170 insertions(+), 1 deletion(-) create mode 100644 apps/syndie/java/src/net/i2p/syndie/web/ThreadNavServlet.java diff --git a/apps/syndie/java/src/net/i2p/syndie/sml/HTMLRenderer.java b/apps/syndie/java/src/net/i2p/syndie/sml/HTMLRenderer.java index dba3f28332..55a012ed81 100644 --- a/apps/syndie/java/src/net/i2p/syndie/sml/HTMLRenderer.java +++ b/apps/syndie/java/src/net/i2p/syndie/sml/HTMLRenderer.java @@ -981,6 +981,13 @@ public class HTMLRenderer extends EventReceiverImpl { else return orig.toString(); } + public static final String sanitizeStrippedXML(String orig) { + if (orig == null) return ""; + orig = orig.replaceAll("&", "&"); + orig = orig.replaceAll("<", "<"); + orig = orig.replaceAll(">", ">"); + return orig; + } private static final String STYLE_CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_"; public static String sanitizeStyle(String style) { diff --git a/apps/syndie/java/src/net/i2p/syndie/web/BaseServlet.java b/apps/syndie/java/src/net/i2p/syndie/web/BaseServlet.java index c63a0deca6..c432d08f65 100644 --- a/apps/syndie/java/src/net/i2p/syndie/web/BaseServlet.java +++ b/apps/syndie/java/src/net/i2p/syndie/web/BaseServlet.java @@ -163,6 +163,9 @@ public abstract class BaseServlet extends HttpServlet { _log.info("New filtered index created (forced? " + forceNewIndex + ", tagsChanged? " + tagsChanged + ", authorsChanged? " + authorsChanged + ")"); } + render(user, req, resp, index); + } + protected void render(User user, HttpServletRequest req, HttpServletResponse resp, ThreadIndex index) throws IOException, ServletException { render(user, req, resp.getWriter(), index); } diff --git a/apps/syndie/java/src/net/i2p/syndie/web/ThreadNavServlet.java b/apps/syndie/java/src/net/i2p/syndie/web/ThreadNavServlet.java new file mode 100644 index 0000000000..e750ceee95 --- /dev/null +++ b/apps/syndie/java/src/net/i2p/syndie/web/ThreadNavServlet.java @@ -0,0 +1,144 @@ +package net.i2p.syndie.web; + +import java.io.*; +import java.util.*; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import net.i2p.I2PAppContext; +import net.i2p.client.naming.*; +import net.i2p.data.*; +import net.i2p.syndie.*; +import net.i2p.syndie.data.*; +import net.i2p.syndie.sml.*; + +/** + * Export the thread nav as either RDF or XML + * + */ +public class ThreadNavServlet extends BaseServlet { + public static final String PARAM_COUNT = "count"; + public static final String PARAM_OFFSET = "offset"; + public static final String PARAM_FORMAT = "format"; + + public static final String FORMAT_RDF = "rdf"; + public static final String FORMAT_XML = "xml"; + + protected void render(User user, HttpServletRequest req, HttpServletResponse resp, ThreadIndex index) throws ServletException, IOException { + int threadCount = empty(req, PARAM_COUNT) ? index.getRootCount() : getInt(req, PARAM_COUNT); + int offset = getInt(req, PARAM_OFFSET); + String uri = req.getRequestURI(); + if (uri.endsWith(FORMAT_XML)) { + resp.setContentType("text/xml; charset=UTF-8"); + render(user, index, resp.getWriter(), threadCount, offset, FORMAT_XML); + } else { + resp.setContentType("application/rdf+xml; charset=UTF-8"); + render(user, index, resp.getWriter(), threadCount, offset, FORMAT_RDF); + } + } + + private int getInt(HttpServletRequest req, String param) { + String val = req.getParameter(param); + if (val != null) { + try { + return Integer.parseInt(val); + } catch (NumberFormatException nfe) { + // ignore + } + } + return -1; + } + + private static final int DEFAULT_THREADCOUNT = 10; + private static final int DEFAULT_THREADOFFSET = 0; + + private void render(User user, ThreadIndex index, PrintWriter out, int threadCount, int offset, String format) throws IOException { + int startRoot = DEFAULT_THREADOFFSET; + if (offset >= 0) + startRoot = offset; + renderStart(out, format); + + int endRoot = startRoot + (threadCount > 0 ? threadCount : DEFAULT_THREADCOUNT); + if (endRoot >= index.getRootCount()) + endRoot = index.getRootCount() - 1; + for (int i = startRoot; i <= endRoot; i++) { + ThreadNode node = index.getRoot(i); + if (FORMAT_XML.equals(format)) + out.write(node.toString()); + else + render(user, node, out); + } + renderEnd(out, format); + } + private void renderStart(PrintWriter out, String format) throws IOException { + out.write("<?xml version=\"1.0\" ?>\n"); + if (FORMAT_XML.equals(format)) { + out.write("<threadTree>"); + } else { + out.write("<rdf:rdf xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\" " + + " xmlns:syndie=\"http://syndie.i2p.net/syndie.ns\">\n"); + } + } + private void renderEnd(PrintWriter out, String format) throws IOException { + if (FORMAT_XML.equals(format)) { + out.write("</threadTree>"); + } else { + out.write("</rdf:rdf>\n"); + } + } + private void render(User user, ThreadNode node, PrintWriter out) throws IOException { + Archive archive = BlogManager.instance().getArchive(); + String blog = node.getEntry().getKeyHash().toBase64(); + out.write("<rdf:Description rdf:about=\"entry://" + blog + "/" + node.getEntry().getEntryId() + "\">"); + PetName pn = user.getPetNameDB().getByLocation(blog); + String name = null; + if (pn != null) { + if (pn.isMember(FilteredThreadIndex.GROUP_FAVORITE)) + out.write("<syndie:favoriteauthor />\n"); + if (pn.isMember(FilteredThreadIndex.GROUP_IGNORE)) + out.write("<syndie:ignoredauthor />\n"); + name = pn.getName(); + } else { + BlogInfo info = archive.getBlogInfo(node.getEntry().getKeyHash()); + if (info != null) + name = info.getProperty(BlogInfo.NAME); + if ( (name == null) || (name.trim().length() <= 0) ) + name = node.getEntry().getKeyHash().toBase64().substring(0,6); + } + out.write("<syndie:author syndie:blog=\"" + blog + "\" syndie:name=\"" + HTMLRenderer.sanitizeStrippedXML(name) + "\" />\n"); + if ( (user.getBlog() != null) && (node.containsAuthor(user.getBlog())) ) + out.write("<syndie:threadself />\n"); + + EntryContainer entry = archive.getEntry(node.getEntry()); + if (entry == null) throw new RuntimeException("Unable to fetch the entry " + node.getEntry()); + + SMLParser parser = new SMLParser(I2PAppContext.getGlobalContext()); + HeaderReceiver rec = new HeaderReceiver(); + parser.parse(entry.getEntry().getText(), rec); + String subject = rec.getHeader(HTMLRenderer.HEADER_SUBJECT); + if ( (subject == null) || (subject.trim().length() <= 0) ) + subject = "(no subject)"; + + out.write("<syndie:subject>" + HTMLRenderer.sanitizeStrippedXML(subject) + "</syndie:subject>\n"); + + long dayBegin = BlogManager.instance().getDayBegin(); + long postId = node.getEntry().getEntryId(); + int daysAgo = (int)((dayBegin - postId + 24*60*60*1000-1)/(24*60*60*1000)); + out.write("<syndie:age>" + daysAgo + "</syndie:age>\n"); + + out.write("<syndie:children>"); + for (int i = 0; i < node.getChildCount(); i++) + render(user, node.getChild(i), out); + out.write("</syndie:children>\n"); + + out.write("</rdf:Description>\n"); + } + + protected void renderServletDetails(User user, HttpServletRequest req, PrintWriter out, ThreadIndex index, + int threadOffset, BlogURI visibleEntry, Archive archive) throws IOException { + throw new UnsupportedOperationException("Not relvent..."); + } +} diff --git a/apps/syndie/jsp/web.xml b/apps/syndie/jsp/web.xml index 83bba5f1a0..d4d7ea68e9 100644 --- a/apps/syndie/jsp/web.xml +++ b/apps/syndie/jsp/web.xml @@ -59,6 +59,11 @@ <servlet-class>net.i2p.syndie.web.ExternalLinkServlet</servlet-class> </servlet> + <servlet> + <servlet-name>net.i2p.syndie.web.ThreadNavServlet</servlet-name> + <servlet-class>net.i2p.syndie.web.ThreadNavServlet</servlet-class> + </servlet> + <servlet> <servlet-name>net.i2p.syndie.UpdaterServlet</servlet-name> <servlet-class>net.i2p.syndie.UpdaterServlet</servlet-class> @@ -117,6 +122,10 @@ <servlet-name>net.i2p.syndie.web.ExternalLinkServlet</servlet-name> <url-pattern>/externallink.jsp</url-pattern> </servlet-mapping> + <servlet-mapping> + <servlet-name>net.i2p.syndie.web.ThreadNavServlet</servlet-name> + <url-pattern>/threadnav/*</url-pattern> + </servlet-mapping> <session-config> <session-timeout> diff --git a/history.txt b/history.txt index 5c8e79f424..ea6f31ffe0 100644 --- a/history.txt +++ b/history.txt @@ -1,4 +1,10 @@ -$Id: history.txt,v 1.346 2005/12/04 15:02:25 jrandom Exp $ +$Id: history.txt,v 1.347 2005/12/04 15:12:19 jrandom Exp $ + +2005-12-05 jrandom + * Added an RDF and XML thread export to Syndie, reachable at + .../threadnav/rdf or .../threadnav/xml, accepting the parameters + count=$numThreads and offset=$threadIndex. If the $numThreads is -1, it + displays all threads. 2005-12-04 TLorD * Patch for the C SAM library to null terminate strings on copy (thanks!) -- GitLab