Return-Path: X-Original-To: archive-asf-public-internal@cust-asf2.ponee.io Delivered-To: archive-asf-public-internal@cust-asf2.ponee.io Received: from cust-asf.ponee.io (cust-asf.ponee.io [163.172.22.183]) by cust-asf2.ponee.io (Postfix) with ESMTP id B5BA8200D6B for ; Sun, 31 Dec 2017 11:52:43 +0100 (CET) Received: by cust-asf.ponee.io (Postfix) id B341A160C09; Sun, 31 Dec 2017 10:52:43 +0000 (UTC) Delivered-To: archive-asf-public@cust-asf.ponee.io Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by cust-asf.ponee.io (Postfix) with SMTP id 55710160C36 for ; Sun, 31 Dec 2017 11:52:41 +0100 (CET) Received: (qmail 64381 invoked by uid 500); 31 Dec 2017 10:52:40 -0000 Mailing-List: contact commits-help@jena.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@jena.apache.org Delivered-To: mailing list commits@jena.apache.org Received: (qmail 64329 invoked by uid 99); 31 Dec 2017 10:52:40 -0000 Received: from git1-us-west.apache.org (HELO git1-us-west.apache.org) (140.211.11.23) by apache.org (qpsmtpd/0.29) with ESMTP; Sun, 31 Dec 2017 10:52:40 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id 78914E0014; Sun, 31 Dec 2017 10:52:39 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: andy@apache.org To: commits@jena.apache.org Date: Sun, 31 Dec 2017 10:52:42 -0000 Message-Id: In-Reply-To: <26a8450f3c43437ea5e547f2c6ec7345@git.apache.org> References: <26a8450f3c43437ea5e547f2c6ec7345@git.apache.org> X-Mailer: ASF-Git Admin Mailer Subject: [04/11] jena git commit: JENA-1454: Introduce builder pattern for result set reading and writing. archived-at: Sun, 31 Dec 2017 10:52:43 -0000 JENA-1454: Introduce builder pattern for result set reading and writing. Project: http://git-wip-us.apache.org/repos/asf/jena/repo Commit: http://git-wip-us.apache.org/repos/asf/jena/commit/716b86cf Tree: http://git-wip-us.apache.org/repos/asf/jena/tree/716b86cf Diff: http://git-wip-us.apache.org/repos/asf/jena/diff/716b86cf Branch: refs/heads/master Commit: 716b86cfa300e8829dbc9238b7c67b711cdef1e2 Parents: d516f35 Author: Andy Seaborne Authored: Mon Dec 18 14:49:40 2017 +0000 Committer: Andy Seaborne Committed: Fri Dec 22 21:40:42 2017 +0000 ---------------------------------------------------------------------- .../org/apache/jena/query/ResultSetFactory.java | 78 +-- .../apache/jena/query/ResultSetFormatter.java | 139 ++-- .../java/org/apache/jena/riot/ResultSetMgr.java | 270 +++++--- .../jena/riot/resultset/ResultSetLang.java | 2 +- .../jena/riot/resultset/ResultSetReader.java | 31 +- .../riot/resultset/ResultSetReaderRegistry.java | 70 +- .../riot/resultset/ResultSetWriterRegistry.java | 85 +-- .../riot/resultset/rw/JSONInputIterator.java | 657 +++++++++++++++++++ .../jena/riot/resultset/rw/JSONResultsKW.java | 44 ++ .../jena/riot/resultset/rw/ReadAnything.java | 100 +++ .../riot/resultset/rw/ResultSetReaderJSON.java | 247 +++++++ .../resultset/rw/ResultSetReaderThrift.java | 60 ++ .../riot/resultset/rw/ResultSetReaderXML.java | 54 ++ .../riot/resultset/rw/ResultSetWriterJSON.java | 305 +++++++++ .../resultset/rw/ResultSetWriterThrift.java | 54 ++ .../riot/resultset/rw/ResultSetWriterXML.java | 380 +++++++++++ .../jena/riot/resultset/rw/ResultsMgrX.java | 69 ++ .../jena/riot/resultset/rw/ResultsReader.java | 151 +++++ .../jena/riot/resultset/rw/ResultsStAX.java | 473 +++++++++++++ .../jena/riot/resultset/rw/ResultsWriter.java | 113 ++++ .../jena/riot/resultset/rw/XMLResults.java | 50 ++ .../jena/riot/system/stream/StreamManager.java | 5 +- .../apache/jena/sparql/resultset/JSONInput.java | 227 +------ .../sparql/resultset/JSONInputIterator.java | 657 ------------------- .../jena/sparql/resultset/JSONOutput.java | 21 +- .../jena/sparql/resultset/JSONOutputASK.java | 54 -- .../sparql/resultset/JSONOutputResultSet.java | 266 -------- .../jena/sparql/resultset/JSONResultsKW.java | 43 -- .../jena/sparql/resultset/SPARQLResult.java | 20 +- .../apache/jena/sparql/resultset/XMLInput.java | 10 +- .../jena/sparql/resultset/XMLInputSAX.java | 23 +- .../jena/sparql/resultset/XMLInputStAX.java | 516 --------------- .../apache/jena/sparql/resultset/XMLOutput.java | 30 +- .../jena/sparql/resultset/XMLOutputASK.java | 74 --- .../sparql/resultset/XMLOutputResultSet.java | 286 -------- .../jena/sparql/resultset/XMLResults.java | 50 -- .../apache/jena/sparql/util/LabelToNodeMap.java | 6 +- .../apache/jena/sparql/util/QueryExecUtils.java | 6 - .../jena/sparql/resultset/TestResultSet.java | 10 +- 39 files changed, 3189 insertions(+), 2547 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/jena/blob/716b86cf/jena-arq/src/main/java/org/apache/jena/query/ResultSetFactory.java ---------------------------------------------------------------------- diff --git a/jena-arq/src/main/java/org/apache/jena/query/ResultSetFactory.java b/jena-arq/src/main/java/org/apache/jena/query/ResultSetFactory.java index dcf33f5..5682b3d 100644 --- a/jena-arq/src/main/java/org/apache/jena/query/ResultSetFactory.java +++ b/jena-arq/src/main/java/org/apache/jena/query/ResultSetFactory.java @@ -27,7 +27,8 @@ import org.apache.jena.rdf.model.Model ; import org.apache.jena.rdf.model.ModelFactory ; import org.apache.jena.riot.Lang ; import org.apache.jena.riot.ResultSetMgr ; -import org.apache.jena.shared.NotFoundException ; +import org.apache.jena.riot.resultset.ResultSetLang; +import org.apache.jena.riot.resultset.rw.ReadAnything; import org.apache.jena.sparql.engine.QueryIterator ; import org.apache.jena.sparql.engine.ResultSetStream ; import org.apache.jena.sparql.graph.GraphFactory ; @@ -88,21 +89,6 @@ public class ResultSetFactory { if ( lang != null ) return ResultSetMgr.read(input, lang) ; - if (format.equals(ResultsFormat.FMT_RS_JSON)) - return JSONInput.fromJSON(input); - - if (format.equals(ResultsFormat.FMT_RS_TSV)) - return TSVInput.fromTSV(input); - - if (format.equals(ResultsFormat.FMT_RS_CSV)) - return CSVInput.fromCSV(input); - - if (format.equals(ResultsFormat.FMT_RS_BIO)) - return BIOInput.fromBIO(input); - - if (format.equals(ResultsFormat.FMT_RS_XML)) - return ResultSetFactory.fromXML(input); - if (format.equals(ResultsFormat.FMT_TEXT)) { Log.warn(ResultSet.class, "Can't read a text result set"); throw new ResultSetException("Can't read a text result set"); @@ -202,27 +188,13 @@ public class ResultSetFactory { } if (format.equals(ResultsFormat.FMT_RS_XML) || format.equals(ResultsFormat.FMT_RS_JSON)) { - InputStream in = null; - try { - in = FileManager.get().open(filenameOrURI); - if (in == null) - throw new NotFoundException(filenameOrURI); - } catch (NotFoundException ex) { - throw new NotFoundException("File not found: " + filenameOrURI); - } - - SPARQLResult x = null; - - if (format.equals(ResultsFormat.FMT_RS_JSON)) - x = JSONInput.make(in, GraphFactory.makeDefaultModel()); - else - x = XMLInput.make(in, GraphFactory.makeDefaultModel()); - + SPARQLResult x = ReadAnything.read(filenameOrURI); if (x.isResultSet()) RDFOutput.encodeAsRDF(model, x.getResultSet()); - else + else if ( x.isBoolean() ) RDFOutput.encodeAsRDF(model, x.getBooleanResult()); - + else + throw new ResultSetException("Not a result set"); return model; } @@ -243,8 +215,9 @@ public class ResultSetFactory { /** * Read in any kind of result kind (result set, boolean, graph) + * @deprecated Use ReadAnything.read(filenameOrURI); */ - + @Deprecated public static SPARQLResult result(String filenameOrURI, ResultsFormat format) { if (format == null) format = ResultsFormat.guessSyntax(filenameOrURI); @@ -261,31 +234,8 @@ public class ResultSetFactory { if (format.equals(ResultsFormat.FMT_RS_XML) || format.equals(ResultsFormat.FMT_RS_JSON) || format.equals(ResultsFormat.FMT_RS_TSV) || format.equals(ResultsFormat.FMT_RS_CSV)) { - InputStream in = null; - try { - in = FileManager.get().open(filenameOrURI); - if (in == null) - throw new NotFoundException(filenameOrURI); - } catch (NotFoundException ex) { - throw new NotFoundException("File not found: " + filenameOrURI); - } - - SPARQLResult x = null; - - if (format.equals(ResultsFormat.FMT_RS_JSON)) - return JSONInput.make(in, GraphFactory.makeDefaultModel()); - else if (format.equals(ResultsFormat.FMT_RS_XML)) - return XMLInput.make(in, GraphFactory.makeDefaultModel()); - else if (format.equals(ResultsFormat.FMT_RS_TSV)) { - ResultSet rs = TSVInput.fromTSV(in); - return new SPARQLResult(rs); - } else if (format.equals(ResultsFormat.FMT_RS_CSV)) { - ResultSet rs = CSVInput.fromCSV(in); - return new SPARQLResult(rs); - } else if (format.equals(ResultsFormat.FMT_RS_BIO)) { - ResultSet rs = BIOInput.fromBIO(in); - return new SPARQLResult(rs); - } + SPARQLResult x = ReadAnything.read(filenameOrURI); + return x; } if (ResultsFormat.isRDFGraphSyntax(format)) { @@ -305,7 +255,7 @@ public class ResultSetFactory { * @return ResultSet */ public static ResultSet fromXML(InputStream in) { - return XMLInput.fromXML(in); + return ResultSetMgr.read(in, ResultSetLang.SPARQLResultSetXML); } /** @@ -314,7 +264,9 @@ public class ResultSetFactory { * @param str * String to process * @return ResultSet + * @deprecated */ + @Deprecated public static ResultSet fromXML(String str) { return XMLInput.fromXML(str); } @@ -328,7 +280,7 @@ public class ResultSetFactory { * @return ResultSet */ public static ResultSet fromJSON(InputStream in) { - return JSONInput.fromJSON(in); + return ResultSetMgr.read(in, ResultSetLang.SPARQLResultSetJSON); } /** @@ -340,7 +292,7 @@ public class ResultSetFactory { * @return ResultSet */ public static ResultSet fromTSV(InputStream in) { - return TSVInput.fromTSV(in); + return ResultSetMgr.read(in, ResultSetLang.SPARQLResultSetTSV); } /** http://git-wip-us.apache.org/repos/asf/jena/blob/716b86cf/jena-arq/src/main/java/org/apache/jena/query/ResultSetFormatter.java ---------------------------------------------------------------------- diff --git a/jena-arq/src/main/java/org/apache/jena/query/ResultSetFormatter.java b/jena-arq/src/main/java/org/apache/jena/query/ResultSetFormatter.java index 43bb07b..49b5586 100644 --- a/jena-arq/src/main/java/org/apache/jena/query/ResultSetFormatter.java +++ b/jena-arq/src/main/java/org/apache/jena/query/ResultSetFormatter.java @@ -18,6 +18,11 @@ package org.apache.jena.query; +import static org.apache.jena.riot.resultset.ResultSetLang.SPARQLResultSetCSV; +import static org.apache.jena.riot.resultset.ResultSetLang.SPARQLResultSetJSON; +import static org.apache.jena.riot.resultset.ResultSetLang.SPARQLResultSetTSV; +import static org.apache.jena.riot.resultset.ResultSetLang.SPARQLResultSetXML; + import java.io.ByteArrayOutputStream ; import java.io.OutputStream ; import java.io.UnsupportedEncodingException ; @@ -28,16 +33,17 @@ import java.util.List ; import org.apache.jena.atlas.logging.Log ; import org.apache.jena.rdf.model.RDFNode ; +import org.apache.jena.riot.Lang; import org.apache.jena.riot.ResultSetMgr ; +import org.apache.jena.riot.resultset.rw.ResultsWriter; import org.apache.jena.shared.PrefixMapping ; import org.apache.jena.sparql.ARQException ; import org.apache.jena.sparql.ARQNotImplemented ; import org.apache.jena.sparql.core.Prologue ; -import org.apache.jena.sparql.core.Var ; -import org.apache.jena.sparql.engine.binding.Binding ; -import org.apache.jena.sparql.engine.binding.BindingOutputStream ; -import org.apache.jena.sparql.engine.binding.BindingUtils ; -import org.apache.jena.sparql.resultset.* ; +import org.apache.jena.sparql.resultset.RDFOutput; +import org.apache.jena.sparql.resultset.ResultsFormat; +import org.apache.jena.sparql.resultset.TextOutput; +import org.apache.jena.sparql.resultset.XMLOutput; import org.apache.jena.sparql.serializer.SerializationContext ; /** ResultSetFormatter - Convenience ways to call the various output formatters. @@ -261,9 +267,6 @@ public class ResultSetFormatter { } } - // ---------------------------------------------------------------- - // As RDF - /** Output a ResultSet in some format. * * @param resultSet Result set @@ -282,31 +285,13 @@ public class ResultSetFormatter { */ static public void output(OutputStream outStream, ResultSet resultSet, ResultsFormat rFmt) { - if ( rFmt.equals(ResultsFormat.FMT_RS_XML) ) { - outputAsXML(outStream, resultSet) ; - return ; - } - - if ( rFmt.equals(ResultsFormat.FMT_RS_JSON) ) { - outputAsJSON(outStream, resultSet) ; - return ; - } - - if ( rFmt.equals(ResultsFormat.FMT_RS_CSV) ) { - outputAsCSV(outStream, resultSet) ; - return ; - } - - if ( rFmt.equals(ResultsFormat.FMT_RS_TSV) ) { - outputAsTSV(outStream, resultSet) ; - return ; - } - - if ( rFmt.equals(ResultsFormat.FMT_RS_BIO) ) { - outputAsBIO(outStream, resultSet) ; + + Lang lang = ResultsFormat.convert(rFmt); + if ( lang != null ) { + output(outStream, resultSet, lang); return ; } - + if ( rFmt.equals(ResultsFormat.FMT_RDF_XML) ) { RDFOutput.outputAsRDF(outStream, "RDF/XML-ABBREV", resultSet) ; return ; @@ -324,13 +309,29 @@ public class ResultSetFormatter { throw new ARQException("Unknown ResultSet format: " + rFmt) ; } - // ---- XML Output + // ---- General Output + public static void output(ResultSet resultSet, Lang resultFormat) { + output(System.out, resultSet, resultFormat); + } + public static void output(OutputStream outStream, ResultSet resultSet, Lang resultFormat) { + ResultsWriter.create().lang(resultFormat).write(outStream, resultSet); + } + public static void output(boolean result, Lang resultFormat) { + output(System.out, result, resultFormat); + } + // ---- General Output + + public static void output(OutputStream outStream, boolean result, Lang resultFormat) { + ResultsWriter.create().lang(resultFormat).build().write(outStream, result); + } /** Output a result set in the XML format * * @param qresults result set */ + // ---- XML Output + static public void outputAsXML(ResultSet qresults) { outputAsXML(System.out, qresults) ; } @@ -341,20 +342,18 @@ public class ResultSetFormatter { */ static public void outputAsXML(OutputStream outStream, ResultSet qresults) - { - outputAsXML(outStream, qresults, (String)null) ; - } + { output(outStream, qresults, SPARQLResultSetXML); } - /** Output a result set in the XML format, inserting a style sheet in the XMl output + /** Output a result set in the XML format, inserting a style sheet in the XML output * * @param qresults result set * @param stylesheet The URL of the stylesheet */ static public void outputAsXML(ResultSet qresults, String stylesheet) - { outputAsXML(System.out, qresults, stylesheet) ; } + { outputAsXML(System.out, qresults, stylesheet); } - /** Output a result set in the XML format, inserting a style sheet in the XMl output + /** Output a result set in the XML format, inserting a style sheet in the XML output * * @param outStream output stream * @param qresults result set @@ -384,9 +383,7 @@ public class ResultSetFormatter { */ public static void outputAsXML(OutputStream outStream, boolean booleanResult) - { - outputAsXML(outStream, booleanResult, null) ; - } + { output(outStream, booleanResult, SPARQLResultSetXML); } /** Output a boolean result in the XML format * @@ -403,10 +400,9 @@ public class ResultSetFormatter { * @param stylesheet The URL of the stylesheet */ - public static void outputAsXML(OutputStream outStream, boolean booleanResult, String stylesheet) - { - XMLOutputASK fmt = new XMLOutputASK(outStream, stylesheet) ; - fmt.exec(booleanResult) ; + public static void outputAsXML(OutputStream outStream, boolean booleanResult, String stylesheet) { + XMLOutput xOut = new XMLOutput(stylesheet); + xOut.format(outStream, booleanResult); } /** Return a string that has the result set serialized as XML (not RDF) @@ -477,7 +473,7 @@ public class ResultSetFormatter { return xOut.asString(booleanResult) ; } - // ---- JSON (and YAML) + // ---- JSON /** Output a result set in the JSON format * Format: Serializing SPARQL Query Results in JSON @@ -485,7 +481,7 @@ public class ResultSetFormatter { * @param resultSet result set */ - static public void outputAsJSON(ResultSet resultSet) + static public void outputAsJSON(ResultSet resultSet) { outputAsJSON(System.out, resultSet) ; } /** Output a result set in the JSON format @@ -497,10 +493,7 @@ public class ResultSetFormatter { */ static public void outputAsJSON(OutputStream outStream, ResultSet resultSet) - { - JSONOutput jOut = new JSONOutput() ; - jOut.format(outStream, resultSet) ; - } + { output(outStream, resultSet, SPARQLResultSetJSON) ; } /** Output a result set in the JSON format * Format: Serializing SPARQL Query Results in JSON @@ -510,7 +503,7 @@ public class ResultSetFormatter { */ static public void outputAsJSON(boolean booleanResult) - { outputAsJSON(System.out, booleanResult ) ; } + { outputAsJSON(System.out, booleanResult) ; } /** Output a result set in the JSON format * Format: Serializing SPARQL Query Results in JSON @@ -521,10 +514,7 @@ public class ResultSetFormatter { */ static public void outputAsJSON(OutputStream outStream, boolean booleanResult) - { - JSONOutput jOut = new JSONOutput() ; - jOut.format(outStream, booleanResult) ; - } + { output(outStream, booleanResult, SPARQLResultSetJSON) ; } // ---- SSE @@ -603,10 +593,7 @@ public class ResultSetFormatter { */ static public void outputAsCSV(OutputStream outStream, boolean booleanResult) - { - CSVOutput fmt = new CSVOutput() ; - fmt.format(outStream, booleanResult) ; - } + { output(outStream, booleanResult, SPARQLResultSetCSV); } /** Output a result set in CSV format * @param resultSet result set @@ -621,10 +608,7 @@ public class ResultSetFormatter { */ static public void outputAsCSV(OutputStream outStream, ResultSet resultSet) - { - CSVOutput fmt = new CSVOutput() ; - fmt.format(outStream, resultSet) ; - } + { output(outStream, resultSet, SPARQLResultSetCSV); } // ---- TSV @@ -643,10 +627,7 @@ public class ResultSetFormatter { */ static public void outputAsTSV(OutputStream outStream, boolean booleanResult) - { - TSVOutput fmt = new TSVOutput() ; - fmt.format(outStream, booleanResult) ; - } + { output(outStream, booleanResult, SPARQLResultSetTSV); } /** Output a result set in TSV format * @param resultSet result set @@ -661,25 +642,5 @@ public class ResultSetFormatter { */ static public void outputAsTSV(OutputStream outStream, ResultSet resultSet) - { - TSVOutput fmt = new TSVOutput() ; - fmt.format(outStream, resultSet) ; - } - - /** Output a result set in BIO format - * @deprecated Experimental - may be removed - */ - @Deprecated - public static void outputAsBIO(OutputStream out, ResultSet results) - { - List vars = Var.varList(results.getResultVars()) ; - - BindingOutputStream bout = new BindingOutputStream(out, vars) ; - for ( ; results.hasNext() ; ) - { - Binding b = BindingUtils.asBinding(results.next()) ; - bout.write(b) ; - } - bout.flush() ; - } + { output(outStream, resultSet, SPARQLResultSetTSV); } } http://git-wip-us.apache.org/repos/asf/jena/blob/716b86cf/jena-arq/src/main/java/org/apache/jena/riot/ResultSetMgr.java ---------------------------------------------------------------------- diff --git a/jena-arq/src/main/java/org/apache/jena/riot/ResultSetMgr.java b/jena-arq/src/main/java/org/apache/jena/riot/ResultSetMgr.java index aeb05cc..2c406f1 100644 --- a/jena-arq/src/main/java/org/apache/jena/riot/ResultSetMgr.java +++ b/jena-arq/src/main/java/org/apache/jena/riot/ResultSetMgr.java @@ -18,15 +18,20 @@ package org.apache.jena.riot; +import java.io.ByteArrayOutputStream; import java.io.InputStream ; import java.io.OutputStream ; +import java.util.Objects; -import org.apache.jena.atlas.web.ContentType ; -import org.apache.jena.atlas.web.TypedInputStream ; +import org.apache.jena.atlas.lib.StrUtils; import org.apache.jena.query.ResultSet ; import org.apache.jena.query.ResultSetFactory ; import org.apache.jena.query.ResultSetFormatter ; -import org.apache.jena.riot.resultset.* ; +import org.apache.jena.riot.resultset.ResultSetReaderRegistry; +import org.apache.jena.riot.resultset.rw.ResultsReader; +import org.apache.jena.riot.resultset.rw.ResultsWriter; +import org.apache.jena.sparql.resultset.ResultSetException; +import org.apache.jena.sparql.resultset.SPARQLResult; import org.apache.jena.sparql.util.Context ; /** @@ -36,7 +41,61 @@ import org.apache.jena.sparql.util.Context ; * @see ResultSetFormatter */ public class ResultSetMgr { - + /** + * Read from a {@code URL} (including filenames) and produce a {@link ResultSet}. + * Note that returned result set may stream and so the input stream be read + * while the ResultSet is used. + *

