[Mulgara-svn] r1223 - in trunk/src/jar/querylang/java/org/mulgara: . protocol
pag at mulgara.org
pag at mulgara.org
Wed Sep 3 14:56:29 UTC 2008
Author: pag
Date: 2008-09-03 07:56:28 -0700 (Wed, 03 Sep 2008)
New Revision: 1223
Added:
trunk/src/jar/querylang/java/org/mulgara/protocol/
trunk/src/jar/querylang/java/org/mulgara/protocol/AbstractStreamedAnswer.java
trunk/src/jar/querylang/java/org/mulgara/protocol/AbstractStreamedXMLAnswer.java
trunk/src/jar/querylang/java/org/mulgara/protocol/StreamedAnswer.java
trunk/src/jar/querylang/java/org/mulgara/protocol/StreamedJSONAnswer.java
trunk/src/jar/querylang/java/org/mulgara/protocol/StreamedSparqlJSONAnswer.java
trunk/src/jar/querylang/java/org/mulgara/protocol/StreamedSparqlJSONAnswerUnitTest.java
trunk/src/jar/querylang/java/org/mulgara/protocol/StreamedSparqlXMLAnswer.java
trunk/src/jar/querylang/java/org/mulgara/protocol/StreamedSparqlXMLAnswerUnitTest.java
trunk/src/jar/querylang/java/org/mulgara/protocol/StreamedTqlXMLAnswer.java
trunk/src/jar/querylang/java/org/mulgara/protocol/StreamedTqlXMLAnswerUnitTest.java
trunk/src/jar/querylang/java/org/mulgara/protocol/StreamedXMLAnswer.java
trunk/src/jar/querylang/java/org/mulgara/protocol/XMLAnswer.java
Log:
Streaming results for queries. JSON not yet being tested
Added: trunk/src/jar/querylang/java/org/mulgara/protocol/AbstractStreamedAnswer.java
===================================================================
--- trunk/src/jar/querylang/java/org/mulgara/protocol/AbstractStreamedAnswer.java (rev 0)
+++ trunk/src/jar/querylang/java/org/mulgara/protocol/AbstractStreamedAnswer.java 2008-09-03 14:56:28 UTC (rev 1223)
@@ -0,0 +1,108 @@
+package org.mulgara.protocol;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.nio.charset.Charset;
+
+import org.jrdf.graph.BlankNode;
+import org.jrdf.graph.Literal;
+import org.jrdf.graph.URIReference;
+import org.mulgara.query.Answer;
+import org.mulgara.query.TuplesException;
+import org.mulgara.query.Variable;
+
+/**
+ * Converts an answer to a stream, acccording to the protocol of the implementing class.
+ *
+ * @created Sep 1, 2008
+ * @author Paul Gearon
+ * @copyright © 2008 <a href="http://www.topazproject.org/">The Topaz Project</a>
+ * @licence <a href="{@docRoot}/../../LICENCE.txt">Open Software License v3.0</a>
+ */
+public abstract class AbstractStreamedAnswer {
+
+ /** The API {@link Answer} to convert to the stream. */
+ protected final Answer answer;
+
+ /** The number of columns in the Answer. */
+ protected final int width;
+
+ /** The {@link Variable}s in the Answer. */
+ protected final Variable[] vars;
+
+ /** The writer used for creating the XML. */
+ protected OutputStreamWriter s = null;
+
+ /** The byte output stream used for creating the XML. */
+ protected OutputStream output = null;
+
+ /** The charset encoding to use when writing to the output stream. */
+ Charset charset = Charset.defaultCharset();
+
+ /** Adds a literal to the stream */
+ protected abstract void addLiteral(Literal literal) throws IOException;
+
+ /** Adds a blank node to the stream */
+ protected abstract void addBNode(BlankNode bnode) throws IOException;
+
+ /** Adds a URI reference to the stream */
+ protected abstract void addURI(URIReference uri) throws IOException;
+
+ /** Adds a variable binding to the stream */
+ protected abstract void addBinding(Variable var, Object value) throws TuplesException, IOException;
+
+ /** Adds a single result to the stream */
+ protected abstract void addResult() throws TuplesException, IOException;
+
+ /** Adds all results to the stream */
+ protected abstract void addResults() throws TuplesException, IOException;
+
+ /** Adds a variable in the header to the stream */
+ protected abstract void addHeaderVariable(Variable var) throws IOException;
+
+ /** Adds the entire header to the stream */
+ protected abstract void addHeader() throws IOException;
+
+ /** Closes the document in the stream */
+ protected abstract void addDocFooter() throws IOException;
+
+ /** Oopens the document in the stream */
+ protected abstract void addDocHeader() throws IOException;
+
+
+ /**
+ * Creates the object around the answer and output stream.
+ * @param answer The answer to encode.
+ * @param output The stream to write to.
+ */
+ public AbstractStreamedAnswer(Answer answer, OutputStream output) {
+ this.answer = answer;
+ this.output = output;
+ width = (answer != null) ? answer.getNumberOfVariables() : 0;
+ vars = (answer != null) ? answer.getVariables() : null;
+ }
+
+ /**
+ * @see org.mulgara.protocol.StreamedXMLAnswer#emit()
+ */
+ public void emit() throws TuplesException, IOException {
+ if (s == null) {
+ s = new OutputStreamWriter(output, charset);
+ generate();
+ s.flush();
+ }
+ }
+
+ /**
+ * Generates the XML document in the {@link #s} buffer.
+ * @throws TuplesException Indicates an error accessing the Answer.
+ */
+ void generate() throws TuplesException, IOException {
+ addDocHeader();
+ addHeader();
+ addResults();
+ addDocFooter();
+ }
+
+}
\ No newline at end of file
Added: trunk/src/jar/querylang/java/org/mulgara/protocol/AbstractStreamedXMLAnswer.java
===================================================================
--- trunk/src/jar/querylang/java/org/mulgara/protocol/AbstractStreamedXMLAnswer.java (rev 0)
+++ trunk/src/jar/querylang/java/org/mulgara/protocol/AbstractStreamedXMLAnswer.java 2008-09-03 14:56:28 UTC (rev 1223)
@@ -0,0 +1,182 @@
+package org.mulgara.protocol;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.URI;
+import java.nio.charset.Charset;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.jrdf.graph.BlankNode;
+import org.jrdf.graph.Literal;
+import org.jrdf.graph.URIReference;
+import org.mulgara.query.Answer;
+import org.mulgara.query.TuplesException;
+import org.mulgara.query.Variable;
+
+/**
+ * Basic functionality for emitting Answers as XML using raw text methods.
+ *
+ * @created Jul 9, 2008
+ * @author Paul Gearon
+ * @copyright © 2008 <a href="http://www.topazproject.org/">The Topaz Project</a>
+ * @licence <a href="{@docRoot}/../../LICENCE.txt">Open Software License v3.0</a>
+ */
+public abstract class AbstractStreamedXMLAnswer extends AbstractStreamedAnswer implements StreamedXMLAnswer {
+
+ /** A single indent for use when pretty printing. */
+ static final private String SINGLE_INDENT_STR = " ";
+
+ /** The size of indents to use for pretty printing. */
+ static final private int SINGLE_INDENT_SIZE = SINGLE_INDENT_STR.length();
+
+ /** The largest indent string allowed. */
+ static final private String MAX_INDENT = "\n ";
+
+ /**
+ * An array of indent strings used by {@link #i(int)}.
+ * This is pre-generated to avoid creating them while emiting xml.
+ */
+ static final String[] INDENT = new String[MAX_INDENT.length() / SINGLE_INDENT_SIZE];
+
+ // Build the indents using the MAX_INDENT as a raw data source
+ static {
+ for (int i = 0; i < INDENT.length; i++) INDENT[i] = MAX_INDENT.substring(0, i * SINGLE_INDENT_SIZE + 1);
+ }
+
+ /** All the namespaces explicitly requested. */
+ Map<String,URI> namespaces = new HashMap<String,URI>();
+
+ /** Indicates that pretty printing should be used. */
+ boolean prettyPrint = true;
+
+ /**
+ * Create an XMLAnswer based on a given {@link Answer}.
+ * @param answer The Answer with the data to convert.
+ */
+ public AbstractStreamedXMLAnswer(Answer answer, OutputStream output) {
+ super(answer, output);
+ }
+
+ /**
+ * @see org.mulgara.protocol.StreamedXMLAnswer#setCharacterEncoding(java.lang.String)
+ */
+ public void setCharacterEncoding(String encoding) {
+ charset = Charset.forName(encoding);
+ }
+
+ /**
+ * @see org.mulgara.protocol.StreamedXMLAnswer#setCharacterEncoding(java.nio.Charset)
+ */
+ public void setCharacterEncoding(Charset charset) {
+ this.charset = charset;
+ }
+
+ /**
+ * @see org.mulgara.protocol.StreamedXMLAnswer#addNamespace(java.lang.String, java.net.URI)
+ */
+ public void addNamespace(String name, URI nsValue) {
+ namespaces.put(name, nsValue);
+ s = null;
+ }
+
+ /**
+ * @see org.mulgara.protocol.StreamedXMLAnswer#clearNamespaces()
+ */
+ public void clearNamespaces() {
+ namespaces.clear();
+ s = null;
+ }
+
+ /**
+ * @see org.mulgara.protocol.StreamedXMLAnswer#setPrettyPrint(boolean)
+ */
+ public void setPrettyPrint(boolean prettyPrint) {
+ this.prettyPrint = prettyPrint;
+ s = null;
+ }
+
+ /**
+ * When {@link #setPrettyPrint(boolean)} is set, returns a string containing a new line and an indentation.
+ * When pretty printing is off, then return an empty string.
+ * @param indent The number of indentations to use.
+ * @return A String containing the appropriate indentation, or an empty string if not pretty printing.
+ */
+ String i(int indent) {
+ if (!prettyPrint) return "";
+ if (indent < INDENT.length) return INDENT[indent];
+ StringBuilder sbi = new StringBuilder(MAX_INDENT);
+ for (int i = INDENT.length; i < indent; i++) sbi.append(SINGLE_INDENT_STR);
+ return sbi.toString();
+ }
+
+ /**
+ * Adds the document header to the buffer.
+ */
+ @Override
+ protected abstract void addDocHeader() throws IOException;
+
+ /**
+ * Adds the document footer to the buffer.
+ */
+ @Override
+ protected abstract void addDocFooter() throws IOException;
+
+ /**
+ * Adds the header to the document data.
+ */
+ @Override
+ protected abstract void addHeader() throws IOException;
+
+ /**
+ * Adds the results to the document data.
+ * @throws TuplesException Indicates an error accessing the Answer.
+ */
+ @Override
+ protected abstract void addResults() throws TuplesException, IOException;
+
+ /**
+ * Adds a variable to the header.
+ * @param var The variable to add.
+ */
+ @Override
+ protected abstract void addHeaderVariable(Variable var) throws IOException;
+
+ /**
+ * Adds a single result, based on the current result in the {@link #answer}.
+ * @throws TuplesException Indicates an error accessing the Answer.
+ */
+ @Override
+ protected abstract void addResult() throws TuplesException, IOException;
+
+ /**
+ * Adds a single binding from the current result in the {@link #answer}.
+ * @param var The bound variable.
+ * @param value The value bound to the variable.
+ * @throws TuplesException Indicates an error accessing the Answer.
+ */
+ @Override
+ protected abstract void addBinding(Variable var, Object value) throws TuplesException, IOException;
+
+ /**
+ * Adds a single URI to the buffer.
+ * @param uri The URIReference for the URI to add.
+ */
+ @Override
+ protected abstract void addURI(URIReference uri) throws IOException;
+
+ /**
+ * Adds a single blank node to the buffer.
+ * @param uri The blank node to add.
+ */
+ @Override
+ protected abstract void addBNode(BlankNode bnode) throws IOException;
+
+ /**
+ * Adds a single Literal to the buffer.
+ * @param literal The Literal to add.
+ */
+ @Override
+ protected abstract void addLiteral(Literal literal) throws IOException;
+
+}
\ No newline at end of file
Added: trunk/src/jar/querylang/java/org/mulgara/protocol/StreamedAnswer.java
===================================================================
--- trunk/src/jar/querylang/java/org/mulgara/protocol/StreamedAnswer.java (rev 0)
+++ trunk/src/jar/querylang/java/org/mulgara/protocol/StreamedAnswer.java 2008-09-03 14:56:28 UTC (rev 1223)
@@ -0,0 +1,23 @@
+package org.mulgara.protocol;
+
+import java.io.IOException;
+
+import org.mulgara.query.TuplesException;
+
+/**
+ * Represents an Answer that can be emitted to a stream.
+ *
+ * @created Sep 8, 2008
+ * @author Paul Gearon
+ * @copyright © 2008 <a href="http://www.topazproject.org/">The Topaz Project</a>
+ * @licence <a href="{@docRoot}/../../LICENCE.txt">Open Software License v3.0</a>
+ */
+public interface StreamedAnswer {
+
+ /**
+ * Converts the Answer to a String and send to output.
+ * @throws TuplesException Indicates an error accessing the Answer.
+ */
+ public void emit() throws TuplesException, IOException;
+
+}
\ No newline at end of file
Added: trunk/src/jar/querylang/java/org/mulgara/protocol/StreamedJSONAnswer.java
===================================================================
--- trunk/src/jar/querylang/java/org/mulgara/protocol/StreamedJSONAnswer.java (rev 0)
+++ trunk/src/jar/querylang/java/org/mulgara/protocol/StreamedJSONAnswer.java 2008-09-03 14:56:28 UTC (rev 1223)
@@ -0,0 +1,23 @@
+package org.mulgara.protocol;
+
+import java.io.IOException;
+
+import org.mulgara.query.TuplesException;
+
+/**
+ * Represents an Answer that can be emitted as JSON to a stream.
+ *
+ * @created Sept 1, 2008
+ * @author Paul Gearon
+ * @copyright © 2008 <a href="http://www.topazproject.org/">The Topaz Project</a>
+ * @licence <a href="{@docRoot}/../../LICENCE.txt">Open Software License v3.0</a>
+ */
+public interface StreamedJSONAnswer extends StreamedAnswer {
+
+ /**
+ * Converts the Answer to a JSON String and send to output.
+ * @throws TuplesException Indicates an error accessing the Answer.
+ */
+ public void emit() throws TuplesException, IOException;
+
+}
\ No newline at end of file
Added: trunk/src/jar/querylang/java/org/mulgara/protocol/StreamedSparqlJSONAnswer.java
===================================================================
--- trunk/src/jar/querylang/java/org/mulgara/protocol/StreamedSparqlJSONAnswer.java (rev 0)
+++ trunk/src/jar/querylang/java/org/mulgara/protocol/StreamedSparqlJSONAnswer.java 2008-09-03 14:56:28 UTC (rev 1223)
@@ -0,0 +1,188 @@
+/*
+ * The contents of this file are subject to the Open Software License
+ * Version 3.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.opensource.org/licenses/osl-3.0.txt
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ */
+
+package org.mulgara.protocol;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.net.URI;
+
+import org.jrdf.graph.BlankNode;
+import org.jrdf.graph.Literal;
+import org.jrdf.graph.URIReference;
+import org.mulgara.query.Answer;
+import org.mulgara.query.BooleanAnswer;
+import org.mulgara.query.TuplesException;
+import org.mulgara.query.Variable;
+
+/**
+ * Represents an Answer as JSON.
+ * The format is specified at: {@link http://www.w3.org/TR/rdf-sparql-json-res/}
+ *
+ * @created Sep 1, 2008
+ * @author Paul Gearon
+ * @copyright © 2008 <a href="http://www.topazproject.org/">The Topaz Project</a>
+ * @licence <a href="{@docRoot}/../../LICENCE.txt">Open Software License v3.0</a>
+ */
+public class StreamedSparqlJSONAnswer extends AbstractStreamedAnswer implements StreamedJSONAnswer {
+
+ /** Additional metadata about the results. */
+ URI additionalMetadata = null;
+
+ /** Boolean answer. */
+ boolean booleanResult = false;
+
+ /** Internal flag to indicate that a comma may be needed. */
+ boolean prependComma = false;
+
+ /**
+ * Creates an XML Answer conforming to SPARQL XML results.
+ * @param answer The Answer to wrap.
+ */
+ public StreamedSparqlJSONAnswer(Answer answer, OutputStream output) {
+ super((answer instanceof BooleanAnswer) ? null : answer, output);
+ if (answer instanceof BooleanAnswer) booleanResult = ((BooleanAnswer)answer).getResult();
+ }
+
+ /**
+ * Creates an XML Answer with additional metadata.
+ * @param answer The Answer to wrap.
+ * @param metadata Additional metadata for the answer.
+ */
+ public StreamedSparqlJSONAnswer(Answer answer, URI metadata, OutputStream output) {
+ this(answer, output);
+ additionalMetadata = metadata;
+ }
+
+ /**
+ * Creates an XML Answer conforming to SPARQL XML results.
+ * @param result The boolean result to encode.
+ */
+ public StreamedSparqlJSONAnswer(boolean result, OutputStream output) {
+ super(null, output);
+ booleanResult = result;
+ }
+
+ /**
+ * Creates an XML Answer with additional metadata.
+ * @param result The boolean result to encode.
+ * @param metadata Additional metadata for the answer.
+ */
+ public StreamedSparqlJSONAnswer(boolean result, URI metadata, OutputStream output) {
+ super(null, output);
+ booleanResult = result;
+ additionalMetadata = metadata;
+ }
+
+ /** {@inheritDoc} */
+ protected void addDocHeader() throws IOException {
+ s.append("{ ");
+ }
+
+ /** {@inheritDoc} */
+ protected void addDocFooter() throws IOException {
+ s.append(" }");
+ }
+
+ /** {@inheritDoc} */
+ protected void addHeader() throws IOException {
+ s.append("\"head\": {");
+ boolean wroteVars = false;
+ if (answer != null && answer.getVariables() != null) {
+ s.append("\"vars\": [");
+ prependComma = false;
+ for (Variable v: answer.getVariables()) addHeaderVariable(v);
+ s.append("]");
+ wroteVars = true;
+ }
+ if (additionalMetadata != null) {
+ if (wroteVars) s.append(", ");
+ s.append("\"link\": [\"").append(additionalMetadata.toString()).append("\"]");
+ }
+ s.append("}, ");
+ }
+
+ /** {@inheritDoc} */
+ protected void addHeaderVariable(Variable var) throws IOException {
+ comma().append("\"").append(var.getName()).append("\"");
+ }
+
+ /** {@inheritDoc} */
+ protected void addResults() throws TuplesException, IOException {
+ if (answer != null) {
+ comma().append("\"results\": { ");
+ s.append("\"bindings\": [ ");
+ answer.beforeFirst();
+ prependComma = false;
+ while (answer.next()) addResult();
+ s.append(" ] }");
+ } else {
+ comma().append("\"boolean\": ").append(Boolean.toString(booleanResult));
+ }
+ }
+
+ /** {@inheritDoc} */
+ protected void addResult() throws TuplesException, IOException {
+ comma().append("{ ");
+ prependComma = false;
+ for (int c = 0; c < width; c++) addBinding(vars[c], answer.getObject(c));
+ s.append(" }");
+ }
+
+ /**
+ * {@inheritDoc}
+ * No binding will be emitted if the value is null (unbound).
+ */
+ protected void addBinding(Variable var, Object value) throws IOException {
+ if (value != null) {
+ comma().append("\"").append(var.getName()).append("\": { ");
+ // no dynamic dispatch, so use if/then
+ if (value instanceof URIReference) addURI((URIReference)value);
+ else if (value instanceof Literal) addLiteral((Literal)value);
+ else if (value instanceof BlankNode) addBNode((BlankNode)value);
+ else throw new IllegalArgumentException("Unable to create a SPARQL response with an answer containing: " + value.getClass().getSimpleName());
+ s.append(" }");
+ }
+ }
+
+ /** {@inheritDoc} */
+ protected void addURI(URIReference uri) throws IOException {
+ s.append("\"type\": \"uri\", \"value\": \"").append(uri.getURI().toString()).append("\"");
+ }
+
+ /** {@inheritDoc} */
+ protected void addBNode(BlankNode bnode) throws IOException {
+ s.append("\"type\": \"bnode\", \"value\": \"").append(bnode.toString()).append("\"");
+ }
+
+ /** {@inheritDoc} */
+ protected void addLiteral(Literal literal) throws IOException {
+ if (literal.getDatatype() != null) {
+ s.append("\"type\": \"typed-literal\", \"datatype\": \"").append(literal.getDatatype().toString()).append("\", ");
+ } else {
+ s.append("\"type\": \"literal\", ");
+ if (literal.getLanguage() != null) s.append(" \"xml:lang\": \"").append(literal.getLanguage()).append("\", ");
+ }
+ s.append("\"value\": \"").append(literal.getLexicalForm()).append("\"");
+ }
+
+ /**
+ * Adds a comma if needed at this point. Commas are usually needed.
+ * @throws IOException An error writing to the stream.
+ */
+ protected OutputStreamWriter comma() throws IOException {
+ if (prependComma) s.append(", ");
+ prependComma = true;
+ return s;
+ }
+}
Added: trunk/src/jar/querylang/java/org/mulgara/protocol/StreamedSparqlJSONAnswerUnitTest.java
===================================================================
--- trunk/src/jar/querylang/java/org/mulgara/protocol/StreamedSparqlJSONAnswerUnitTest.java (rev 0)
+++ trunk/src/jar/querylang/java/org/mulgara/protocol/StreamedSparqlJSONAnswerUnitTest.java 2008-09-03 14:56:28 UTC (rev 1223)
@@ -0,0 +1,592 @@
+/*
+ * The contents of this file are subject to the Open Software License
+ * Version 3.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.opensource.org/licenses/osl-3.0.txt
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ */
+
+package org.mulgara.protocol;
+
+
+// JUnit
+import junit.framework.*;
+
+// Java 2 standard packages
+import java.io.ByteArrayOutputStream;
+import java.net.URI;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+// Locally written packages
+import org.mulgara.query.AnswerImpl;
+import org.mulgara.query.BooleanAnswer;
+import org.mulgara.query.Variable;
+import org.mulgara.query.rdf.BlankNodeImpl;
+import org.mulgara.query.rdf.LiteralImpl;
+import org.mulgara.query.rdf.URIReferenceImpl;
+import org.mulgara.util.ResultSetRow;
+import org.mulgara.util.TestResultSet;
+
+/**
+ * Test case for {@link StreamedSparqlJSONAnswer}.
+ *
+ * @created Sep 1, 2008
+ * @author Paul Gearon
+ * @copyright © 2008 <a href="http://www.topazproject.org/">The Topaz Project</a>
+ * @licence <a href="{@docRoot}/../../LICENCE.txt">Open Software License v3.0</a>
+ */
+public class StreamedSparqlJSONAnswerUnitTest extends TestCase {
+
+ /**
+ * Test instance.
+ * <table>
+ * <thead>
+ * <tr><th>x</th> <th>y</th></tr>
+ * </thead>
+ * <tbody>
+ * <tr><td>X1</td><td>Y1</td></tr>
+ * <tr><td>X2</td><td>Y2</td></tr>
+ * </tbody>
+ * </table>
+ */
+ private AnswerImpl answer;
+
+ private AnswerImpl empty;
+
+ private ByteArrayOutputStream output;
+
+ private ByteArrayOutputStream outputb;
+
+ private ByteArrayOutputStream outputa;
+
+ private static final URI REL_URI = URI.create("rel/uri");
+
+ /**
+ * Constructs a new answer test with the given name.
+ * @param name the name of the test
+ */
+ public StreamedSparqlJSONAnswerUnitTest(String name) {
+ super(name);
+ }
+
+ /**
+ * Hook for test runner to obtain a test suite from.
+ * @return The test suite
+ */
+ public static Test suite() {
+ TestSuite suite = new TestSuite();
+ // TODO: tests not yet written
+// suite.addTest(new StreamedSparqlJSONAnswerUnitTest("testEmptyConstructor"));
+// suite.addTest(new StreamedSparqlJSONAnswerUnitTest("testEmptyConstructorPretty"));
+// suite.addTest(new StreamedSparqlJSONAnswerUnitTest("testBooleanAnswer"));
+// suite.addTest(new StreamedSparqlJSONAnswerUnitTest("testBooleanAnswerPretty"));
+// suite.addTest(new StreamedSparqlJSONAnswerUnitTest("testPrettyPrint"));
+// suite.addTest(new StreamedSparqlJSONAnswerUnitTest("testCompactPrint"));
+// suite.addTest(new StreamedSparqlJSONAnswerUnitTest("testPrettyPrintVariations"));
+// suite.addTest(new StreamedSparqlJSONAnswerUnitTest("testCompactPrintVariations"));
+ return suite;
+ }
+
+ /**
+ * Default text runner.
+ * @param args The command line arguments
+ */
+ public static void main(String[] args) {
+ junit.textui.TestRunner.run(suite());
+ }
+
+
+ /**
+ * Tests an empty answer.
+ * @throws Exception On error
+ */
+ public void testEmptyConstructor() throws Exception {
+ StreamedSparqlJSONAnswer a = new StreamedSparqlJSONAnswer(empty, output);
+ a.emit();
+ assertEquals(getEmpty(), output.toString());
+ }
+
+
+ /**
+ * Tests an empty answer.
+ * @throws Exception On error
+ */
+ public void testEmptyConstructorPretty() throws Exception {
+ StreamedSparqlJSONAnswer a = new StreamedSparqlJSONAnswer(empty, output);
+ a.emit();
+ assertEquals(getEmptyP(), output.toString());
+
+ output.reset();
+ a.emit();
+ assertEquals(getEmpty(), output.toString());
+ }
+
+
+ /**
+ * Tests a boolean answer.
+ * @throws Exception On error
+ */
+ public void testBooleanAnswer() throws Exception {
+ StreamedSparqlJSONAnswer a = new StreamedSparqlJSONAnswer(true, output);
+ a.emit();
+ assertEquals(getTrue(), output.toString());
+
+ a = new StreamedSparqlJSONAnswer(new BooleanAnswer(true), output);
+ output.reset();
+ a.emit();
+ assertEquals(getTrue(), output.toString());
+ }
+
+
+ /**
+ * Tests a boolean answer.
+ * @throws Exception On error
+ */
+ public void testBooleanAnswerPretty() throws Exception {
+ StreamedSparqlJSONAnswer a = new StreamedSparqlJSONAnswer(true, output);
+ a.emit();
+ assertEquals(getTrueP(), output.toString());
+ output.reset();
+ a.emit();
+ assertEquals(getTrue(), output.toString());
+ }
+
+
+ /**
+ * Test main structure.
+ */
+ public void testPrettyPrint() throws Exception {
+ StreamedSparqlJSONAnswer a = new StreamedSparqlJSONAnswer(answer, output);
+ a.emit();
+ assertEquals(getAnswerP(), output.toString());
+ }
+
+
+ /**
+ * Test main structure.
+ */
+ public void testCompactPrint() throws Exception {
+ StreamedSparqlJSONAnswer a = new StreamedSparqlJSONAnswer(answer, output);
+ a.emit();
+ assertEquals(getAnswer(), output.toString());
+ }
+
+
+ /**
+ * Tests the variations of answers.
+ * @throws Exception On error
+ */
+ public void testCompactPrintVariations() throws Exception {
+ StreamedSparqlJSONAnswer e = new StreamedSparqlJSONAnswer(empty, REL_URI, output);
+ StreamedSparqlJSONAnswer b = new StreamedSparqlJSONAnswer(true, REL_URI, outputb);
+ StreamedSparqlJSONAnswer a = new StreamedSparqlJSONAnswer(answer, REL_URI, outputa);
+
+ // No namespaces, no schema, meta set
+ e.emit();
+ b.emit();
+ a.emit();
+ assertEquals(getEmpty(false, true), output.toString());
+ assertEquals(getTrue(false, true), outputb.toString());
+ assertEquals(getAnswer(false, true), outputa.toString());
+
+ // No namespaces, schema set, meta set
+ output.reset();
+ outputb.reset();
+ outputa.reset();
+ e.emit();
+ b.emit();
+ a.emit();
+ assertEquals(getEmpty(true, true), output.toString());
+ assertEquals(getTrue(true, true), outputb.toString());
+ assertEquals(getAnswer(true, true), outputa.toString());
+
+ // Namespaces set, schema set, meta set
+ output.reset();
+ outputb.reset();
+ outputa.reset();
+ e.emit();
+ b.emit();
+ a.emit();
+ assertEquals(getEmpty(true, true), output.toString());
+ assertEquals(getTrue(true, true), outputb.toString());
+ assertEquals(getAnswer(true, true), outputa.toString());
+
+ // Namespaces set, no schema, meta set
+ output.reset();
+ outputb.reset();
+ outputa.reset();
+ e.emit();
+ b.emit();
+ a.emit();
+ assertEquals(getEmpty(false, true), output.toString());
+ assertEquals(getTrue(false, true), outputb.toString());
+ assertEquals(getAnswer(false, true), outputa.toString());
+
+ e = new StreamedSparqlJSONAnswer(empty, output);
+ b = new StreamedSparqlJSONAnswer(true, outputb);
+ a = new StreamedSparqlJSONAnswer(answer, outputa);
+
+ // No namespaces, schema set, no meta
+ output.reset();
+ outputb.reset();
+ outputa.reset();
+ e.emit();
+ b.emit();
+ a.emit();
+ assertEquals(getEmpty(true, false), output.toString());
+ assertEquals(getTrue(true, false), outputb.toString());
+ assertEquals(getAnswer(true, false), outputa.toString());
+
+ // Namespaces set, schema set, no meta
+ output.reset();
+ outputb.reset();
+ outputa.reset();
+ e.emit();
+ b.emit();
+ a.emit();
+ assertEquals(getEmpty(true, false), output.toString());
+ assertEquals(getTrue(true, false), outputb.toString());
+ assertEquals(getAnswer(true, false), outputa.toString());
+
+ // Namespaces set, no schema, no meta
+ output.reset();
+ outputb.reset();
+ outputa.reset();
+ e.emit();
+ b.emit();
+ a.emit();
+ assertEquals(getEmpty(false, false), output.toString());
+ assertEquals(getTrue(false, false), outputb.toString());
+ assertEquals(getAnswer(false, false), outputa.toString());
+
+ // No Namespaces, no schema, no meta
+ output.reset();
+ outputb.reset();
+ outputa.reset();
+ e.emit();
+ b.emit();
+ a.emit();
+ assertEquals(getEmpty(false, false), output.toString());
+ assertEquals(getTrue(false, false), outputb.toString());
+ assertEquals(getAnswer(false, false), outputa.toString());
+
+ // No namespaces, schema set, no meta
+ output.reset();
+ outputb.reset();
+ outputa.reset();
+ e.emit();
+ b.emit();
+ a.emit();
+ assertEquals(getEmpty(true, false), output.toString());
+ assertEquals(getTrue(true, false), outputb.toString());
+ assertEquals(getAnswer(true, false), outputa.toString());
+ }
+
+
+ /**
+ * Tests the variations of answers.
+ * @throws Exception On error
+ */
+ public void testPrettyPrintVariations() throws Exception {
+ StreamedSparqlJSONAnswer e = new StreamedSparqlJSONAnswer(empty, REL_URI, output);
+ StreamedSparqlJSONAnswer b = new StreamedSparqlJSONAnswer(true, REL_URI, outputb);
+ StreamedSparqlJSONAnswer a = new StreamedSparqlJSONAnswer(answer, REL_URI, outputa);
+
+ // No namespaces, no schema, meta set
+ e.emit();
+ b.emit();
+ a.emit();
+ assertEquals(getEmptyP(false, true), output.toString());
+ assertEquals(getTrueP(false, true), outputb.toString());
+ assertEquals(getAnswerP(false, true), outputa.toString());
+
+ // No namespaces, schema set, meta set
+ output.reset();
+ outputb.reset();
+ outputa.reset();
+ e.emit();
+ b.emit();
+ a.emit();
+ assertEquals(getEmptyP(true, true), output.toString());
+ assertEquals(getTrueP(true, true), outputb.toString());
+ assertEquals(getAnswerP(true, true), outputa.toString());
+
+ // Namespaces set, schema set, meta set
+ output.reset();
+ outputb.reset();
+ outputa.reset();
+ e.emit();
+ b.emit();
+ a.emit();
+ assertEquals(getEmptyP(true, true), output.toString());
+ assertEquals(getTrueP(true, true), outputb.toString());
+ assertEquals(getAnswerP(true, true), outputa.toString());
+
+ // Namespaces set, no schema, meta set
+ output.reset();
+ outputb.reset();
+ outputa.reset();
+ e.emit();
+ b.emit();
+ a.emit();
+ assertEquals(getEmptyP(false, true), output.toString());
+ assertEquals(getTrueP(false, true), outputb.toString());
+ assertEquals(getAnswerP(false, true), outputa.toString());
+
+ e = new StreamedSparqlJSONAnswer(empty, output);
+ b = new StreamedSparqlJSONAnswer(true, outputb);
+ a = new StreamedSparqlJSONAnswer(answer, outputa);
+
+ // No namespaces, schema set, no meta
+ output.reset();
+ outputb.reset();
+ outputa.reset();
+ e.emit();
+ b.emit();
+ a.emit();
+ assertEquals(getEmptyP(true, false), output.toString());
+ assertEquals(getTrueP(true, false), outputb.toString());
+ assertEquals(getAnswerP(true, false), outputa.toString());
+
+ // Namespaces set, schema set, no meta
+ output.reset();
+ outputb.reset();
+ outputa.reset();
+ e.emit();
+ b.emit();
+ a.emit();
+ assertEquals(getEmptyP(true, false), output.toString());
+ assertEquals(getTrueP(true, false), outputb.toString());
+ assertEquals(getAnswerP(true, false), outputa.toString());
+
+ // Namespaces set, no schema, no meta
+ output.reset();
+ outputb.reset();
+ outputa.reset();
+ e.emit();
+ b.emit();
+ a.emit();
+ assertEquals(getEmptyP(false, false), output.toString());
+ assertEquals(getTrueP(false, false), outputb.toString());
+ assertEquals(getAnswerP(false, false), outputa.toString());
+
+ // No Namespaces, no schema, no meta
+ output.reset();
+ outputb.reset();
+ outputa.reset();
+ e.emit();
+ b.emit();
+ a.emit();
+ assertEquals(getEmptyP(false, false), output.toString());
+ assertEquals(getTrueP(false, false), outputb.toString());
+ assertEquals(getAnswerP(false, false), outputa.toString());
+
+ // No namespaces, schema set, no meta
+ output.reset();
+ outputb.reset();
+ outputa.reset();
+ e.emit();
+ b.emit();
+ a.emit();
+ assertEquals(getEmptyP(true, false), output.toString());
+ assertEquals(getTrueP(true, false), outputb.toString());
+ assertEquals(getAnswerP(true, false), outputa.toString());
+ }
+
+
+ /**
+ * Populate the test answer.
+ * @throws Exception Error setting up the ResultSet
+ */
+ protected void setUp() throws Exception {
+ TestResultSet trs1 = new TestResultSet(new String[] { "x", "y" });
+ ResultSetRow row;
+ row = new ResultSetRow(trs1);
+ row.setObject("x", new LiteralImpl("X1"));
+ row.setObject("y", new URIReferenceImpl(URI.create("urn:y1")));
+ trs1.addRow(row);
+ row = new ResultSetRow(trs1);
+ row.setObject("x", new LiteralImpl("X2", "en"));
+ row.setObject("y", new BlankNodeImpl(42));
+ trs1.addRow(row);
+ answer = new AnswerImpl(trs1);
+
+ List<Variable> variables = Arrays.asList(new Variable[] { new Variable("x") });
+ empty = new AnswerImpl(variables);
+
+ output = new ByteArrayOutputStream();
+ outputb = new ByteArrayOutputStream();
+ outputa = new ByteArrayOutputStream();
+ }
+
+ /**
+ * Clean up the test answer.
+ */
+ public void tearDown() {
+ answer.close();
+ empty.close();
+ }
+
+ /////////////////////////////
+ // start of getEmpty variants
+ /////////////////////////////
+
+ private static String getEmpty() {
+ return getEmpty(false, false);
+ }
+
+ private static String getEmptyP() {
+ return getEmptyP(false, false);
+ }
+
+ private static String getEmpty(boolean schema, boolean meta) {
+ return getCommonStart(schema, meta) + EMPTY_BODY;
+ }
+
+ private static String getEmptyP(boolean schema, boolean meta) {
+ return getCommonStartP(schema, meta) + EMPTY_BODY_P;
+ }
+
+ ////////////////////////////
+ // start of getTrue variants
+ ////////////////////////////
+
+ private static String getTrue() {
+ return getTrue(false, false);
+ }
+
+ private static String getTrueP() {
+ return getTrueP(false, false);
+ }
+
+ private static String getTrue(boolean schema, boolean meta) {
+ return getCommonStart(schema, meta) + TRUE_BODY;
+ }
+
+ private static String getTrueP(boolean schema, boolean meta) {
+ return getCommonStartP(schema, meta) + TRUE_BODY_P;
+ }
+
+ //////////////////////////////
+ // start of getAnswer variants
+ //////////////////////////////
+
+ private static String getAnswer() {
+ return getAnswer(false, false);
+ }
+
+ private static String getAnswerP() {
+ return getAnswerP(false, false);
+ }
+
+ private static String getAnswer(boolean schema, boolean meta) {
+ return getShortCommonStart(schema) + ANSWER_VARS + getMeta(meta) + ANSWER_BODY;
+ }
+
+ private static String getAnswerP(boolean schema, boolean meta) {
+ return getShortCommonStartP(schema) + ANSWER_VARS_P + getMetaP(meta) + ANSWER_BODY_P;
+ }
+
+ ////////////////
+ // common header
+ ////////////////
+
+ private static String getCommonStart(boolean schema, boolean meta) {
+ return getShortCommonStart(schema) + getMeta(meta);
+ }
+
+ private static String getCommonStartP(boolean schema, boolean meta) {
+ return getShortCommonStartP(schema) + getMetaP(meta);
+ }
+
+ private static String getShortCommonStart(boolean schema) {
+ String result = DOC_HEAD + SPARQL_HEAD;
+ if (schema) result += " " + SPARQL_HEAD_ATTR;
+ result += ">" + EMPTY_HEAD;
+ return result;
+ }
+
+ private static String getShortCommonStartP(boolean schema) {
+ String result = DOC_HEAD + SPARQL_HEAD;
+ if (schema) result += "\n" + SPARQL_HEAD_INDENT + SPARQL_HEAD_ATTR;
+ result += ">\n " + EMPTY_HEAD + "\n";
+ return result;
+ }
+
+ private static String getMeta(boolean meta) {
+ return meta ? HEAD_META : "";
+ }
+
+ private static String getMetaP(boolean meta) {
+ return meta ? HEAD_META_INDENT + HEAD_META + "\n" : "";
+ }
+
+ static final String DOC_HEAD = "<?xml version=\"1.0\"?>\n";
+
+ static final String SPARQL_HEAD = "<sparql xmlns=\"http://www.w3.org/2005/sparql-results#\"";
+
+ static final String SPARQL_HEAD_ATTR = "xsi:schemaLocation=\"http://www.w3.org/2007/SPARQL/result.xsd\"";
+
+ static final String SPARQL_HEAD_INDENT = " ";
+
+ static final String HEAD_META = "<link href=\"" + REL_URI + "\"/>";
+
+ static final String HEAD_META_INDENT = " ";
+
+ static final String EMPTY_HEAD = "<head>";
+
+ static final String EMPTY_BODY = "</head><results></results></sparql>";
+
+ static final String EMPTY_BODY_P = " </head>\n" +
+ " <results>\n" +
+ " </results>\n" +
+ "</sparql>";
+
+ static final String TRUE_BODY = "</head><boolean>true</boolean></sparql>";
+
+ static final String TRUE_BODY_P = " </head>\n" +
+ " <boolean>true</boolean>\n" +
+ "</sparql>";
+
+ static final String ANSWER_VARS = "<variable name=\"x\"/><variable name=\"y\"/>";
+
+ static final String ANSWER_BODY = "</head>" +
+ "<results>" +
+ "<result><binding name=\"x\"><literal>X1</literal></binding>" +
+ "<binding name=\"y\"><uri>urn:y1</uri></binding></result>" +
+ "<result><binding name=\"x\"><literal xml:lang=\"en\">X2</literal></binding>" +
+ "<binding name=\"y\"><bnode>_node42</bnode></binding></result>" +
+ "</results>" +
+ "</sparql>";
+
+ static final String ANSWER_VARS_P = " <variable name=\"x\"/>\n" +
+ " <variable name=\"y\"/>\n";
+
+ static final String ANSWER_BODY_P = " </head>\n" +
+ " <results>\n" +
+ " <result>\n" +
+ " <binding name=\"x\">\n" +
+ " <literal>X1</literal>\n" +
+ " </binding>\n" +
+ " <binding name=\"y\">\n" +
+ " <uri>urn:y1</uri>\n" +
+ " </binding>\n" +
+ " </result>\n" +
+ " <result>\n" +
+ " <binding name=\"x\">\n" +
+ " <literal xml:lang=\"en\">X2</literal>\n" +
+ " </binding>\n" +
+ " <binding name=\"y\">\n" +
+ " <bnode>_node42</bnode>\n" +
+ " </binding>\n" +
+ " </result>\n" +
+ " </results>\n" +
+ "</sparql>";
+}
Added: trunk/src/jar/querylang/java/org/mulgara/protocol/StreamedSparqlXMLAnswer.java
===================================================================
--- trunk/src/jar/querylang/java/org/mulgara/protocol/StreamedSparqlXMLAnswer.java (rev 0)
+++ trunk/src/jar/querylang/java/org/mulgara/protocol/StreamedSparqlXMLAnswer.java 2008-09-03 14:56:28 UTC (rev 1223)
@@ -0,0 +1,187 @@
+/*
+ * The contents of this file are subject to the Open Software License
+ * Version 3.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.opensource.org/licenses/osl-3.0.txt
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ */
+
+package org.mulgara.protocol;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.URI;
+import java.util.Map;
+
+import org.jrdf.graph.BlankNode;
+import org.jrdf.graph.Literal;
+import org.jrdf.graph.URIReference;
+import org.mulgara.query.Answer;
+import org.mulgara.query.BooleanAnswer;
+import org.mulgara.query.TuplesException;
+import org.mulgara.query.Variable;
+
+/**
+ * Represents an Answer as XML.
+ * The format is specified at: {@link http://www.w3.org/TR/rdf-sparql-XMLres/}
+ *
+ * @created Jul 8, 2008
+ * @author Paul Gearon
+ * @copyright © 2008 <a href="http://www.topazproject.org/">The Topaz Project</a>
+ * @licence <a href="{@docRoot}/../../LICENCE.txt">Open Software License v3.0</a>
+ */
+public class StreamedSparqlXMLAnswer extends AbstractStreamedXMLAnswer {
+
+ /** Indent to use for namespaces in the document header. */
+ private static final String HEADER_INDENT = "\n ";
+
+ /** Indicates that the W3C Schema should be used. */
+ boolean useW3CSchema = false;
+
+ /** Additional metadata about the results. */
+ URI additionalMetadata = null;
+
+ /** Boolean answer. */
+ boolean booleanResult = false;
+
+ /**
+ * Creates an XML Answer conforming to SPARQL XML results.
+ * @param answer The Answer to wrap.
+ */
+ public StreamedSparqlXMLAnswer(Answer answer, OutputStream output) {
+ super((answer instanceof BooleanAnswer) ? null : answer, output);
+ if (answer instanceof BooleanAnswer) booleanResult = ((BooleanAnswer)answer).getResult();
+ }
+
+ /**
+ * Creates an XML Answer with additional metadata.
+ * @param answer The Answer to wrap.
+ * @param metadata Additional metadata for the answer.
+ */
+ public StreamedSparqlXMLAnswer(Answer answer, URI metadata, OutputStream output) {
+ this(answer, output);
+ additionalMetadata = metadata;
+ }
+
+ /**
+ * Creates an XML Answer conforming to SPARQL XML results.
+ * @param result The boolean result to encode.
+ */
+ public StreamedSparqlXMLAnswer(boolean result, OutputStream output) {
+ super(null, output);
+ booleanResult = result;
+ }
+
+ /**
+ * Creates an XML Answer with additional metadata.
+ * @param result The boolean result to encode.
+ * @param metadata Additional metadata for the answer.
+ */
+ public StreamedSparqlXMLAnswer(boolean result, URI metadata, OutputStream output) {
+ super(null, output);
+ booleanResult = result;
+ additionalMetadata = metadata;
+ }
+
+ /**
+ * Set this XMLAnswer to use the W3C Schema for SPARQL results.
+ * @param use Set to <code>true</code> if the W3C schema should be used.
+ */
+ public void useW3CSchema(boolean use) {
+ useW3CSchema = use;
+ s = null;
+ }
+
+ /** {@inheritDoc} */
+ protected void addDocHeader() throws IOException {
+ s.append("<?xml version=\"1.0\"?>\n");
+ s.append("<sparql xmlns=\"http://www.w3.org/2005/sparql-results#\"");
+ for (Map.Entry<String,URI> ns: namespaces.entrySet()) {
+ s.append(prettyPrint ? HEADER_INDENT : " ");
+ s.append(ns.getKey()).append("=\"").append(ns.getValue().toString()).append("\"");
+ }
+ if (useW3CSchema) s.append(prettyPrint ? HEADER_INDENT : " ").append("xsi:schemaLocation=\"http://www.w3.org/2007/SPARQL/result.xsd\"");
+ s.append(">");
+ }
+
+ /** {@inheritDoc} */
+ protected void addDocFooter() throws IOException {
+ s.append(i(0)).append("</sparql>");
+ }
+
+ /** {@inheritDoc} */
+ protected void addHeader() throws IOException {
+ s.append(i(1)).append("<head>");
+ if (answer != null && answer.getVariables() != null) {
+ for (Variable v: answer.getVariables()) addHeaderVariable(v);
+ }
+ if (additionalMetadata != null) {
+ s.append(i(2)).append("<link href=\"").append(additionalMetadata.toString()).append("\"/>");
+ }
+ s.append(i(1)).append("</head>");
+ }
+
+ /** {@inheritDoc} */
+ protected void addHeaderVariable(Variable var) throws IOException {
+ s.append(i(2)).append("<variable name=\"");
+ s.append(var.getName()).append("\"/>");
+ }
+
+ /** {@inheritDoc} */
+ protected void addResults() throws TuplesException, IOException {
+ if (answer != null) {
+ s.append(i(1)).append("<results>");
+ answer.beforeFirst();
+ while (answer.next()) addResult();
+ s.append(i(1)).append("</results>");
+ } else {
+ s.append(i(1)).append("<boolean>").append(Boolean.toString(booleanResult)).append("</boolean>");
+ }
+ }
+
+ /** {@inheritDoc} */
+ protected void addResult() throws TuplesException, IOException {
+ s.append(i(2)).append("<result>");
+ for (int c = 0; c < width; c++) addBinding(vars[c], answer.getObject(c));
+ s.append(i(2)).append("</result>");
+ }
+
+ /**
+ * {@inheritDoc}
+ * No binding will be emitted if the value is null (unbound).
+ */
+ protected void addBinding(Variable var, Object value) throws IOException {
+ if (value != null) {
+ s.append(i(3)).append("<binding name=\"").append(var.getName()).append("\">");
+ // no dynamic dispatch, so use if/then
+ if (value instanceof URIReference) addURI((URIReference)value);
+ else if (value instanceof Literal) addLiteral((Literal)value);
+ else if (value instanceof BlankNode) addBNode((BlankNode)value);
+ else throw new IllegalArgumentException("Unable to create a SPARQL response with an answer containing: " + value.getClass().getSimpleName());
+ s.append(i(3)).append("</binding>");
+ }
+ }
+
+ /** {@inheritDoc} */
+ protected void addURI(URIReference uri) throws IOException {
+ s.append(i(4)).append("<uri>").append(uri.getURI().toString()).append("</uri>");
+ }
+
+ /** {@inheritDoc} */
+ protected void addBNode(BlankNode bnode) throws IOException {
+ s.append(i(4)).append("<bnode>").append(bnode.toString()).append("</bnode>");
+ }
+
+ /** {@inheritDoc} */
+ protected void addLiteral(Literal literal) throws IOException {
+ s.append(i(4)).append("<literal");
+ if (literal.getLanguage() != null) s.append(" xml:lang=\"").append(literal.getLanguage()).append("\"");
+ else if (literal.getDatatype() != null) s.append(" datatype=\"").append(literal.getDatatype().toString()).append("\"");
+ s.append(">").append(literal.getLexicalForm()).append("</literal>");
+ }
+
+}
Added: trunk/src/jar/querylang/java/org/mulgara/protocol/StreamedSparqlXMLAnswerUnitTest.java
===================================================================
--- trunk/src/jar/querylang/java/org/mulgara/protocol/StreamedSparqlXMLAnswerUnitTest.java (rev 0)
+++ trunk/src/jar/querylang/java/org/mulgara/protocol/StreamedSparqlXMLAnswerUnitTest.java 2008-09-03 14:56:28 UTC (rev 1223)
@@ -0,0 +1,702 @@
+/*
+ * The contents of this file are subject to the Open Software License
+ * Version 3.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.opensource.org/licenses/osl-3.0.txt
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ */
+
+package org.mulgara.protocol;
+
+
+// JUnit
+import junit.framework.*;
+
+// Java 2 standard packages
+import java.io.ByteArrayOutputStream;
+import java.net.URI;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+// Locally written packages
+import org.mulgara.query.AnswerImpl;
+import org.mulgara.query.BooleanAnswer;
+import org.mulgara.query.Variable;
+import org.mulgara.query.rdf.BlankNodeImpl;
+import org.mulgara.query.rdf.LiteralImpl;
+import org.mulgara.query.rdf.URIReferenceImpl;
+import org.mulgara.util.ResultSetRow;
+import org.mulgara.util.TestResultSet;
+
+/**
+ * Test case for {@link StreamedSparqlXMLAnswer}.
+ *
+ * @created Jul 8, 2008
+ * @author Paul Gearon
+ * @copyright © 2008 <a href="http://www.topazproject.org/">The Topaz Project</a>
+ * @licence <a href="{@docRoot}/../../LICENCE.txt">Open Software License v3.0</a>
+ */
+public class StreamedSparqlXMLAnswerUnitTest extends TestCase {
+
+ /**
+ * Test instance.
+ * <table>
+ * <thead>
+ * <tr><th>x</th> <th>y</th></tr>
+ * </thead>
+ * <tbody>
+ * <tr><td>X1</td><td>Y1</td></tr>
+ * <tr><td>X2</td><td>Y2</td></tr>
+ * </tbody>
+ * </table>
+ */
+ private AnswerImpl answer;
+
+ private AnswerImpl empty;
+
+ private Map<String,String> namesp = new HashMap<String,String>();
+
+ private ByteArrayOutputStream output;
+
+ private ByteArrayOutputStream outputb;
+
+ private ByteArrayOutputStream outputa;
+
+ private static final URI REL_URI = URI.create("rel/uri");
+
+ private static final String NAME1 = "ns1";
+
+ private static final String NAME2 = "ns2";
+
+ private static final URI NS1 = URI.create("http://mulgara.org/test/ns1");
+
+ private static final URI NS2 = URI.create("http://mulgara.org/test/ns2");
+
+ /**
+ * Constructs a new answer test with the given name.
+ * @param name the name of the test
+ */
+ public StreamedSparqlXMLAnswerUnitTest(String name) {
+ super(name);
+ }
+
+ /**
+ * Hook for test runner to obtain a test suite from.
+ * @return The test suite
+ */
+ public static Test suite() {
+ TestSuite suite = new TestSuite();
+ suite.addTest(new StreamedSparqlXMLAnswerUnitTest("testEmptyConstructor"));
+ suite.addTest(new StreamedSparqlXMLAnswerUnitTest("testEmptyConstructorPretty"));
+ suite.addTest(new StreamedSparqlXMLAnswerUnitTest("testBooleanAnswer"));
+ suite.addTest(new StreamedSparqlXMLAnswerUnitTest("testBooleanAnswerPretty"));
+ suite.addTest(new StreamedSparqlXMLAnswerUnitTest("testPrettyPrint"));
+ suite.addTest(new StreamedSparqlXMLAnswerUnitTest("testCompactPrint"));
+ suite.addTest(new StreamedSparqlXMLAnswerUnitTest("testPrettyPrintVariations"));
+ suite.addTest(new StreamedSparqlXMLAnswerUnitTest("testCompactPrintVariations"));
+ return suite;
+ }
+
+ /**
+ * Default text runner.
+ * @param args The command line arguments
+ */
+ public static void main(String[] args) {
+ junit.textui.TestRunner.run(suite());
+ }
+
+
+ /**
+ * Tests an empty answer.
+ * @throws Exception On error
+ */
+ public void testEmptyConstructor() throws Exception {
+ StreamedSparqlXMLAnswer a = new StreamedSparqlXMLAnswer(empty, output);
+ a.setPrettyPrint(false);
+ a.emit();
+ assertEquals(getEmpty(), output.toString());
+ }
+
+
+ /**
+ * Tests an empty answer.
+ * @throws Exception On error
+ */
+ public void testEmptyConstructorPretty() throws Exception {
+ StreamedSparqlXMLAnswer a = new StreamedSparqlXMLAnswer(empty, output);
+ a.emit();
+ assertEquals(getEmptyP(), output.toString());
+
+ a.setPrettyPrint(false);
+ output.reset();
+ a.emit();
+ assertEquals(getEmpty(), output.toString());
+ }
+
+
+ /**
+ * Tests a boolean answer.
+ * @throws Exception On error
+ */
+ public void testBooleanAnswer() throws Exception {
+ StreamedSparqlXMLAnswer a = new StreamedSparqlXMLAnswer(true, output);
+ a.setPrettyPrint(false);
+ a.emit();
+ assertEquals(getTrue(), output.toString());
+
+ a = new StreamedSparqlXMLAnswer(new BooleanAnswer(true), output);
+ a.setPrettyPrint(false);
+ output.reset();
+ a.emit();
+ assertEquals(getTrue(), output.toString());
+ }
+
+
+ /**
+ * Tests a boolean answer.
+ * @throws Exception On error
+ */
+ public void testBooleanAnswerPretty() throws Exception {
+ StreamedSparqlXMLAnswer a = new StreamedSparqlXMLAnswer(true, output);
+ a.emit();
+ assertEquals(getTrueP(), output.toString());
+ a.setPrettyPrint(false);
+ output.reset();
+ a.emit();
+ assertEquals(getTrue(), output.toString());
+ }
+
+
+ /**
+ * Test main structure.
+ */
+ public void testPrettyPrint() throws Exception {
+ StreamedSparqlXMLAnswer a = new StreamedSparqlXMLAnswer(answer, output);
+ a.emit();
+ assertEquals(getAnswerP(), output.toString());
+ }
+
+
+ /**
+ * Test main structure.
+ */
+ public void testCompactPrint() throws Exception {
+ StreamedSparqlXMLAnswer a = new StreamedSparqlXMLAnswer(answer, output);
+ a.setPrettyPrint(false);
+ a.emit();
+ assertEquals(getAnswer(), output.toString());
+ }
+
+
+ /**
+ * Tests the variations of answers.
+ * @throws Exception On error
+ */
+ public void testCompactPrintVariations() throws Exception {
+ StreamedSparqlXMLAnswer e = new StreamedSparqlXMLAnswer(empty, REL_URI, output);
+ StreamedSparqlXMLAnswer b = new StreamedSparqlXMLAnswer(true, REL_URI, outputb);
+ StreamedSparqlXMLAnswer a = new StreamedSparqlXMLAnswer(answer, REL_URI, outputa);
+ e.setPrettyPrint(false);
+ b.setPrettyPrint(false);
+ a.setPrettyPrint(false);
+
+ // No namespaces, no schema, meta set
+ e.emit();
+ b.emit();
+ a.emit();
+ assertEquals(getEmpty(null, false, true), output.toString());
+ assertEquals(getTrue(null, false, true), outputb.toString());
+ assertEquals(getAnswer(null, false, true), outputa.toString());
+
+ e.useW3CSchema(true);
+ b.useW3CSchema(true);
+ a.useW3CSchema(true);
+
+ // No namespaces, schema set, meta set
+ output.reset();
+ outputb.reset();
+ outputa.reset();
+ e.emit();
+ b.emit();
+ a.emit();
+ assertEquals(getEmpty(null, true, true), output.toString());
+ assertEquals(getTrue(null, true, true), outputb.toString());
+ assertEquals(getAnswer(null, true, true), outputa.toString());
+
+ e.addNamespace(NAME1, NS1);
+ e.addNamespace(NAME2, NS2);
+ b.addNamespace(NAME1, NS1);
+ b.addNamespace(NAME2, NS2);
+ a.addNamespace(NAME1, NS1);
+ a.addNamespace(NAME2, NS2);
+
+ // Namespaces set, schema set, meta set
+ output.reset();
+ outputb.reset();
+ outputa.reset();
+ e.emit();
+ b.emit();
+ a.emit();
+ assertEquals(getEmpty(namesp, true, true), output.toString());
+ assertEquals(getTrue(namesp, true, true), outputb.toString());
+ assertEquals(getAnswer(namesp, true, true), outputa.toString());
+
+ e.useW3CSchema(false);
+ b.useW3CSchema(false);
+ a.useW3CSchema(false);
+
+ // Namespaces set, no schema, meta set
+ output.reset();
+ outputb.reset();
+ outputa.reset();
+ e.emit();
+ b.emit();
+ a.emit();
+ assertEquals(getEmpty(namesp, false, true), output.toString());
+ assertEquals(getTrue(namesp, false, true), outputb.toString());
+ assertEquals(getAnswer(namesp, false, true), outputa.toString());
+
+ e = new StreamedSparqlXMLAnswer(empty, output);
+ b = new StreamedSparqlXMLAnswer(true, outputb);
+ a = new StreamedSparqlXMLAnswer(answer, outputa);
+
+ e.setPrettyPrint(false);
+ b.setPrettyPrint(false);
+ a.setPrettyPrint(false);
+
+ e.useW3CSchema(true);
+ b.useW3CSchema(true);
+ a.useW3CSchema(true);
+
+ // No namespaces, schema set, no meta
+ output.reset();
+ outputb.reset();
+ outputa.reset();
+ e.emit();
+ b.emit();
+ a.emit();
+ assertEquals(getEmpty(null, true, false), output.toString());
+ assertEquals(getTrue(null, true, false), outputb.toString());
+ assertEquals(getAnswer(null, true, false), outputa.toString());
+
+ e.addNamespace(NAME1, NS1);
+ e.addNamespace(NAME2, NS2);
+ b.addNamespace(NAME1, NS1);
+ b.addNamespace(NAME2, NS2);
+ a.addNamespace(NAME1, NS1);
+ a.addNamespace(NAME2, NS2);
+
+ // Namespaces set, schema set, no meta
+ output.reset();
+ outputb.reset();
+ outputa.reset();
+ e.emit();
+ b.emit();
+ a.emit();
+ assertEquals(getEmpty(namesp, true, false), output.toString());
+ assertEquals(getTrue(namesp, true, false), outputb.toString());
+ assertEquals(getAnswer(namesp, true, false), outputa.toString());
+
+ e.useW3CSchema(false);
+ b.useW3CSchema(false);
+ a.useW3CSchema(false);
+
+ // Namespaces set, no schema, no meta
+ output.reset();
+ outputb.reset();
+ outputa.reset();
+ e.emit();
+ b.emit();
+ a.emit();
+ assertEquals(getEmpty(namesp, false, false), output.toString());
+ assertEquals(getTrue(namesp, false, false), outputb.toString());
+ assertEquals(getAnswer(namesp, false, false), outputa.toString());
+
+ e.clearNamespaces();
+ b.clearNamespaces();
+ a.clearNamespaces();
+
+ // No Namespaces, no schema, no meta
+ output.reset();
+ outputb.reset();
+ outputa.reset();
+ e.emit();
+ b.emit();
+ a.emit();
+ assertEquals(getEmpty(null, false, false), output.toString());
+ assertEquals(getTrue(null, false, false), outputb.toString());
+ assertEquals(getAnswer(null, false, false), outputa.toString());
+
+ e.useW3CSchema(true);
+ b.useW3CSchema(true);
+ a.useW3CSchema(true);
+
+ // No namespaces, schema set, no meta
+ output.reset();
+ outputb.reset();
+ outputa.reset();
+ e.emit();
+ b.emit();
+ a.emit();
+ assertEquals(getEmpty(null, true, false), output.toString());
+ assertEquals(getTrue(null, true, false), outputb.toString());
+ assertEquals(getAnswer(null, true, false), outputa.toString());
+ }
+
+
+ /**
+ * Tests the variations of answers.
+ * @throws Exception On error
+ */
+ public void testPrettyPrintVariations() throws Exception {
+ StreamedSparqlXMLAnswer e = new StreamedSparqlXMLAnswer(empty, REL_URI, output);
+ StreamedSparqlXMLAnswer b = new StreamedSparqlXMLAnswer(true, REL_URI, outputb);
+ StreamedSparqlXMLAnswer a = new StreamedSparqlXMLAnswer(answer, REL_URI, outputa);
+ e.setPrettyPrint(true);
+ b.setPrettyPrint(true);
+ a.setPrettyPrint(true);
+
+ // No namespaces, no schema, meta set
+ e.emit();
+ b.emit();
+ a.emit();
+ assertEquals(getEmptyP(null, false, true), output.toString());
+ assertEquals(getTrueP(null, false, true), outputb.toString());
+ assertEquals(getAnswerP(null, false, true), outputa.toString());
+
+ e.useW3CSchema(true);
+ b.useW3CSchema(true);
+ a.useW3CSchema(true);
+
+ // No namespaces, schema set, meta set
+ output.reset();
+ outputb.reset();
+ outputa.reset();
+ e.emit();
+ b.emit();
+ a.emit();
+ assertEquals(getEmptyP(null, true, true), output.toString());
+ assertEquals(getTrueP(null, true, true), outputb.toString());
+ assertEquals(getAnswerP(null, true, true), outputa.toString());
+
+ e.addNamespace(NAME1, NS1);
+ e.addNamespace(NAME2, NS2);
+ b.addNamespace(NAME1, NS1);
+ b.addNamespace(NAME2, NS2);
+ a.addNamespace(NAME1, NS1);
+ a.addNamespace(NAME2, NS2);
+
+ // Namespaces set, schema set, meta set
+ output.reset();
+ outputb.reset();
+ outputa.reset();
+ e.emit();
+ b.emit();
+ a.emit();
+ assertEquals(getEmptyP(namesp, true, true), output.toString());
+ assertEquals(getTrueP(namesp, true, true), outputb.toString());
+ assertEquals(getAnswerP(namesp, true, true), outputa.toString());
+
+ e.useW3CSchema(false);
+ b.useW3CSchema(false);
+ a.useW3CSchema(false);
+
+ // Namespaces set, no schema, meta set
+ output.reset();
+ outputb.reset();
+ outputa.reset();
+ e.emit();
+ b.emit();
+ a.emit();
+ assertEquals(getEmptyP(namesp, false, true), output.toString());
+ assertEquals(getTrueP(namesp, false, true), outputb.toString());
+ assertEquals(getAnswerP(namesp, false, true), outputa.toString());
+
+ e = new StreamedSparqlXMLAnswer(empty, output);
+ b = new StreamedSparqlXMLAnswer(true, outputb);
+ a = new StreamedSparqlXMLAnswer(answer, outputa);
+
+ e.useW3CSchema(true);
+ b.useW3CSchema(true);
+ a.useW3CSchema(true);
+
+ // No namespaces, schema set, no meta
+ output.reset();
+ outputb.reset();
+ outputa.reset();
+ e.emit();
+ b.emit();
+ a.emit();
+ assertEquals(getEmptyP(null, true, false), output.toString());
+ assertEquals(getTrueP(null, true, false), outputb.toString());
+ assertEquals(getAnswerP(null, true, false), outputa.toString());
+
+ e.addNamespace(NAME1, NS1);
+ e.addNamespace(NAME2, NS2);
+ b.addNamespace(NAME1, NS1);
+ b.addNamespace(NAME2, NS2);
+ a.addNamespace(NAME1, NS1);
+ a.addNamespace(NAME2, NS2);
+
+ // Namespaces set, schema set, no meta
+ output.reset();
+ outputb.reset();
+ outputa.reset();
+ e.emit();
+ b.emit();
+ a.emit();
+ assertEquals(getEmptyP(namesp, true, false), output.toString());
+ assertEquals(getTrueP(namesp, true, false), outputb.toString());
+ assertEquals(getAnswerP(namesp, true, false), outputa.toString());
+
+ e.useW3CSchema(false);
+ b.useW3CSchema(false);
+ a.useW3CSchema(false);
+
+ // Namespaces set, no schema, no meta
+ output.reset();
+ outputb.reset();
+ outputa.reset();
+ e.emit();
+ b.emit();
+ a.emit();
+ assertEquals(getEmptyP(namesp, false, false), output.toString());
+ assertEquals(getTrueP(namesp, false, false), outputb.toString());
+ assertEquals(getAnswerP(namesp, false, false), outputa.toString());
+
+ e.clearNamespaces();
+ b.clearNamespaces();
+ a.clearNamespaces();
+
+ // No Namespaces, no schema, no meta
+ output.reset();
+ outputb.reset();
+ outputa.reset();
+ e.emit();
+ b.emit();
+ a.emit();
+ assertEquals(getEmptyP(null, false, false), output.toString());
+ assertEquals(getTrueP(null, false, false), outputb.toString());
+ assertEquals(getAnswerP(null, false, false), outputa.toString());
+
+ e.useW3CSchema(true);
+ b.useW3CSchema(true);
+ a.useW3CSchema(true);
+
+ // No namespaces, schema set, no meta
+ output.reset();
+ outputb.reset();
+ outputa.reset();
+ e.emit();
+ b.emit();
+ a.emit();
+ assertEquals(getEmptyP(null, true, false), output.toString());
+ assertEquals(getTrueP(null, true, false), outputb.toString());
+ assertEquals(getAnswerP(null, true, false), outputa.toString());
+ }
+
+
+ /**
+ * Populate the test answer.
+ * @throws Exception Error setting up the ResultSet
+ */
+ protected void setUp() throws Exception {
+ TestResultSet trs1 = new TestResultSet(new String[] { "x", "y" });
+ ResultSetRow row;
+ row = new ResultSetRow(trs1);
+ row.setObject("x", new LiteralImpl("X1"));
+ row.setObject("y", new URIReferenceImpl(URI.create("urn:y1")));
+ trs1.addRow(row);
+ row = new ResultSetRow(trs1);
+ row.setObject("x", new LiteralImpl("X2", "en"));
+ row.setObject("y", new BlankNodeImpl(42));
+ trs1.addRow(row);
+ answer = new AnswerImpl(trs1);
+
+ List<Variable> variables = Arrays.asList(new Variable[] { new Variable("x") });
+ empty = new AnswerImpl(variables);
+
+ namesp.put(NAME1, NS1.toString());
+ namesp.put(NAME2, NS2.toString());
+
+ output = new ByteArrayOutputStream();
+ outputb = new ByteArrayOutputStream();
+ outputa = new ByteArrayOutputStream();
+ }
+
+ /**
+ * Clean up the test answer.
+ */
+ public void tearDown() {
+ answer.close();
+ empty.close();
+ }
+
+ /////////////////////////////
+ // start of getEmpty variants
+ /////////////////////////////
+
+ private static String getEmpty() {
+ return getEmpty(null, false, false);
+ }
+
+ private static String getEmptyP() {
+ return getEmptyP(null, false, false);
+ }
+
+ private static String getEmpty(Map<String,String> ns, boolean schema, boolean meta) {
+ return getCommonStart(ns, schema, meta) + EMPTY_BODY;
+ }
+
+ private static String getEmptyP(Map<String,String> ns, boolean schema, boolean meta) {
+ return getCommonStartP(ns, schema, meta) + EMPTY_BODY_P;
+ }
+
+ ////////////////////////////
+ // start of getTrue variants
+ ////////////////////////////
+
+ private static String getTrue() {
+ return getTrue(null, false, false);
+ }
+
+ private static String getTrueP() {
+ return getTrueP(null, false, false);
+ }
+
+ private static String getTrue(Map<String,String> ns, boolean schema, boolean meta) {
+ return getCommonStart(ns, schema, meta) + TRUE_BODY;
+ }
+
+ private static String getTrueP(Map<String,String> ns, boolean schema, boolean meta) {
+ return getCommonStartP(ns, schema, meta) + TRUE_BODY_P;
+ }
+
+ //////////////////////////////
+ // start of getAnswer variants
+ //////////////////////////////
+
+ private static String getAnswer() {
+ return getAnswer(null, false, false);
+ }
+
+ private static String getAnswerP() {
+ return getAnswerP(null, false, false);
+ }
+
+ private static String getAnswer(Map<String,String> ns, boolean schema, boolean meta) {
+ return getShortCommonStart(ns, schema) + ANSWER_VARS + getMeta(meta) + ANSWER_BODY;
+ }
+
+ private static String getAnswerP(Map<String,String> ns, boolean schema, boolean meta) {
+ return getShortCommonStartP(ns, schema) + ANSWER_VARS_P + getMetaP(meta) + ANSWER_BODY_P;
+ }
+
+ ////////////////
+ // common header
+ ////////////////
+
+ private static String getCommonStart(Map<String,String> ns, boolean schema, boolean meta) {
+ return getShortCommonStart(ns, schema) + getMeta(meta);
+ }
+
+ private static String getCommonStartP(Map<String,String> ns, boolean schema, boolean meta) {
+ return getShortCommonStartP(ns, schema) + getMetaP(meta);
+ }
+
+ private static String getShortCommonStart(Map<String,String> ns, boolean schema) {
+ String result = DOC_HEAD + SPARQL_HEAD;
+ if (ns != null) {
+ for (String k: ns.keySet()) result += " " + k + "=\"" + ns.get(k) + "\"";
+ }
+ if (schema) result += " " + SPARQL_HEAD_ATTR;
+ result += ">" + EMPTY_HEAD;
+ return result;
+ }
+
+ private static String getShortCommonStartP(Map<String,String> ns, boolean schema) {
+ String result = DOC_HEAD + SPARQL_HEAD;
+ if (ns != null) {
+ for (String k: ns.keySet()) result += "\n" + SPARQL_HEAD_INDENT + k + "=\"" + ns.get(k) + "\"";
+ }
+ if (schema) result += "\n" + SPARQL_HEAD_INDENT + SPARQL_HEAD_ATTR;
+ result += ">\n " + EMPTY_HEAD + "\n";
+ return result;
+ }
+
+ private static String getMeta(boolean meta) {
+ return meta ? HEAD_META : "";
+ }
+
+ private static String getMetaP(boolean meta) {
+ return meta ? HEAD_META_INDENT + HEAD_META + "\n" : "";
+ }
+
+ static final String DOC_HEAD = "<?xml version=\"1.0\"?>\n";
+
+ static final String SPARQL_HEAD = "<sparql xmlns=\"http://www.w3.org/2005/sparql-results#\"";
+
+ static final String SPARQL_HEAD_ATTR = "xsi:schemaLocation=\"http://www.w3.org/2007/SPARQL/result.xsd\"";
+
+ static final String SPARQL_HEAD_INDENT = " ";
+
+ static final String HEAD_META = "<link href=\"" + REL_URI + "\"/>";
+
+ static final String HEAD_META_INDENT = " ";
+
+ static final String EMPTY_HEAD = "<head>";
+
+ static final String EMPTY_BODY = "</head><results></results></sparql>";
+
+ static final String EMPTY_BODY_P = " </head>\n" +
+ " <results>\n" +
+ " </results>\n" +
+ "</sparql>";
+
+ static final String TRUE_BODY = "</head><boolean>true</boolean></sparql>";
+
+ static final String TRUE_BODY_P = " </head>\n" +
+ " <boolean>true</boolean>\n" +
+ "</sparql>";
+
+ static final String ANSWER_VARS = "<variable name=\"x\"/><variable name=\"y\"/>";
+
+ static final String ANSWER_BODY = "</head>" +
+ "<results>" +
+ "<result><binding name=\"x\"><literal>X1</literal></binding>" +
+ "<binding name=\"y\"><uri>urn:y1</uri></binding></result>" +
+ "<result><binding name=\"x\"><literal xml:lang=\"en\">X2</literal></binding>" +
+ "<binding name=\"y\"><bnode>_node42</bnode></binding></result>" +
+ "</results>" +
+ "</sparql>";
+
+ static final String ANSWER_VARS_P = " <variable name=\"x\"/>\n" +
+ " <variable name=\"y\"/>\n";
+
+ static final String ANSWER_BODY_P = " </head>\n" +
+ " <results>\n" +
+ " <result>\n" +
+ " <binding name=\"x\">\n" +
+ " <literal>X1</literal>\n" +
+ " </binding>\n" +
+ " <binding name=\"y\">\n" +
+ " <uri>urn:y1</uri>\n" +
+ " </binding>\n" +
+ " </result>\n" +
+ " <result>\n" +
+ " <binding name=\"x\">\n" +
+ " <literal xml:lang=\"en\">X2</literal>\n" +
+ " </binding>\n" +
+ " <binding name=\"y\">\n" +
+ " <bnode>_node42</bnode>\n" +
+ " </binding>\n" +
+ " </result>\n" +
+ " </results>\n" +
+ "</sparql>";
+}
Added: trunk/src/jar/querylang/java/org/mulgara/protocol/StreamedTqlXMLAnswer.java
===================================================================
--- trunk/src/jar/querylang/java/org/mulgara/protocol/StreamedTqlXMLAnswer.java (rev 0)
+++ trunk/src/jar/querylang/java/org/mulgara/protocol/StreamedTqlXMLAnswer.java 2008-09-03 14:56:28 UTC (rev 1223)
@@ -0,0 +1,150 @@
+/*
+ * The contents of this file are subject to the Open Software License
+ * Version 3.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.opensource.org/licenses/osl-3.0.txt
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ */
+
+package org.mulgara.protocol;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import org.jrdf.graph.BlankNode;
+import org.jrdf.graph.Literal;
+import org.jrdf.graph.URIReference;
+import org.mulgara.query.Answer;
+import org.mulgara.query.TuplesException;
+import org.mulgara.query.Variable;
+
+/**
+ * Represents an Answer as TQL XML.
+ *
+ * @created Jul 8, 2008
+ * @author Paul Gearon
+ * @copyright © 2008 <a href="http://www.topazproject.org/">The Topaz Project</a>
+ * @licence <a href="{@docRoot}/../../LICENCE.txt">Open Software License v3.0</a>
+ */
+public class StreamedTqlXMLAnswer extends AbstractStreamedXMLAnswer {
+
+ /**
+ * Creates an XML Answer for XML results. Pretty printing is off by default.
+ * @param answer The Answer to wrap.
+ */
+ public StreamedTqlXMLAnswer(Answer answer, OutputStream output) {
+ super(answer, output);
+ setPrettyPrint(false);
+ }
+
+ /** {@inheritDoc} */
+ protected void addDocHeader() throws IOException {
+ s.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
+ s.append("<answer xmlns=\"http://mulgara.org/tql#\">");
+ s.append(i(1)).append("<query>");
+ }
+
+ /** {@inheritDoc} */
+ protected void addDocFooter() throws IOException {
+ s.append(i(1)).append("</query>");
+ s.append(i(0)).append("</answer>");
+ }
+
+ /** {@inheritDoc} */
+ protected void addHeader() throws IOException {
+ addHeader(answer, 0);
+ }
+
+ void addHeader(Answer a, int indent) throws IOException {
+ s.append(i(indent + 2)).append("<variables>");
+ if (a != null && a.getVariables() != null) for (Variable v: a.getVariables()) addHeaderVariable(v, indent);
+ s.append(i(indent + 2)).append("</variables>");
+ }
+
+ /** {@inheritDoc} */
+ protected void addHeaderVariable(Variable var) throws IOException {
+ addHeaderVariable(var, 0);
+ }
+
+ /** {@inheritDoc} */
+ protected void addHeaderVariable(Variable var, int indent) throws IOException {
+ s.append(i(indent + 3)).append("<").append(var.getName()).append("/>");
+ }
+
+ /** {@inheritDoc} */
+ protected void addResults() throws TuplesException, IOException {
+ answer.beforeFirst();
+ while (answer.next()) addResult();
+ }
+
+ /** {@inheritDoc} */
+ protected void addResults(Answer a, int indent) throws TuplesException, IOException {
+ a.beforeFirst();
+ while (a.next()) addResult(a, indent);
+ }
+
+ /** {@inheritDoc} */
+ protected void addResult() throws TuplesException, IOException {
+ addResult(answer, 0);
+ }
+
+ /** {@inheritDoc} */
+ protected void addResult(Answer a, int indent) throws TuplesException, IOException {
+ s.append(i(indent + 2)).append("<solution>");
+ for (int c = 0; c < width; c++) addBinding(vars[c], answer.getObject(c), indent);
+ s.append(i(indent + 2)).append("</solution>");
+ }
+
+ /**
+ * {@inheritDoc}
+ * No binding will be emitted if the value is null (unbound).
+ */
+ protected void addBinding(Variable var, Object value) throws TuplesException, IOException {
+ addBinding(var, value, 0);
+ }
+
+ /**
+ * {@inheritDoc}
+ * No binding will be emitted if the value is null (unbound).
+ * @throws TuplesException Indicates an error accessing the Answer.
+ */
+ protected void addBinding(Variable var, Object value, int indent) throws TuplesException, IOException {
+ if (value != null) {
+ s.append(i(indent + 3)).append("<").append(var.getName());
+ // no dynamic dispatch, so use if/then
+ if (value instanceof URIReference) {
+ addURI((URIReference)value);
+ } else if (value instanceof BlankNode) {
+ addBNode((BlankNode)value);
+ } else if (value instanceof Literal) {
+ addLiteral((Literal)value);
+ s.append("</").append(var.getName()).append(">");
+ } else if (value instanceof Answer) {
+ addHeader((Answer)value, indent + 4);
+ addResults((Answer)value, indent + 4);
+ } else throw new IllegalArgumentException("Unable to create a SPARQL response with an answer containing: " + value.getClass().getSimpleName());
+ }
+ }
+
+ /** {@inheritDoc} */
+ protected void addURI(URIReference uri) throws IOException {
+ s.append(" resource=\"").append(uri.getURI().toString()).append("\"/>");
+ }
+
+ /** {@inheritDoc} */
+ protected void addBNode(BlankNode bnode) throws IOException {
+ s.append(" blank-node=\"").append(bnode.toString()).append("\"/>");
+ }
+
+ /** {@inheritDoc} */
+ protected void addLiteral(Literal literal) throws IOException {
+ if (literal.getLanguage() != null) s.append(" language=\"").append(literal.getLanguage()).append("\"");
+ else if (literal.getDatatype() != null) s.append(" datatype=\"").append(literal.getDatatype().toString()).append("\"");
+ s.append(">").append(literal.getLexicalForm());
+ }
+
+}
Added: trunk/src/jar/querylang/java/org/mulgara/protocol/StreamedTqlXMLAnswerUnitTest.java
===================================================================
--- trunk/src/jar/querylang/java/org/mulgara/protocol/StreamedTqlXMLAnswerUnitTest.java (rev 0)
+++ trunk/src/jar/querylang/java/org/mulgara/protocol/StreamedTqlXMLAnswerUnitTest.java 2008-09-03 14:56:28 UTC (rev 1223)
@@ -0,0 +1,257 @@
+/*
+ * The contents of this file are subject to the Open Software License
+ * Version 3.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.opensource.org/licenses/osl-3.0.txt
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ */
+
+package org.mulgara.protocol;
+
+
+// JUnit
+import junit.framework.*;
+
+// Java 2 standard packages
+import java.io.ByteArrayOutputStream;
+import java.net.URI;
+import java.util.Arrays;
+import java.util.List;
+
+// Locally written packages
+import org.mulgara.query.AnswerImpl;
+import org.mulgara.query.BooleanAnswer;
+import org.mulgara.query.Variable;
+import org.mulgara.query.rdf.BlankNodeImpl;
+import org.mulgara.query.rdf.LiteralImpl;
+import org.mulgara.query.rdf.URIReferenceImpl;
+import org.mulgara.util.ResultSetRow;
+import org.mulgara.util.TestResultSet;
+
+/**
+ * Test case for {@link StreamedTqlXMLAnswer}.
+ *
+ * @created Jul 8, 2008
+ * @author Paul Gearon
+ * @copyright © 2008 <a href="http://www.topazproject.org/">The Topaz Project</a>
+ * @licence <a href="{@docRoot}/../../LICENCE.txt">Open Software License v3.0</a>
+ */
+public class StreamedTqlXMLAnswerUnitTest extends TestCase {
+
+ /**
+ * Test instance.
+ * <table>
+ * <thead>
+ * <tr><th>x</th> <th>y</th></tr>
+ * </thead>
+ * <tbody>
+ * <tr><td>X1</td><td>Y1</td></tr>
+ * <tr><td>X2</td><td>Y2</td></tr>
+ * </tbody>
+ * </table>
+ */
+ private AnswerImpl answer;
+
+ private AnswerImpl empty;
+
+ private ByteArrayOutputStream output;
+
+ /**
+ * Constructs a new answer test with the given name.
+ * @param name the name of the test
+ */
+ public StreamedTqlXMLAnswerUnitTest(String name) {
+ super(name);
+ }
+
+ /**
+ * Hook for test runner to obtain a test suite from.
+ * @return The test suite
+ */
+ public static Test suite() {
+ TestSuite suite = new TestSuite();
+ suite.addTest(new StreamedTqlXMLAnswerUnitTest("testEmptyConstructor"));
+ suite.addTest(new StreamedTqlXMLAnswerUnitTest("testEmptyConstructorPretty"));
+ suite.addTest(new StreamedTqlXMLAnswerUnitTest("testBooleanAnswer"));
+ suite.addTest(new StreamedTqlXMLAnswerUnitTest("testBooleanAnswerPretty"));
+ suite.addTest(new StreamedTqlXMLAnswerUnitTest("testPrettyPrint"));
+ suite.addTest(new StreamedTqlXMLAnswerUnitTest("testCompactPrint"));
+ return suite;
+ }
+
+ /**
+ * Default text runner.
+ * @param args The command line arguments
+ */
+ public static void main(String[] args) {
+ junit.textui.TestRunner.run(suite());
+ }
+
+
+ /**
+ * Tests an empty answer.
+ * @throws Exception On error
+ */
+ public void testEmptyConstructor() throws Exception {
+ StreamedTqlXMLAnswer a = new StreamedTqlXMLAnswer(empty, output);
+ a.emit();
+ assertEquals(EMPTY, output.toString());
+ }
+
+
+ /**
+ * Tests an empty answer.
+ * @throws Exception On error
+ */
+ public void testEmptyConstructorPretty() throws Exception {
+ StreamedTqlXMLAnswer a = new StreamedTqlXMLAnswer(empty, output);
+ a.setPrettyPrint(true);
+ a.emit();
+ assertEquals(EMPTY_P, output.toString());
+ a.setPrettyPrint(false);
+ output.reset();
+ a.emit();
+ assertEquals(EMPTY, output.toString());
+ }
+
+
+ /**
+ * Tests a boolean answer.
+ * @throws Exception On error
+ */
+ public void testBooleanAnswer() throws Exception {
+ StreamedTqlXMLAnswer a = new StreamedTqlXMLAnswer(new BooleanAnswer(true), output);
+ a.emit();
+ assertEquals(TRUE, output.toString());
+ }
+
+
+ /**
+ * Tests a boolean answer.
+ * @throws Exception On error
+ */
+ public void testBooleanAnswerPretty() throws Exception {
+ StreamedTqlXMLAnswer a = new StreamedTqlXMLAnswer(new BooleanAnswer(true), output);
+ a.emit();
+ assertEquals(TRUE, output.toString());
+ a.setPrettyPrint(true);
+ output.reset();
+ a.emit();
+ assertEquals(TRUE_P, output.toString());
+ a.setPrettyPrint(false);
+ output.reset();
+ a.emit();
+ assertEquals(TRUE, output.toString());
+ }
+
+
+ /**
+ * Test main structure.
+ */
+ public void testPrettyPrint() throws Exception {
+ StreamedTqlXMLAnswer a = new StreamedTqlXMLAnswer(answer, output);
+ a.setPrettyPrint(true);
+ a.emit();
+ assertEquals(ANSWER_P, output.toString());
+ }
+
+
+ /**
+ * Test main structure.
+ */
+ public void testCompactPrint() throws Exception {
+ StreamedTqlXMLAnswer a = new StreamedTqlXMLAnswer(answer, output);
+ a.emit();
+ assertEquals(ANSWER, output.toString());
+ }
+
+
+ /**
+ * Populate the test answer.
+ * @throws Exception Error setting up the ResultSet
+ */
+ protected void setUp() throws Exception {
+ TestResultSet trs1 = new TestResultSet(new String[] { "x", "y" });
+ ResultSetRow row;
+ row = new ResultSetRow(trs1);
+ row.setObject("x", new LiteralImpl("X1"));
+ row.setObject("y", new URIReferenceImpl(URI.create("urn:y1")));
+ trs1.addRow(row);
+ row = new ResultSetRow(trs1);
+ row.setObject("x", new LiteralImpl("X2", "en"));
+ row.setObject("y", new BlankNodeImpl(42));
+ trs1.addRow(row);
+ answer = new AnswerImpl(trs1);
+
+ List<Variable> variables = Arrays.asList(new Variable[] { new Variable("x") });
+ empty = new AnswerImpl(variables);
+ output = new ByteArrayOutputStream();
+ }
+
+ /**
+ * Clean up the test answer.
+ */
+ public void tearDown() {
+ answer.close();
+ empty.close();
+ }
+
+ static final String EMPTY = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
+ "<answer xmlns=\"http://mulgara.org/tql#\"><query><variables></variables></query></answer>";
+
+ static final String EMPTY_P = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
+ "<answer xmlns=\"http://mulgara.org/tql#\">\n" +
+ " <query>\n" +
+ " <variables>\n" +
+ " </variables>\n" +
+ " </query>\n" +
+ "</answer>";
+
+ static final String TRUE = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
+ "<answer xmlns=\"http://mulgara.org/tql#\">" +
+ "<query><variables><k0/></variables>" +
+ "<solution><k0 datatype=\"http://www.w3.org/2001/XMLSchema#boolean\">true</k0></solution>" +
+ "</query></answer>";
+
+ static final String TRUE_P = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
+ "<answer xmlns=\"http://mulgara.org/tql#\">\n" +
+ " <query>\n" +
+ " <variables>\n" +
+ " <k0/>\n" +
+ " </variables>\n" +
+ " <solution>\n" +
+ " <k0 datatype=\"http://www.w3.org/2001/XMLSchema#boolean\">true</k0>\n" +
+ " </solution>\n" +
+ " </query>\n" +
+ "</answer>";
+
+ static final String ANSWER = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
+ "<answer xmlns=\"http://mulgara.org/tql#\">" +
+ "<query><variables><x/><y/></variables>" +
+ "<solution><x>X1</x><y resource=\"urn:y1\"/></solution>" +
+ "<solution><x language=\"en\">X2</x><y blank-node=\"_node42\"/></solution>" +
+ "</query>" +
+ "</answer>";
+
+ static final String ANSWER_P = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
+ "<answer xmlns=\"http://mulgara.org/tql#\">\n" +
+ " <query>\n" +
+ " <variables>\n" +
+ " <x/>\n" +
+ " <y/>\n" +
+ " </variables>\n" +
+ " <solution>\n" +
+ " <x>X1</x>\n" +
+ " <y resource=\"urn:y1\"/>\n" +
+ " </solution>\n" +
+ " <solution>\n" +
+ " <x language=\"en\">X2</x>\n" +
+ " <y blank-node=\"_node42\"/>\n" +
+ " </solution>\n" +
+ " </query>\n" +
+ "</answer>";
+}
Added: trunk/src/jar/querylang/java/org/mulgara/protocol/StreamedXMLAnswer.java
===================================================================
--- trunk/src/jar/querylang/java/org/mulgara/protocol/StreamedXMLAnswer.java (rev 0)
+++ trunk/src/jar/querylang/java/org/mulgara/protocol/StreamedXMLAnswer.java 2008-09-03 14:56:28 UTC (rev 1223)
@@ -0,0 +1,35 @@
+package org.mulgara.protocol;
+
+import java.io.IOException;
+import java.nio.charset.Charset;
+
+import org.mulgara.query.TuplesException;
+
+/**
+ * Represents an Answer that can be emitted as XML to a stream.
+ *
+ * @created Jul 8, 2008
+ * @author Paul Gearon
+ * @copyright © 2008 <a href="http://www.topazproject.org/">The Topaz Project</a>
+ * @licence <a href="{@docRoot}/../../LICENCE.txt">Open Software License v3.0</a>
+ */
+public interface StreamedXMLAnswer extends XMLAnswer, StreamedAnswer {
+
+ /**
+ * Converts the Answer to an XML String and send to output.
+ * @throws TuplesException Indicates an error accessing the Answer.
+ */
+ public void emit() throws TuplesException, IOException;
+
+ /**
+ * Sets the character encoding when writing XML text to a byte stream.
+ * @param encoding The encoding to use.
+ */
+ public void setCharacterEncoding(String encoding);
+
+ /**
+ * Sets the character encoding when writing XML text to a byte stream.
+ * @param encoding The charset encoding to use.
+ */
+ public void setCharacterEncoding(Charset charset);
+}
\ No newline at end of file
Added: trunk/src/jar/querylang/java/org/mulgara/protocol/XMLAnswer.java
===================================================================
--- trunk/src/jar/querylang/java/org/mulgara/protocol/XMLAnswer.java (rev 0)
+++ trunk/src/jar/querylang/java/org/mulgara/protocol/XMLAnswer.java 2008-09-03 14:56:28 UTC (rev 1223)
@@ -0,0 +1,33 @@
+package org.mulgara.protocol;
+
+import java.net.URI;
+
+/**
+ * Represents an Answer that can be emitted as XML.
+ *
+ * @created Jul 9, 2008
+ * @author Paul Gearon
+ * @copyright © 2008 <a href="http://www.topazproject.org/">The Topaz Project</a>
+ * @licence <a href="{@docRoot}/../../LICENCE.txt">Open Software License v3.0</a>
+ */
+public interface XMLAnswer {
+
+ /**
+ * Explicitly adds a namespace to be used in the document.
+ * @param name The name of the namespace to use.
+ * @param nsValue The URI of the namespace.
+ */
+ public abstract void addNamespace(String name, URI nsValue);
+
+ /**
+ * Remove all previously added namespaces.
+ */
+ public abstract void clearNamespaces();
+
+ /**
+ * Sets whether or not to used pretty printing when creating the XML. On by default.
+ * @param prettyPrint <code>true</code> to turn pretty printing on. <code>false</code> to turn it off.
+ */
+ public abstract void setPrettyPrint(boolean prettyPrint);
+
+}
\ No newline at end of file
More information about the Mulgara-svn
mailing list