From cb67d09c40c80d0389d7a0a796a4abf0007f61a6 Mon Sep 17 00:00:00 2001 From: Fredrik Tolf Date: Mon, 14 Dec 2009 02:25:44 +0100 Subject: [PATCH] Improved the DocBuffer and DOM writers to where they are kind of usable. The bsvc ShellPage uses them for reference. --- samples/bsh/src/dolda/bsvc/ShellPage.java | 70 +++++++++++++------------------ src/dolda/jsvc/next/DocBuffer.java | 6 ++- src/dolda/jsvc/next/Html.java | 36 +++++++++++++++- src/dolda/jsvc/next/HtmlWriter.java | 46 ++++++++++++++++++++ src/dolda/jsvc/next/XHtmlWriter.java | 21 ++++++++++ src/dolda/jsvc/next/XmlWriter.java | 10 +++-- 6 files changed, 144 insertions(+), 45 deletions(-) create mode 100644 src/dolda/jsvc/next/HtmlWriter.java create mode 100644 src/dolda/jsvc/next/XHtmlWriter.java diff --git a/samples/bsh/src/dolda/bsvc/ShellPage.java b/samples/bsh/src/dolda/bsvc/ShellPage.java index c26998e..13be814 100644 --- a/samples/bsh/src/dolda/bsvc/ShellPage.java +++ b/samples/bsh/src/dolda/bsvc/ShellPage.java @@ -2,10 +2,12 @@ package dolda.bsvc; import dolda.jsvc.*; import dolda.jsvc.util.*; +import dolda.jsvc.next.*; +import org.w3c.dom.*; import java.io.*; import bsh.Interpreter; -public class ShellPage extends SimpleWriter { +public class ShellPage implements Responder { private Console cons = new Console(); private Interpreter ip = new Interpreter(cons); @@ -54,19 +56,14 @@ public class ShellPage extends SimpleWriter { } } - public void respond(Request req, PrintWriter out) { + public void respond(Request req) { MultiMap params = req.params(); String cmd = params.get("cmd"); - out.println(""); - out.println(""); - out.println(""); - out.println(""); - out.println("Shell"); - out.println(""); - out.println(""); - out.println(""); - out.println("

Shell

"); + Html buf = Html.xhtml11("Shell"); + buf.addcss("css", null); + buf.insert("body", buf.el("h1", buf.text("Shell"))); + if((req.method() == "POST") && (cmd != null)) { String eo, ee; synchronized(cons) { @@ -75,47 +72,40 @@ public class ShellPage extends SimpleWriter { try { ip.set("req", req); resp = ip.eval(cmd); - out.println("
");
-		    out.println(Misc.htmlq((resp == null)?"(null)":(resp.toString())));
-		    out.println("
"); + buf.insert("body", buf.el("pre", buf.text((resp == null)?"(null)":(resp.toString())))); } catch(bsh.EvalError exc) { - out.println("

Evaluation error

"); - out.println("
");
-		    out.print(exc.toString());
-		    out.println("
"); + buf.insert("body", buf.el("h2", buf.text("Evaluation error"))); + buf.insert("body", buf.el("pre", buf.text(exc.toString()))); if(exc instanceof bsh.TargetError) { bsh.TargetError te = (bsh.TargetError)exc; - out.println("

Target error

"); - out.println("
");
-			te.getTarget().printStackTrace(out);
-			out.println("
"); + buf.insert("body", buf.el("h3", buf.text("Target error"))); + StringWriter sbuf = new StringWriter(); + te.getTarget().printStackTrace(new PrintWriter(sbuf)); + buf.insert("body", buf.el("pre", buf.text(sbuf.toString()))); } } eo = new String(cons.obuf.toByteArray(), Misc.utf8); ee = new String(cons.ebuf.toByteArray(), Misc.utf8); } if(eo.length() > 0) { - out.println("

Output

"); - out.println("
");
-		out.println(Misc.htmlq(eo));
-		out.println("
"); + buf.insert("body", buf.el("h2", buf.text("Output"))); + buf.insert("body", buf.el("pre", buf.text(eo))); } if(ee.length() > 0) { - out.println("

Errors

"); - out.println("
");
-		out.println(Misc.htmlq(ee));
-		out.println("
"); + buf.insert("body", buf.el("h2", buf.text("Errors"))); + buf.insert("body", buf.el("pre", buf.text(ee))); } } - out.println("
"); - out.println(""); - out.println(""); - out.println(""); - out.println("
"); - out.println(""); - out.println(""); + + Element form; + buf.insert("body", buf.el("form", form = buf.el("p", null), "action=sh", "method=post")); + form.appendChild(buf.el("textarea", buf.text(cmd), "cols=80", "rows=5", "name=cmd")); + form.appendChild(buf.el("input", null, "type=submit", "value=Evaluate")); + form.appendChild(buf.el("input", null, "type=reset", "value=Reset")); + try { + buf.output(req); + } catch(IOException e) { + throw(new RuntimeException(e)); + } } } diff --git a/src/dolda/jsvc/next/DocBuffer.java b/src/dolda/jsvc/next/DocBuffer.java index b2d1f0a..2690309 100644 --- a/src/dolda/jsvc/next/DocBuffer.java +++ b/src/dolda/jsvc/next/DocBuffer.java @@ -46,7 +46,9 @@ public class DocBuffer { Node c = cursor(cursor); if(c == null) throw(new RuntimeException("No such cursor: `" + cursor + "'")); - c.getParentNode().insertBefore(doc.importNode(n, true), c); + if(n.getOwnerDocument() != doc) + n = doc.importNode(n, true); + c.getParentNode().insertBefore(n, c); } public Element makecursor(String name) { @@ -69,6 +71,8 @@ public class DocBuffer { } public Text text(String text) { + if(text == null) + return(null); return(doc.createTextNode(text)); } diff --git a/src/dolda/jsvc/next/Html.java b/src/dolda/jsvc/next/Html.java index c90bb40..4c5b417 100644 --- a/src/dolda/jsvc/next/Html.java +++ b/src/dolda/jsvc/next/Html.java @@ -5,6 +5,8 @@ import org.w3c.dom.ls.*; import javax.xml.validation.*; import java.net.*; import java.io.*; +import dolda.jsvc.*; +import dolda.jsvc.util.*; public class Html extends DocBuffer { public static final String ns = "http://www.w3.org/1999/xhtml"; @@ -18,8 +20,8 @@ public class Html extends DocBuffer { Html buf = new Html("-//W3C//DTD XHTML 1.1//EN", "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"); Node html = buf.doc.getDocumentElement(); Node head = DomUtil.insertel(html, "head"); - head.appendChild(buf.makecursor("head")); Node tit = DomUtil.insertel(head, "title"); + head.appendChild(buf.makecursor("head")); DomUtil.inserttext(tit, title); Node body = DomUtil.insertel(html, "body"); body.appendChild(buf.makecursor("body")); @@ -53,4 +55,36 @@ public class Html extends DocBuffer { throw(new Error(e)); } } + + private static boolean asxhtml(Request req) { + String ah = req.inheaders().get("Accept"); + AcceptMap ctmap = AcceptMap.parse((ah == null)?"":ah); + AcceptMap.Entry ha = ctmap.accepts("text/html"); + AcceptMap.Entry xa = ctmap.accepts("text/xhtml+xml"); + if(xa == null) + xa = ctmap.accepts("application/xhtml+xml"); + if((ha == null) && (xa == null)) + return(false); + else if((ha != null) && (xa == null)) + return(false); + else if((ha == null) && (xa != null)) + return(true); + if(xa.q < ha.q) + return(false); + return(true); + } + + public void output(Request req) throws IOException { + finalise(); + validate(); + XmlWriter w; + if(asxhtml(req)) { + req.outheaders().put("Content-Type", "application/xhtml+xml"); + w = new XHtmlWriter(doc); + } else { + req.outheaders().put("Content-Type", "text/html; charset=utf-8"); + w = new HtmlWriter(doc); + } + w.write(req.output()); + } } diff --git a/src/dolda/jsvc/next/HtmlWriter.java b/src/dolda/jsvc/next/HtmlWriter.java new file mode 100644 index 0000000..40e5d53 --- /dev/null +++ b/src/dolda/jsvc/next/HtmlWriter.java @@ -0,0 +1,46 @@ +package dolda.jsvc.next; + +import java.io.*; +import org.w3c.dom.*; + +public class HtmlWriter extends XHtmlWriter { + public HtmlWriter(Document doc) { + super(doc); + } + + protected boolean asempty(ColumnWriter out, Element el) { + if(!super.asempty(out, el)) + return(false); + String n = el.getTagName(); + if(n.equals("br") || n.equals("hr") || n.equals("img") || + n.equals("input")) + return(true); + return(false); + } + + protected void attribute(ColumnWriter out, Attr attr, int indent) throws IOException { + if(attr.getNamespaceURI() != null) + throw(new RuntimeException("HTML does not support non-null-NS attributes (" + attr.getNamespaceURI() + " encountered)")); + super.attribute(out, attr, indent); + } + + protected void element(ColumnWriter out, Element el, int indent) throws IOException { + if(!el.getNamespaceURI().equals(Html.ns)) + throw(new RuntimeException("HTML does not support non-HTML elements (namespace " + el.getNamespaceURI() + " encountered)")); + super.element(out, el, indent); + } + + public void write(Writer out) throws IOException { + DocumentType dt = doc.getDoctype(); + if(dt == null) + throw(new RuntimeException("Writing HTML requires an HTML document")); + if(!dt.getName().equals("html")) + throw(new RuntimeException("Writing HTML requires an HTML document, not `" + dt.getName() + "'")); + String pubid = dt.getPublicId(); + if(pubid.equals("-//W3C//DTD XHTML 1.1//EN")) { + } else { + throw(new RuntimeException("Unimplemented HTML doctype `" + pubid)); + } + super.write(out); + } +} diff --git a/src/dolda/jsvc/next/XHtmlWriter.java b/src/dolda/jsvc/next/XHtmlWriter.java new file mode 100644 index 0000000..678b3c7 --- /dev/null +++ b/src/dolda/jsvc/next/XHtmlWriter.java @@ -0,0 +1,21 @@ +package dolda.jsvc.next; + +import java.io.*; +import org.w3c.dom.*; + +public class XHtmlWriter extends IndentWriter { + public XHtmlWriter(Document doc) { + super(doc); + setnsname(Html.ns, null); + } + + protected int indent(ColumnWriter out, Element el) { + if(Html.ns.equals(el.getNamespaceURI())) { + if(el.getTagName().equals("pre")) + return(-1); + if(el.getTagName().equals("textarea")) + return(-1); + } + return(super.indent(out, el)); + } +} diff --git a/src/dolda/jsvc/next/XmlWriter.java b/src/dolda/jsvc/next/XmlWriter.java index a1004e4..a5e698e 100644 --- a/src/dolda/jsvc/next/XmlWriter.java +++ b/src/dolda/jsvc/next/XmlWriter.java @@ -7,7 +7,7 @@ import dolda.jsvc.util.Misc; public class XmlWriter { private Map nsnames = new HashMap(); - private Document doc; + public final Document doc; private int nsser = 1; public XmlWriter(Document doc) { @@ -146,7 +146,7 @@ public class XmlWriter { } protected void text(ColumnWriter out, String s, int indent) throws IOException { - out.write(s); + out.write(Misc.htmlq(s)); } protected void text(ColumnWriter out, Text txt, int indent) throws IOException { @@ -176,12 +176,16 @@ public class XmlWriter { } } + protected void doctype(ColumnWriter out, DocumentType dt) throws IOException { + out.write(String.format("\n", dt.getName(), dt.getPublicId(), dt.getSystemId())); + } + public void write(Writer out) throws IOException { findallnsnames(); ColumnWriter col = new ColumnWriter(out); DocumentType t = doc.getDoctype(); if(t != null) - out.write(String.format("\n", t.getName(), t.getPublicId(), t.getSystemId())); + doctype(col, t); node(col, doc.getDocumentElement(), 0); } -- 2.11.0