+ * See {@link ResultSetFactory#copyResults(ResultSet)} + * for a ResultSet that is detached from the {@code InputStream}. + * + * @param urlOrFilename + * @return ResultSet + */ + public static ResultSet read(String urlOrFilename) { + ResultSet rs = readAny(urlOrFilename).getResultSet(); + if ( rs == null ) + throw new ResultSetException("Not a result set"); + return rs; + } + + + /** + * Read from a {@code URL} (including filenames) and produce a {@link ResultSet}; + * the stream is expect to use syntax {@code lang}. Note that returned + * result set may stream and so the input stream be read while the ResultSet is used. + * See {@link ResultSetFactory#copyResults(ResultSet)} + * for a ResultSet that is detached from the {@code InputStream}. + * + * @param urlOrFilename + * @param lang + * @return ResultSet + */ + public static ResultSet read(String urlOrFilename, Lang lang) { + ResultSet rs = readAny(urlOrFilename, lang).getResultSet(); + if ( rs == null ) + throw new ResultSetException("Not a result set"); + return rs; + } + + /** + * Read from a {@code URL} (including filenames) and produce a {@link ResultSet}. + * Note that returned result set may stream and so the input stream be read + * while the ResultSet is used. + *

+ * See {@link ResultSetFactory#copyResults(ResultSet)} + * for a ResultSet that is detached from the {@code InputStream}. + * + * @param input + * @return ResultSet + */ + public static ResultSet read(InputStream input) { + ResultSet rs = readAny(input).getResultSet(); + if ( rs == null ) + throw new ResultSetException("Not a result set"); + return rs; + } + /** * Read from an {@code InputStream} and produce a {@link ResultSet}; * the stream is expect to use syntax {@code lang}. Note that returned @@ -44,115 +103,154 @@ public class ResultSetMgr { * See {@link ResultSetFactory#copyResults(ResultSet)} * for a ResultSet that is detached from the {@code InputStream}. * - * @param in + * @param input * @param lang * @return ResultSet */ - public static ResultSet read(InputStream in, Lang lang) { - return process(TypedInputStream.wrap(in), null, lang, null) ; + public static ResultSet read(InputStream input, Lang lang) { + ResultSet rs = readAny(input, lang).getResultSet(); + if ( rs == null ) + throw new ResultSetException("Not a result set"); + return rs; + } + + private static void checkLang(Lang lang) { + Objects.requireNonNull(lang); + if ( ! ResultSetReaderRegistry.isRegistered(lang) ) { + throw new ResultSetException("Not a result set syntax: "+lang); + } } - /** Read a result set from the URI */ - public static ResultSet read(String uri) { - return read(uri, null) ; + /** Read a boolean result from the URI + * + * @param urlOrFilename + * @return boolean + */ + public static boolean readBoolean(String urlOrFilename) { + Boolean b = readAny(urlOrFilename).getBooleanResult(); + return b; } - /** Read a result set from the URI, in the specified syntax */ - public static ResultSet read(String uri, Lang lang) { - return parse(uri, lang, null) ; + /** Read a boolean result from the URI; + * the input is expect to use syntax {@code lang} + * + * @param urlOrFilename + * @param lang + * @return boolean + */ + public static boolean readBoolean(String urlOrFilename, Lang lang) { + Boolean b = readAny(urlOrFilename, lang).getBooleanResult(); + return b; + } + + /** Read a boolean result from the URI + * + * @param input + * @return boolean + */ + public static boolean readBoolean(InputStream input) { + Boolean b = readAny(input).getBooleanResult(); + return b; + } + + /** Read a boolean result from the URI; + * the input is expect to use syntax {@code lang} + * + * @param input + * @param lang + * @return boolean + */ + public static boolean readBoolean(InputStream input, Lang lang) { + Boolean b = readAny(input, lang).getBooleanResult(); + return b; } + private static SPARQLResult readAny(String url) { + return ResultsReader.create().build().readAny(url); + } + + private static SPARQLResult readAny(String url, Lang lang) { + checkLang(lang); + return ResultsReader.create() + .lang(lang) + .build() + .readAny(url); + } + + private static SPARQLResult readAny(InputStream input) { + return ResultsReader.create().build().readAny(input); + } + + private static SPARQLResult readAny(InputStream input, Lang lang) { + checkLang(lang); + return ResultsReader.create() + .lang(lang) + .build() + .readAny(input); + } + // ------------------------------- + /** Read ResultSet. * @param uri URI to read from (includes file: and a plain file name). * @param hintLang Hint for the syntax * @param context Content object to control reading process. */ - public static ResultSet parse(String uri, Lang hintLang, Context context) - { - // Conneg - if ( uri == null ) - throw new IllegalArgumentException("URI to read from is null") ; - if ( hintLang == null ) - hintLang = RDFLanguages.filenameToLang(uri) ; - TypedInputStream in = RDFDataMgr.open(uri, context) ; - if ( in == null ) - throw new RiotException("Not found: "+uri) ; - return process(in, uri, hintLang, context) ; - } - - private static ResultSet process(TypedInputStream in, String srcURI, Lang hintLang, Context context) { - ContentType ct = WebContent.determineCT(in.getContentType(), hintLang, srcURI) ; - if ( ct == null ) - throw new RiotException("Failed to determine the content type: (URI="+srcURI+" : stream="+in.getContentType()+" : hint="+hintLang+")") ; - ResultSetReader reader = getReader(ct) ; - if ( reader == null ) - throw new RiotException("No parser registered for content type: "+ct.getContentType()) ; - return reader.read(in, context) ; + public static ResultSet parse(String uri, Lang hintLang, Context context) { + ResultSet rs = ResultsReader.create().lang(hintLang).context(context).read(uri); + if ( rs == null ) + throw new ResultSetException("Not a result set"); + return rs; } - - private static ResultSetReader getReader(ContentType ct) - { - Lang lang = RDFLanguages.contentTypeToLang(ct) ; - if ( lang == null ) - return null ; - ResultSetReaderFactory r = ResultSetReaderRegistry.getFactory(lang) ; - if ( r == null ) - return null ; - return r.create(lang) ; - } - - // ------------------------------- + // ------------------------------- + /** Write a SPARQL result set to the output stream in the specified language/syntax. - * @param out + * @param output * @param resultSet * @param lang */ - public static void write(OutputStream out, ResultSet resultSet, Lang lang) { - ResultSetWriterFactory f = ResultSetWriterRegistry.lookup(lang) ; - if ( f == null ) - throw new RiotException("No resultSet writer for "+lang) ; - f.create(lang).write(out, resultSet, null) ; + public static void write(OutputStream output, ResultSet resultSet, Lang lang) { + ResultsWriter.create() + .lang(lang) + .write(output, resultSet); } - + /** Write a SPARQL boolean result to the output stream in the specified language/syntax. - * @param out + * @param output * @param result * @param lang */ - public static void write(OutputStream out, boolean result, Lang lang) { - ResultSetWriterFactory f = ResultSetWriterRegistry.lookup(lang) ; - if ( f == null ) - throw new RiotException("No resultSet writer for "+lang) ; - f.create(lang).write(out, result, null) ; + public static void write(OutputStream output, boolean result, Lang lang) { + ResultsWriter.create() + .lang(lang) + .build() + .write(output, result); } -// /** Write a SPARQL result set to the {@link java.io.Writer} in the speciifcied language/syntax. -// * Using {@link OutputStream}s is better because the charcater encoding will match the -// * requirements of the language. -// * @param out -// * @param resultSet -// * @param lang -// */ -// @Deprecated -// public static void write(Writer out, ResultSet resultSet, Lang lang) { -// ResultSetWriterFactory f = ResultSetWriterRegistry.lookup(lang) ; -// if ( f == null ) -// throw new RiotException("No resultSet writer for "+lang) ; -// f.create(lang).write(out, resultSet, null) ; -// } -// -// /** Write a SPARQL result set to the {@link java.io.Writer} in the speciifcied language/syntax. -// * @param out -// * @param resultSet -// * @param lang -// */ -// public static void write(StringWriter out, ResultSet resultSet, Lang lang) { -// ResultSetWriterFactory f = ResultSetWriterRegistry.lookup(lang) ; -// if ( f == null ) -// throw new RiotException("No resultSet writer for "+lang) ; -// f.create(lang).write(out, resultSet, null) ; -// } + /** Generate a string in the specified language/syntax for a SPARQL result set. + * @param resultSet + * @param lang + */ + public static String asString(ResultSet resultSet, Lang lang) { + ByteArrayOutputStream output = new ByteArrayOutputStream(1000); + ResultsWriter.create() + .lang(lang) + .write(output, resultSet); + return StrUtils.fromUTF8bytes(output.toByteArray()); + } + + /** Generate a string in the specified language/syntax for a SPARQL boolean result. + * @param result + * @param lang + */ + public static String asString(boolean result, Lang lang) { + ByteArrayOutputStream output = new ByteArrayOutputStream(1000); + ResultsWriter.create() + .lang(lang) + .build() + .write(output, result); + return StrUtils.fromUTF8bytes(output.toByteArray()); + } } http://git-wip-us.apache.org/repos/asf/jena/blob/716b86cf/jena-arq/src/main/java/org/apache/jena/riot/resultset/ResultSetLang.java ---------------------------------------------------------------------- diff --git a/jena-arq/src/main/java/org/apache/jena/riot/resultset/ResultSetLang.java b/jena-arq/src/main/java/org/apache/jena/riot/resultset/ResultSetLang.java index 53d6a28..5ca83ae 100644 --- a/jena-arq/src/main/java/org/apache/jena/riot/resultset/ResultSetLang.java +++ b/jena-arq/src/main/java/org/apache/jena/riot/resultset/ResultSetLang.java @@ -24,7 +24,7 @@ import org.apache.jena.riot.RDFLanguages ; import org.apache.jena.riot.WebContent ; public class ResultSetLang { - // Add SSE! + public static final Lang SPARQLResultSetXML = LangBuilder.create("SPARQL-Results-XML", WebContent.contentTypeResultsXML) .addAltNames("SRX") http://git-wip-us.apache.org/repos/asf/jena/blob/716b86cf/jena-arq/src/main/java/org/apache/jena/riot/resultset/ResultSetReader.java ---------------------------------------------------------------------- diff --git a/jena-arq/src/main/java/org/apache/jena/riot/resultset/ResultSetReader.java b/jena-arq/src/main/java/org/apache/jena/riot/resultset/ResultSetReader.java index c894344..242b8a1 100644 --- a/jena-arq/src/main/java/org/apache/jena/riot/resultset/ResultSetReader.java +++ b/jena-arq/src/main/java/org/apache/jena/riot/resultset/ResultSetReader.java @@ -23,31 +23,50 @@ import java.io.Reader ; import org.apache.jena.query.ResultSet ; import org.apache.jena.query.ResultSetFactory ; +import org.apache.jena.sparql.resultset.SPARQLResult; import org.apache.jena.sparql.util.Context ; public interface ResultSetReader { /** * Read from an {@code InputStream} and produce a {@link ResultSet}. - * Note that return result may stream and so the input stream be read - * while the ResultSet is used. + * Note that return result may stream and so the input stream may be read + * while the {@link ResultSet} is used. * See {@link ResultSetFactory#copyResults(ResultSet)} for a ResultSet that is detached from the {@code InputStream}. * @param in InputStream to read from. * @param context * @return ResultSet */ - public ResultSet read(InputStream in, Context context) ; + public default ResultSet read(InputStream in, Context context) { + return readAny(in, context).getResultSet(); + } + + /** + * Read from an {@code InputStream} and produce a {@link SPARQLResult}. + * Note that return result may stream and so the input stream may be read + * while the {@link ResultSet} is used. + * See {@link #read(InputStream, Context)} for more details + * @param in InputStream to read from. + * @param context + * @return SPARQLResult + */ + public SPARQLResult readAny(InputStream in, Context context) ; /** - * Using {@link #read(InputStream, Context)} is preferred. + * Using {@link #read(InputStream, Context)} is preferred. + *

+ * Notall formast support reading from a {@code java.io.Reader}. + *

* Read from an {@code Reader} and produce a {@link ResultSet}. - * Note that return result may stream and so the reader be read + * Note that return result may stream and so the reader may be read * while the ResultSet is used. * See {@link ResultSetFactory#copyResults(ResultSet)} for a ResultSet that is detached from the {@code InputStream}. * @param in Reader * @param context * @return ResultSet */ - public ResultSet read(Reader in, Context context) ; + public default ResultSet read(Reader in, Context context) { + throw new UnsupportedOperationException("ResultSetReader.read - input from a Java Reader not supported. Use an InputStream."); + } } http://git-wip-us.apache.org/repos/asf/jena/blob/716b86cf/jena-arq/src/main/java/org/apache/jena/riot/resultset/ResultSetReaderRegistry.java ---------------------------------------------------------------------- diff --git a/jena-arq/src/main/java/org/apache/jena/riot/resultset/ResultSetReaderRegistry.java b/jena-arq/src/main/java/org/apache/jena/riot/resultset/ResultSetReaderRegistry.java index f2a34d6..57f8c31 100644 --- a/jena-arq/src/main/java/org/apache/jena/riot/resultset/ResultSetReaderRegistry.java +++ b/jena-arq/src/main/java/org/apache/jena/riot/resultset/ResultSetReaderRegistry.java @@ -18,11 +18,7 @@ package org.apache.jena.riot.resultset; -import static org.apache.jena.riot.resultset.ResultSetLang.SPARQLResultSetCSV ; -import static org.apache.jena.riot.resultset.ResultSetLang.SPARQLResultSetJSON ; -import static org.apache.jena.riot.resultset.ResultSetLang.SPARQLResultSetTSV ; -import static org.apache.jena.riot.resultset.ResultSetLang.SPARQLResultSetThrift ; -import static org.apache.jena.riot.resultset.ResultSetLang.SPARQLResultSetXML ; +import static org.apache.jena.riot.resultset.ResultSetLang.*; import java.io.InputStream ; import java.io.Reader ; @@ -34,11 +30,12 @@ import org.apache.jena.atlas.lib.NotImplemented ; import org.apache.jena.query.ResultSet ; import org.apache.jena.riot.Lang ; import org.apache.jena.riot.RiotException ; +import org.apache.jena.riot.resultset.rw.ResultSetReaderJSON; +import org.apache.jena.riot.resultset.rw.ResultSetReaderXML; import org.apache.jena.riot.thrift.BinRDF ; import org.apache.jena.sparql.resultset.CSVInput ; -import org.apache.jena.sparql.resultset.JSONInput ; +import org.apache.jena.sparql.resultset.SPARQLResult; import org.apache.jena.sparql.resultset.TSVInput ; -import org.apache.jena.sparql.resultset.XMLInput ; import org.apache.jena.sparql.util.Context ; public class ResultSetReaderRegistry { @@ -56,6 +53,12 @@ public class ResultSetReaderRegistry { registry.put(lang, factory) ; } + /** Test whether {@link Lang} is registered as a result set syntax. */ + public static boolean isRegistered(Lang lang) { + Objects.requireNonNull(lang) ; + return registry.containsKey(lang); + } + private static Map registry = new HashMap<>() ; private static boolean initialized = false ; @@ -65,8 +68,8 @@ public class ResultSetReaderRegistry { initialized = true ; ResultSetReaderFactory factory = new ResultSetReaderFactoryStd() ; - register(SPARQLResultSetXML, factory) ; - register(SPARQLResultSetJSON, factory) ; + register(SPARQLResultSetXML, ResultSetReaderXML.factory) ; + register(SPARQLResultSetJSON, ResultSetReaderJSON.factory) ; register(SPARQLResultSetCSV, factory) ; register(SPARQLResultSetTSV, factory) ; register(SPARQLResultSetThrift, factory) ; @@ -76,11 +79,10 @@ public class ResultSetReaderRegistry { @Override public ResultSetReader create(Lang lang) { lang = Objects.requireNonNull(lang, "Language must not be null") ; - if ( lang.equals(SPARQLResultSetXML) ) return readerXML ; - if ( lang.equals(SPARQLResultSetJSON) ) return readerJSON ; +// if ( lang.equals(SPARQLResultSetXML) ) return readerXML ; +// if ( lang.equals(SPARQLResultSetJSON) ) return readerJSON ; if ( lang.equals(SPARQLResultSetCSV) ) return readerCSV ; if ( lang.equals(SPARQLResultSetTSV) ) return readerTSV ; - if ( lang.equals(SPARQLResultSetThrift) ) return readerThrift ; throw new RiotException("Lang not registered (ResultSet reader)") ; } } @@ -96,43 +98,49 @@ public class ResultSetReaderRegistry { @Override public ResultSet read(Reader in, Context context) { throw new NotImplemented("Reading binary data from a java.io.Reader is not possible") ; - }} ; + + } + @Override public SPARQLResult readAny(InputStream in, Context context) { + return new SPARQLResult(read(in, context)); + } + } ; } } // These all call static methods, so have no state and so don't // need to be created for each read operation. - private static ResultSetReader readerXML = new ResultSetReader() { - @Override public ResultSet read(InputStream in, Context context) { return XMLInput.fromXML(in); } - @Override public ResultSet read(Reader in, Context context) { return XMLInput.fromXML(in); } - } ; - - private static ResultSetReader readerJSON = new ResultSetReader() { - @Override public ResultSet read(InputStream in, Context context) { return JSONInput.fromJSON(in) ; } - @Override public ResultSet read(Reader in, Context context) { throw new NotImplemented("Reader") ; } - } ; +// private static ResultSetReader readerXML = new ResultSetReader() { +// @Override public ResultSet read(InputStream in, Context context) { return XMLInput.fromXML(in); } +// @Override public ResultSet read(Reader in, Context context) { return XMLInput.fromXML(in); } +// @Override public SPARQLResult readAny(InputStream in, Context context) { return XMLInput.make(in); } +// }; +// private static ResultSetReader readerJSON = new ResultSetReader() { +// @Override public ResultSet read(InputStream in, Context context) { return JSONInput.fromJSON(in) ; } +// @Override public ResultSet read(Reader in, Context context) { throw new NotImplemented("Reader") ; } +// } ; +// private static ResultSetReader readerCSV = new ResultSetReader() { @Override public ResultSet read(InputStream in, Context context) { return CSVInput.fromCSV(in) ; } @Override public ResultSet read(Reader in, Context context) { throw new NotImplemented("Reader") ; } + @Override public SPARQLResult readAny(InputStream in, Context context) { + // Not switchable. + return new SPARQLResult(read(in, context)); + } } ; private static ResultSetReader readerTSV = new ResultSetReader() { @Override public ResultSet read(InputStream in, Context context) { return TSVInput.fromTSV(in); } @Override public ResultSet read(Reader in, Context context) { throw new NotImplemented("Reader") ; } - } ; - - private static ResultSetReader readerThrift = new ResultSetReader() { - @Override public ResultSet read(InputStream in, Context context) { return BinRDF.readResultSet(in) ;} - @Override public ResultSet read(Reader in, Context context) { - throw new NotImplemented("Reading binary data from a java.io.Reader is not possible") ; - } + @Override public SPARQLResult readAny(InputStream in, Context context) { + // Not switchable. + return new SPARQLResult(read(in, context)); + } } ; private static ResultSetReader readerNo = new ResultSetReader() { @Override public ResultSet read(InputStream in, Context context) { return null ; } @Override public ResultSet read(Reader in, Context context) { return null ; } + @Override public SPARQLResult readAny(InputStream in, Context context) { return null ; } } ; - - } http://git-wip-us.apache.org/repos/asf/jena/blob/716b86cf/jena-arq/src/main/java/org/apache/jena/riot/resultset/ResultSetWriterRegistry.java ---------------------------------------------------------------------- diff --git a/jena-arq/src/main/java/org/apache/jena/riot/resultset/ResultSetWriterRegistry.java b/jena-arq/src/main/java/org/apache/jena/riot/resultset/ResultSetWriterRegistry.java index b5c4738..859ab79 100644 --- a/jena-arq/src/main/java/org/apache/jena/riot/resultset/ResultSetWriterRegistry.java +++ b/jena-arq/src/main/java/org/apache/jena/riot/resultset/ResultSetWriterRegistry.java @@ -18,12 +18,7 @@ package org.apache.jena.riot.resultset; -import static org.apache.jena.riot.resultset.ResultSetLang.SPARQLResultSetCSV ; -import static org.apache.jena.riot.resultset.ResultSetLang.SPARQLResultSetJSON ; -import static org.apache.jena.riot.resultset.ResultSetLang.SPARQLResultSetTSV ; -import static org.apache.jena.riot.resultset.ResultSetLang.SPARQLResultSetText ; -import static org.apache.jena.riot.resultset.ResultSetLang.SPARQLResultSetThrift ; -import static org.apache.jena.riot.resultset.ResultSetLang.SPARQLResultSetXML ; +import static org.apache.jena.riot.resultset.ResultSetLang.*; import java.io.OutputStream ; import java.io.Writer ; @@ -35,9 +30,13 @@ import org.apache.jena.atlas.lib.NotImplemented ; import org.apache.jena.query.ResultSet ; import org.apache.jena.riot.Lang ; import org.apache.jena.riot.RiotException ; -import org.apache.jena.riot.thrift.BinRDF ; +import org.apache.jena.riot.resultset.rw.ResultSetWriterJSON; +import org.apache.jena.riot.resultset.rw.ResultSetWriterThrift; +import org.apache.jena.riot.resultset.rw.ResultSetWriterXML; import org.apache.jena.sparql.core.Prologue ; -import org.apache.jena.sparql.resultset.* ; +import org.apache.jena.sparql.resultset.CSVOutput; +import org.apache.jena.sparql.resultset.TSVOutput; +import org.apache.jena.sparql.resultset.TextOutput; import org.apache.jena.sparql.serializer.SerializationContext ; import org.apache.jena.sparql.util.Context ; @@ -46,11 +45,16 @@ public class ResultSetWriterRegistry { private static Map registry = new HashMap<>() ; /** Lookup a {@link Lang} to get the registered {@link ResultSetReaderFactory} (or null) */ - public static ResultSetWriterFactory lookup(Lang lang) { + public static ResultSetWriterFactory getFactory(Lang lang) { Objects.requireNonNull(lang) ; return registry.get(lang) ; } + public static boolean isRegistered(Lang lang) { + Objects.requireNonNull(lang) ; + return registry.containsKey(lang) ; + } + /** Register a {@link ResultSetReaderFactory} for a {@link Lang} */ public static void register(Lang lang, ResultSetWriterFactory factory) { Objects.requireNonNull(lang) ; @@ -65,45 +69,21 @@ public class ResultSetWriterRegistry { initialized = true ; ResultSetWriterFactory factory = new ResultSetWriterFactoryStd() ; - register(SPARQLResultSetXML, factory) ; - register(SPARQLResultSetJSON, factory) ; + register(SPARQLResultSetXML, ResultSetWriterXML.factory) ; + register(SPARQLResultSetJSON, ResultSetWriterJSON.factory) ; + register(SPARQLResultSetThrift, ResultSetWriterThrift.factory) ; register(SPARQLResultSetCSV, factory) ; register(SPARQLResultSetTSV, factory) ; - register(SPARQLResultSetThrift, new ResultSetWriterThriftFactory()) ; register(SPARQLResultSetText, factory) ; } - private static ResultSetWriter writerXML = new ResultSetWriter() { - @Override public void write(OutputStream out, ResultSet resultSet, Context context) { - XMLOutput xOut = new XMLOutput(null) ; - xOut.format(out, resultSet) ; - } - @Override public void write(Writer out, ResultSet resultSet, Context context) {throw new NotImplemented("Writer") ; } - @Override public void write(OutputStream out, boolean result, Context context) { - XMLOutput xOut = new XMLOutput(null); - xOut.format(out, result); - } - } ; - - private static ResultSetWriter writerJSON = new ResultSetWriter() { - @Override public void write(OutputStream out, ResultSet resultSet, Context context) { - JSONOutput jOut = new JSONOutput() ; - jOut.format(out, resultSet) ; - } - @Override public void write(Writer out, ResultSet resultSet, Context context) {throw new NotImplemented("Writer") ; } - @Override public void write(OutputStream out, boolean result, Context context) { - JSONOutput jOut = new JSONOutput() ; - jOut.format(out, result) ; - } - } ; - private static ResultSetWriter writerCSV = new ResultSetWriter() { @Override public void write(OutputStream out, ResultSet resultSet, Context context) { CSVOutput fmt = new CSVOutput() ; fmt.format(out, resultSet) ; } - @Override public void write(Writer out, ResultSet resultSet, Context context) {throw new NotImplemented("Writer") ; } - @Override public void write(OutputStream out, boolean result, Context context) { + @Override public void write(Writer out, ResultSet resultSet, Context context) { throw new NotImplemented("Writer") ; } + @Override public void write(OutputStream out, boolean result, Context context) { CSVOutput fmt = new CSVOutput() ; fmt.format(out, result) ; } @@ -114,8 +94,8 @@ public class ResultSetWriterRegistry { TSVOutput fmt = new TSVOutput() ; fmt.format(out, resultSet) ; } - @Override public void write(Writer out, ResultSet resultSet, Context context) {throw new NotImplemented("Writer") ; } - @Override public void write(OutputStream out, boolean result, Context context) { + @Override public void write(Writer out, ResultSet resultSet, Context context) {throw new NotImplemented("Writer") ; } + @Override public void write(OutputStream out, boolean result, Context context) { TSVOutput fmt = new TSVOutput() ; fmt.format(out, result) ; } @@ -124,7 +104,7 @@ public class ResultSetWriterRegistry { private static ResultSetWriter writerNo = new ResultSetWriter() { @Override public void write(OutputStream out, ResultSet resultSet, Context context) {} @Override public void write(Writer out, ResultSet resultSet, Context context) {} - @Override public void write(OutputStream out, boolean result, Context context) {} + @Override public void write(OutputStream out, boolean result, Context context) {} } ; private static ResultSetWriter writerText = new ResultSetWriter() { @@ -145,32 +125,13 @@ public class ResultSetWriterRegistry { @Override public ResultSetWriter create(Lang lang) { lang = Objects.requireNonNull(lang, "Language must not be null") ; - if ( lang.equals(SPARQLResultSetXML) ) return writerXML ; - if ( lang.equals(SPARQLResultSetJSON) ) return writerJSON ; +// if ( lang.equals(SPARQLResultSetXML) ) return writerXML ; +// if ( lang.equals(SPARQLResultSetJSON) ) return writerJSON ; if ( lang.equals(SPARQLResultSetCSV) ) return writerCSV ; if ( lang.equals(SPARQLResultSetTSV) ) return writerTSV ; if ( lang.equals(SPARQLResultSetText) ) return writerText ; throw new RiotException("Lang not registered (ResultSet writer)") ; } } - - private static class ResultSetWriterThriftFactory implements ResultSetWriterFactory { - @Override - public ResultSetWriter create(Lang lang) { - return new ResultSetWriter() { - @Override - public void write(OutputStream out, ResultSet resultSet, Context context) - { BinRDF.writeResultSet(out, resultSet) ; } - - @Override - public void write(Writer out, ResultSet resultSet, Context context) { - throw new NotImplemented("Writing binary data to a java.io.Writer is not possible") ; - } - @Override - public void write(OutputStream out, boolean result, Context context) - { throw new NotImplemented("No Thrift RDF encoding defined for boolean results"); } - } ; - } - } } http://git-wip-us.apache.org/repos/asf/jena/blob/716b86cf/jena-arq/src/main/java/org/apache/jena/riot/resultset/rw/JSONInputIterator.java ---------------------------------------------------------------------- diff --git a/jena-arq/src/main/java/org/apache/jena/riot/resultset/rw/JSONInputIterator.java b/jena-arq/src/main/java/org/apache/jena/riot/resultset/rw/JSONInputIterator.java new file mode 100644 index 0000000..ccf770b --- /dev/null +++ b/jena-arq/src/main/java/org/apache/jena/riot/resultset/rw/JSONInputIterator.java @@ -0,0 +1,657 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jena.riot.resultset.rw; + +import java.io.InputStream; +import java.util.*; + +import org.apache.jena.atlas.AtlasException; +import org.apache.jena.atlas.io.IO; +import org.apache.jena.atlas.io.IndentedWriter; +import org.apache.jena.atlas.io.PeekReader; +import org.apache.jena.atlas.iterator.PeekIterator; +import org.apache.jena.atlas.json.io.parser.TokenizerJSON; +import org.apache.jena.datatypes.TypeMapper; +import org.apache.jena.graph.Node; +import org.apache.jena.graph.NodeFactory; +import org.apache.jena.query.QueryException; +import org.apache.jena.riot.RiotParseException; +import org.apache.jena.riot.tokens.Token; +import org.apache.jena.riot.tokens.TokenType; +import org.apache.jena.sparql.core.Var; +import org.apache.jena.sparql.engine.binding.Binding; +import org.apache.jena.sparql.engine.binding.BindingFactory; +import org.apache.jena.sparql.engine.binding.BindingMap; +import org.apache.jena.sparql.engine.iterator.QueryIteratorBase; +import org.apache.jena.sparql.serializer.SerializationContext; + +/** + * Streaming Iterator over SPARQL JSON results, not yet fully implemented (see + * JENA-267) + *

+ * Creating the Iterator automatically causes it to parse a small chunk of the + * stream to determine the variables in the result set either by reading the + * header or reading some portion of the results if the results appear before + * the header since JSON does not guarantee the order of keys within an object + *

+ */ +public class JSONInputIterator extends QueryIteratorBase { + + private InputStream input; + + private boolean isBooleanResults = false, + boolResult = false, headerSeen = false; + private Binding binding = null; + private TokenizerJSON tokens; + private PeekIterator peekIter; + + private Queue cache = new LinkedList<>(); + private Set vars = new HashSet<>(); + + /** + * Creates a SPARQL JSON Iterator + *

+ * Automatically parses some portion of the input to determine the variables + * in use + *

+ */ + public JSONInputIterator(InputStream input) { + this.input = input; + this.tokens = new TokenizerJSON(PeekReader.makeUTF8(input)); + this.peekIter = new PeekIterator<>(this.tokens); + + // We should always parse the first little bit to see the head stuff or + // to cache a chunk of results and infer the headers + // Primarily we are trying to find out what the variables are + preParse(); + } + + /** + * Returns the variables present in the result sets + */ + public Iterator getVars() { + return vars.iterator(); + } + + /** + * Gets whether the SPARQL JSON represents a boolean result set + */ + public boolean isBooleanResult() { + return isBooleanResults; + } + + /** + * Does the pre-parsing which attempts to read the header of the results + * file and determine variables present + *

+ * If the header is encountered first then we read this, if the results are + * encountered first we parse the first 100 results and determine the + * variables present from those instead + *

+ */ + private void preParse() { + // First off the { to start the object + expect("Expected the start of the JSON Results Object", TokenType.LBRACE); + + // Then expect to see a Property Name + // Loop here because we might see some things we can discard first + do { + if ( !isPropertyName() ) { + Token t = nextToken(); + String name = t.getImage(); + checkColon(); + + if ( name.equals("head") ) { + if ( headerSeen ) + exception(t, "Invalid duplicate header property"); + parseHeader(); + // Continue afterwards because we want to be in place to + // start streaming results + } else if ( name.equals("boolean") ) { + parseBoolean(); + // Afterwards we continue because we want to see an empty + // head + } else if ( name.equals("results") ) { + if ( isBooleanResults ) + exception(t, "Encountered results property when boolean property has already been countered"); + + // Scroll to first result + parseToFirstResult(); + + // If we already saw the header then exit at this point + if ( headerSeen ) + return; + + // If not we're going to pre-cache some chunk of results so + // we can infer the variable names + boolean complete = cacheResults(100); + + // If this exhausted the result set then we can continue + // looking for the header + // Otherwise we should exit as we may eventually see the + // header later... + if ( !complete ) { + // TODO Now determine variables present from this + return; + } + } else { + ignoreValue(); + } + checkComma(TokenType.RBRACE); + } else if ( lookingAt(TokenType.RBRACE) ) { + // We hit the end of the result object already + if ( !headerSeen ) + exception(peekToken(), "End of JSON Results Object encountered before a valid header was seen"); + nextToken(); + + // Shouldn't be any further content + if ( !lookingAt(TokenType.EOF) ) + exception(peekToken(), "Unexpected content after end of JSON Results Object"); + + // Can stop our initial buffering at this stage + return; + } else { + exception(peekToken(), "Expected a JSON property name but got %s", peekToken()); + } + } while (true); + } + + private void parseHeader() { + do { + if ( isPropertyName() ) { + Token t = nextToken(); + String name = t.getImage(); + checkColon(); + + if ( name.equals("vars") ) { + parseVars(); + } else if ( name.equals("link") ) { + // Throw away the links + skipLinks(); + } else { + exception(t, "Unexpected property %s encountered in head object", name); + } + checkComma(TokenType.RBRACE); + } else if ( lookingAt(TokenType.RBRACE) ) { + nextToken(); + return; + } else { + exception(peekToken(), "Unexpected Token encountered while parsing head object"); + } + } while (true); + } + + private void parseVars() { + if ( lookingAt(TokenType.LBRACKET) ) { + nextToken(); + vars.clear(); + do { + if ( lookingAt(TokenType.STRING) ) { + Token t = nextToken(); + String var = t.getImage(); + vars.add(var); + checkComma(TokenType.RBRACKET); + } else if ( lookingAt(TokenType.RBRACKET) ) { + nextToken(); + return; + } else { + exception(peekToken(), "Unexpected Token encountered while parsing the variables list in the head object"); + } + } while (true); + } else { + exception(peekToken(), "Unexpected Token ecountered, expected a [ to start the array of variables in the head object"); + } + } + + private void skipLinks() { + if ( lookingAt(TokenType.LBRACKET) ) { + nextToken(); + do { + if ( lookingAt(TokenType.RBRACKET) ) { + // End of links + nextToken(); + return; + } else if ( lookingAt(TokenType.STRING) ) { + // Ignore link and continue + nextToken(); + } else { + exception(peekToken(), "Unexpected Token when a Link URI was expected"); + } + checkComma(TokenType.RBRACKET); + } while (true); + } else { + exception(peekToken(), "Unexpected token when a [ was expected to start the list of URIs for a link property"); + } + } + + private void parseToFirstResult() { + if ( lookingAt(TokenType.LBRACE) ) { + nextToken(); + if ( isPropertyName() ) { + Token t = nextToken(); + String name = t.getImage(); + if ( name.equals("bindings") ) { + checkColon(); + if ( lookingAt(TokenType.LBRACKET) ) { + nextToken(); + } else { + exception(peekToken(), "Unexpected Token encountered, expected a [ for the start of the bindings array"); + } + } else { + exception(t, "Unexpected Token encountered, expected the bindings property"); + } + } else { + exception(peekToken(), "Unexpected Token ecnountered, expected the bindings property"); + } + } else { + exception(peekToken(), "Unexpected Token encountered, expected a { to start the results list object"); + } + } + + private void parseToEnd() { + // TODO Parse through to end of the JSON document consuming the header + // if we haven't seen it already + checkComma(TokenType.RBRACE); + } + + private void ignoreValue() { + if ( isPropertyName() ) { + // Just a string value so can discard and then check for the + // subsequent comma + nextToken(); + checkComma(TokenType.RBRACE); + } else if ( lookingAt(TokenType.DECIMAL) || lookingAt(TokenType.INTEGER) || lookingAt(TokenType.DOUBLE) + || lookingAt(TokenType.KEYWORD) ) { + // Just a numeric/keyword (boolean) value do discard and check for + // subsequent comma + nextToken(); + checkComma(TokenType.RBRACE); + } else if ( lookingAt(TokenType.LBRACE) ) { + // Start of an Object + nextToken(); + + // TODO We should really care about the syntactic validity of + // objects we are ignoring but that seems like a bit too much effort + int openBraces = 1; + while (openBraces >= 1) { + Token next = nextToken(); + if ( next.getType().equals(TokenType.LBRACE) ) { + openBraces++; + } else if ( next.getType().equals(TokenType.RBRACE) ) { + openBraces--; + } + } + checkComma(TokenType.RBRACE); + } else if ( lookingAt(TokenType.LBRACKET) ) { + // Start of an Array + nextToken(); + + // TODO We should really care about the syntactic validity of + // objects we are ignoring but that seems like a bit too much effort + int openBraces = 1; + while (openBraces >= 1) { + Token next = nextToken(); + if ( next.getType().equals(TokenType.LBRACKET) ) { + openBraces++; + } else if ( next.getType().equals(TokenType.RBRACKET) ) { + openBraces--; + } + } + checkComma(TokenType.RBRACE); + } else { + exception(peekToken(), "Unexpected Token"); + } + } + + /** + * Caches the first N results so we can infer variables, indicates whether + * the caching exhausted the result set + * + * @param n + * Number of results to cache + */ + private boolean cacheResults(int n) { + for ( int i = 0 ; i < n ; i++ ) { + if ( parseNextBinding() ) { + this.cache.add(this.binding); + this.binding = null; + } else { + return true; + } + } + return false; + } + + private void parseBoolean() { + isBooleanResults = true; + if ( lookingAt(TokenType.KEYWORD) ) { + Token t = nextToken(); + String keyword = t.getImage(); + if ( keyword.equals("true") ) { + boolResult = true; + } else if ( keyword.equals("false") ) { + boolResult = false; + } else { + exception(t, "Unexpected keyword %s encountered, expected true or false", keyword); + } + } else { + exception(peekToken(), "Unexpected token when a true/false keyword was expected for the value of the boolean property"); + } + } + + @Override + public void output(IndentedWriter out, SerializationContext sCxt) { + // Not needed - only called as part of printing/debugging query plans. + out.println("JSONInputIterator"); + } + + @Override + protected boolean hasNextBinding() { + if ( isBooleanResults ) + return false; + + if ( this.input != null ) { + if ( this.cache.size() > 0 ) { + this.binding = this.cache.remove(); + return true; + } else if ( this.binding == null ) { + return this.parseNextBinding(); + } else { + return true; + } + } else { + return false; + } + } + + private boolean parseNextBinding() { + if ( lookingAt(TokenType.LBRACE) ) { + nextToken(); + BindingMap b = BindingFactory.create(); + do { + if ( isPropertyName() ) { + Token t = nextToken(); + String var = t.getImage(); + checkColon(); + + Node n = parseNode(); + b.add(Var.alloc(var), n); + + checkComma(TokenType.RBRACE); + } else if ( lookingAt(TokenType.RBRACE) ) { + nextToken(); + checkComma(TokenType.RBRACKET); + break; + } else { + exception(peekToken(), "Unexpected Token encountered, expected a property name to indicate the value for a variable"); + } + } while (true); + + this.binding = b; + return true; + } else if ( lookingAt(TokenType.RBRACKET) ) { + // End of Bindings Array + nextToken(); + if ( lookingAt(TokenType.RBRACE) ) { + nextToken(); + parseToEnd(); + } else { + exception(peekToken(), "Unexpected Token encountered, expected a } to end the results object"); + } + } else { + exception(peekToken(), + "Unexpected Token encountered, expected a { for the start of a binding of ] to end the array of bindings"); + } + return false; + } + + private Node parseNode() { + String type, value, lang, datatype; + type = value = lang = datatype = null; + + if ( lookingAt(TokenType.LBRACE) ) { + Token pos = nextToken(); + + // Collect the Properties + do { + if ( isPropertyName() ) { + Token t = nextToken(); + String name = t.getImage(); + checkColon(); + + if ( name.equals("type") ) { + if ( type != null ) + exception(t, "Illegal duplicate type property"); + type = parseNodeInfo("type"); + } else if ( name.equals("value") ) { + if ( value != null ) + exception(t, "Illegal duplicate value property"); + value = parseNodeInfo("value"); + } else if ( name.equals("datatype") ) { + if ( datatype != null ) + exception(t, "Illegal duplicate datatype property"); + datatype = parseNodeInfo("datatype"); + } else if ( name.equals("xml:lang") ) { + if ( lang != null ) + exception(t, "Illegal duplicate xml:lang property"); + lang = parseNodeInfo("xml:lang"); + } else { + exception(t, "Unexpected Property Name '%s', expected one of type, value, datatype or xml:lang", name); + } + } else if ( lookingAt(TokenType.RBRACE) ) { + nextToken(); + break; + } else { + exception(peekToken(), "Unexpected Token, expected a property name as part of a Node object"); + } + } while (true); + + // Error if missing type or value + if ( type == null ) + exception(pos, "Encountered a Node object with no type property"); + if ( value == null ) + exception(pos, "Encountered a Node object with no value property"); + + // Generate a Node based on the properties we saw + if ( type.equals("uri") ) { + return NodeFactory.createURI(value); + } else if ( type.equals("literal") ) { + if ( datatype != null ) { + return NodeFactory.createLiteral(value, TypeMapper.getInstance().getSafeTypeByName(datatype)); + } else if ( lang != null ) { + return NodeFactory.createLiteral(value, lang); + } else { + return NodeFactory.createLiteral(value); + } + } else if ( type.equals("bnode") ) { + return NodeFactory.createBlankNode(value); + } else { + exception(pos, "Encountered a Node object with an invalid type value '%s', expected one of uri, literal or bnode", type); + } + } else { + exception(peekToken(), "Unexpected Token, expected a { for the start of a Node object"); + } + return null; + } + + private String parseNodeInfo(String name) { + if ( lookingAt(TokenType.STRING) ) { + Token t = nextToken(); + String value = t.getImage(); + checkComma(TokenType.RBRACE); + return value; + } else { + exception(peekToken(), "Unexpected Token, expected a string as the value for the %s property", name); + return null; + } + } + + @Override + protected Binding moveToNextBinding() { + if ( !hasNext() ) + throw new NoSuchElementException(); + Binding b = this.binding; + this.binding = null; + return b; + } + + @Override + protected void closeIterator() { + IO.close(input); + input = null; + } + + @Override + protected void requestCancel() { + // Don't need to do anything special to cancel + // Superclass should take care of that and call closeIterator() where we + // do our actual clean up + } + + // JSON Parsing Helpers taken from LangRDFJSON + + private boolean isPropertyName() { + return lookingAt(TokenType.STRING); + } + + private Token checkValidForStringProperty(String property) { + Token t = null; + if ( lookingAt(TokenType.STRING) ) { + t = nextToken(); + } else { + exception(peekToken(), "JSON Values given for property " + property + " must be Strings"); + } + return t; + } + + private void checkColon() { + if ( !lookingAt(TokenType.COLON) ) { + exception(peekToken(), "Expected a : character after a JSON Property Name but got %s", peekToken()); + } + nextToken(); + } + + private void checkComma(TokenType terminator) { + if ( lookingAt(TokenType.COMMA) ) { + nextToken(); + } else if ( lookingAt(terminator) ) { + return; + } else { + exception(peekToken(), "Unexpected Token encountered, expected a , or a %s", terminator); + } + } + + // Streaming Parsing Helper Functions nicked from LangEngine + + // ---- Managing tokens. + + protected final Token peekToken() { + // Avoid repeating. + if ( eof() ) + return tokenEOF; + return peekIter.peek(); + } + + // Set when we get to EOF to record line/col of the EOF. + private Token tokenEOF = null; + + protected final boolean eof() { + if ( tokenEOF != null ) + return true; + + if ( !moreTokens() ) { + tokenEOF = new Token(tokens.getLine(), tokens.getColumn()); + tokenEOF.setType(TokenType.EOF); + return true; + } + return false; + } + + protected final boolean moreTokens() { + return peekIter.hasNext(); + } + + protected final boolean lookingAt(TokenType tokenType) { + if ( eof() ) + return tokenType == TokenType.EOF; + if ( tokenType == TokenType.NODE ) + return peekToken().isNode(); + return peekToken().hasType(tokenType); + } + + // Remember line/col of last token for messages + protected long currLine = -1; + protected long currCol = -1; + + protected final Token nextToken() { + if ( eof() ) + return tokenEOF; + + // Tokenizer errors appear here! + try { + Token t = peekIter.next(); + currLine = t.getLine(); + currCol = t.getColumn(); + return t; + } + catch (RiotParseException ex) { + // Intercept to log it. + raiseException(ex); + throw ex; + } + catch (AtlasException ex) { + // Bad I/O + RiotParseException ex2 = new RiotParseException(ex.getMessage(), -1, -1); + raiseException(ex2); + throw ex2; + } + } + + protected final void expectOrEOF(String msg, TokenType tokenType) { + // DOT or EOF + if ( eof() ) + return; + expect(msg, tokenType); + } + + protected final void expect(String msg, TokenType ttype) { + + if ( !lookingAt(ttype) ) { + Token location = peekToken(); + exception(location, msg); + } + nextToken(); + } + + protected final void exception(Token token, String msg, Object... args) { + if ( token != null ) + exceptionDirect(String.format(msg, args), token.getLine(), token.getColumn()); + else + exceptionDirect(String.format(msg, args), -1, -1); + } + + protected final void exceptionDirect(String msg, long line, long col) { + raiseException(new RiotParseException(msg, line, col)); + } + + protected final void raiseException(RiotParseException ex) { + throw new QueryException("Error passing SPARQL JSON results", ex); + } + +} http://git-wip-us.apache.org/repos/asf/jena/blob/716b86cf/jena-arq/src/main/java/org/apache/jena/riot/resultset/rw/JSONResultsKW.java ---------------------------------------------------------------------- diff --git a/jena-arq/src/main/java/org/apache/jena/riot/resultset/rw/JSONResultsKW.java b/jena-arq/src/main/java/org/apache/jena/riot/resultset/rw/JSONResultsKW.java new file mode 100644 index 0000000..beac34f --- /dev/null +++ b/jena-arq/src/main/java/org/apache/jena/riot/resultset/rw/JSONResultsKW.java @@ -0,0 +1,44 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jena.riot.resultset.rw; + +//Keywords for JSON: +//Taken from: +//From http://www.w3.org/TR/sparql11-results-json/ (Oct 2011) + +public class JSONResultsKW +{ + public static String kHead = "head" ; + public static String kVars = "vars" ; + public static String kLink = "link" ; + public static String kResults = "results" ; + public static String kBindings = "bindings" ; + public static String kType = "type" ; + public static String kUri = "uri" ; + public static String kValue = "value" ; + public static String kLiteral = "literal" ; + public static String kUnbound = "undef" ; + // Legacy. + public static String kTypedLiteral = "typed-literal" ; + public static String kXmlLang = "xml:lang" ; + public static String kDatatype = "datatype" ; + public static String kBnode = "bnode" ; + public static String kBoolean = "boolean" ; +} + http://git-wip-us.apache.org/repos/asf/jena/blob/716b86cf/jena-arq/src/main/java/org/apache/jena/riot/resultset/rw/ReadAnything.java ---------------------------------------------------------------------- diff --git a/jena-arq/src/main/java/org/apache/jena/riot/resultset/rw/ReadAnything.java b/jena-arq/src/main/java/org/apache/jena/riot/resultset/rw/ReadAnything.java new file mode 100644 index 0000000..089845b --- /dev/null +++ b/jena-arq/src/main/java/org/apache/jena/riot/resultset/rw/ReadAnything.java @@ -0,0 +1,100 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jena.riot.resultset.rw; + +import java.util.function.Supplier; + +import org.apache.jena.atlas.web.ContentType; +import org.apache.jena.atlas.web.TypedInputStream; +import org.apache.jena.query.ARQ; +import org.apache.jena.query.Dataset; +import org.apache.jena.query.DatasetFactory; +import org.apache.jena.rdf.model.Model; +import org.apache.jena.rdf.model.ModelFactory; +import org.apache.jena.riot.*; +import org.apache.jena.riot.resultset.ResultSetReaderRegistry; +import org.apache.jena.riot.system.StreamRDF; +import org.apache.jena.riot.system.StreamRDFLib; +import org.apache.jena.riot.system.stream.StreamManager; +import org.apache.jena.sparql.resultset.SPARQLResult; +import org.apache.jena.sparql.util.Context; +import org.apache.jena.system.Txn; + +/** Read anything (RDF). + *
  • By MIME type. + *
  • By format (resultset, boolean, graph) + */ +public class ReadAnything { + + /** Read something RDF/SPARQL like */ + public static SPARQLResult read(String url) { + return read(url, ARQ.getContext()); + } + + /** Read something RDF/SPARQL like */ + public static SPARQLResult read(String url, Context context) { + TypedInputStream in = StreamManager.get(context).open(url); + ContentType ct = WebContent.determineCT(in.getContentType(), null, url); + Lang lang = RDFLanguages.contentTypeToLang(ct); + + if ( RDFLanguages.isTriples(lang) ) { + Model model = ModelFactory.createDefaultModel(); + Supplier r = ()->{ + StreamRDF sink = StreamRDFLib.graph(model.getGraph()); + RDFParser.source(in).lang(lang).parse(sink); + return new SPARQLResult(model); + }; + if ( model.supportsTransactions() ) + return model.calculateInTxn(r); + else + return r.get(); + } + + if ( RDFLanguages.isQuads(lang) ) { + Dataset ds = DatasetFactory.create(); + Supplier r = ()->{ + StreamRDF sink = StreamRDFLib.dataset(ds.asDatasetGraph()); + RDFParser.source(in).lang(lang).parse(sink); + return new SPARQLResult(ds); + }; + + if ( ds.supportsTransactions() ) + return Txn.calculateWrite(ds, r); + else + return r.get(); + } + + if ( ResultSetReaderRegistry.isRegistered(lang) ) { + return + ResultsReader.create() + .forceLang(lang) + .context(context) + .build() + .readAny(in.getInputStream()); + // Which would do, if we need to invert the code ... +// ResultSetReaderFactory factory = ResultSetReaderRegistry.getFactory(lang); +// if ( factory == null ) +// throw new RiotException("No ResultSetReaderFactory for "+lang); +// ResultSetReader reader = factory.create(lang); +// ResultSet rs = reader.read(in.getInputStream(), context); + } + + throw new RiotException("Failed to determine: lang = "+lang); + } +}