From f0255f1a032753dc8c8c39f83555f8c85945de7c Mon Sep 17 00:00:00 2001 From: Andy Seaborne Date: Wed, 15 Nov 2017 23:26:27 +0000 Subject: [PATCH 1/2] RDFParser.parse for graph and datasetgraph --- .../java/org/apache/jena/riot/RDFParser.java | 19 +++++++++++++++++++ .../apache/jena/riot/RDFParserBuilder.java | 16 ++++++++-------- 2 files changed, 27 insertions(+), 8 deletions(-) diff --git a/jena-arq/src/main/java/org/apache/jena/riot/RDFParser.java b/jena-arq/src/main/java/org/apache/jena/riot/RDFParser.java index da8ef555b5b..a32197a2426 100644 --- a/jena-arq/src/main/java/org/apache/jena/riot/RDFParser.java +++ b/jena-arq/src/main/java/org/apache/jena/riot/RDFParser.java @@ -221,6 +221,25 @@ private boolean allNull(Object... objs) { return true; } + /** + * Parse the source, sending the results to a {@link Graph}. The source must be for + * triples; any quads are discarded. + */ + public void parse(Graph graph) { + parse(StreamRDFLib.graph(graph)); + } + + + /** + * Parse the source, sending the results to a {@link DatasetGraph}. + */ + public void parse(DatasetGraph dataset) { + parse(StreamRDFLib.dataset(dataset)); + } + + /** + * Parse the source, sending the results to a {@link StreamRDF}. + */ public void parse(StreamRDF destination) { if ( !canUse ) throw new RiotException("Parser has been used once and can not be used again"); diff --git a/jena-arq/src/main/java/org/apache/jena/riot/RDFParserBuilder.java b/jena-arq/src/main/java/org/apache/jena/riot/RDFParserBuilder.java index 09a1de4bf10..dc916058c4b 100644 --- a/jena-arq/src/main/java/org/apache/jena/riot/RDFParserBuilder.java +++ b/jena-arq/src/main/java/org/apache/jena/riot/RDFParserBuilder.java @@ -418,26 +418,26 @@ public void parse(StreamRDF stream) { } /** - * Parse the source, sending the results to a {@link Graph}. The source must be for - * triples; any quads are discarded. - * Short form for {@code build().parse(stream)} - * where {@code stream} sends triples and prefixes to the {@code Graph}. + * Parse the source, sending the results to a {@link Graph}. + * The source must be for triples; any quads are discarded. + * Short form for {@code build().parse(graph)} + * which sends triples and prefixes to the {@code Graph}. * * @param graph */ public void parse(Graph graph) { - parse(StreamRDFLib.graph(graph)); + build().parse(graph); } /** * Parse the source, sending the results to a {@link DatasetGraph}. - * Short form for {@code build().parse(stream)} - * where {@code stream} sends triples and prefixes to the {@code DatasetGraph}. + * Short form for {@code build().parse(dataset)} + * which sends triples and prefixes to the {@code DatasetGraph}. * * @param dataset */ public void parse(DatasetGraph dataset) { - parse(StreamRDFLib.dataset(dataset)); + build().parse(dataset); } /** Build an {@link RDFParser}. The parser takes it's configuration from this builder and can not then be changed. From c3d6d17894b98f5fb340964cdd8e2f269e27acf0 Mon Sep 17 00:00:00 2001 From: Andy Seaborne Date: Wed, 15 Nov 2017 23:26:47 +0000 Subject: [PATCH 2/2] JENA-1424: LOAD with conneg --- .../sparql/modify/UpdateEngineWorker.java | 63 +++++++----- .../sparql/modify/TestUpdateOperations.java | 97 ++++++++++++++++++- jena-arq/testing/Update/D-bad.nq | 2 + jena-arq/testing/Update/D-bad.nt | 3 + jena-arq/testing/Update/D-quads.nt | 1 + 5 files changed, 142 insertions(+), 24 deletions(-) create mode 100644 jena-arq/testing/Update/D-bad.nq create mode 100644 jena-arq/testing/Update/D-bad.nt create mode 100644 jena-arq/testing/Update/D-quads.nt diff --git a/jena-arq/src/main/java/org/apache/jena/sparql/modify/UpdateEngineWorker.java b/jena-arq/src/main/java/org/apache/jena/sparql/modify/UpdateEngineWorker.java index 0b9d97dfd67..e6891ecb6f0 100644 --- a/jena-arq/src/main/java/org/apache/jena/sparql/modify/UpdateEngineWorker.java +++ b/jena-arq/src/main/java/org/apache/jena/sparql/modify/UpdateEngineWorker.java @@ -33,15 +33,14 @@ import org.apache.jena.atlas.iterator.Iter ; import org.apache.jena.atlas.lib.Pair ; import org.apache.jena.atlas.lib.Sink ; +import org.apache.jena.atlas.web.TypedInputStream; import org.apache.jena.graph.Graph ; import org.apache.jena.graph.GraphUtil ; import org.apache.jena.graph.Node ; import org.apache.jena.graph.Triple ; import org.apache.jena.query.Query ; import org.apache.jena.query.QueryExecutionFactory ; -import org.apache.jena.riot.Lang ; -import org.apache.jena.riot.RDFLanguages ; -import org.apache.jena.riot.RDFParser ; +import org.apache.jena.riot.*; import org.apache.jena.riot.system.SerializationFactoryFinder ; import org.apache.jena.sparql.ARQInternalErrorException ; import org.apache.jena.sparql.SystemARQ ; @@ -137,30 +136,48 @@ public void visit(UpdateLoad update) { // LOAD SILENT? iri ( INTO GraphRef )? String source = update.getSource(); Node dest = update.getDest(); + Graph graph = graph(datasetGraph, dest); + // We must load buffered if silent so that the dataset graph sees + // all or no triples/quads when there is a parse error + // (no nested transaction abort). + boolean loadBuffered = update.getSilent() || ! datasetGraph.supportsTransactionAbort() ; try { - // Read into temporary storage to protect against parse errors. - if ( dest != null ) { - Lang lang = RDFLanguages.filenameToLang(source); - // load-to-graph - must be triples. - if ( ! RDFLanguages.isTriples(lang) ) - throw new UpdateException("Attempt to load quads into a graph"); - // LOAD-INTO graph ... must be triples. + if ( dest == null ) { + // LOAD SILENT? iri + // Quads accepted (extension). + if ( loadBuffered ) { + DatasetGraph dsg2 = DatasetGraphFactory.create(); + RDFDataMgr.read(dsg2, source); + dsg2.find().forEachRemaining(datasetGraph::add); + } else { + RDFDataMgr.read(datasetGraph, source); + } + return ; + } + // LOAD SILENT? iri INTO GraphRef + // Load triples. To give a decent error message and also not have the usual + // parser behaviour of just selecting default graph triples when the + // destination is a graph, we need to do the same steps as RDFParser.parseURI, + // with different checking. + TypedInputStream input = RDFDataMgr.open(source); + String contentType = input.getContentType(); + Lang lang = RDFDataMgr.determineLang(source, contentType, Lang.TTL); + if ( lang == null ) + throw new UpdateException("Failed to determine the syntax for '"+source+"'"); + if ( ! RDFLanguages.isTriples(lang) ) + throw new UpdateException("Attempt to load quads into a graph"); + RDFParser parser = RDFParser + .source(input.getInputStream()) + .forceLang(lang) + .build(); + if ( loadBuffered ) { Graph g = GraphFactory.createGraphMem(); - RDFParser.source(source).parse(g); - Graph g2 = graph(datasetGraph, dest); - GraphUtil.addInto(g2, g); + parser.parse(g); + GraphUtil.addInto(graph, g); } else { - // LOAD -- allow quads. - DatasetGraph dsg = DatasetGraphFactory.create(); - RDFParser.source(source).parse(dsg); - Iterator iter = dsg.find(); - for ( ; iter.hasNext() ; ) { - Quad q = iter.next(); - datasetGraph.add(q); - } + parser.parse(graph); } - } - catch (RuntimeException ex) { + } catch (RuntimeException ex) { if ( !update.getSilent() ) { if ( ex instanceof UpdateException ) throw ex; diff --git a/jena-arq/src/test/java/org/apache/jena/sparql/modify/TestUpdateOperations.java b/jena-arq/src/test/java/org/apache/jena/sparql/modify/TestUpdateOperations.java index 02d83aceede..aa250470af6 100644 --- a/jena-arq/src/test/java/org/apache/jena/sparql/modify/TestUpdateOperations.java +++ b/jena-arq/src/test/java/org/apache/jena/sparql/modify/TestUpdateOperations.java @@ -28,14 +28,21 @@ import org.apache.jena.rdf.model.ModelFactory ; import org.apache.jena.rdf.model.RDFNode ; import org.apache.jena.rdf.model.Resource ; +import org.apache.jena.riot.system.ErrorHandler; +import org.apache.jena.riot.system.ErrorHandlerFactory; import org.apache.jena.sparql.core.DatasetGraph ; import org.apache.jena.sparql.core.DatasetGraphFactory ; import org.apache.jena.sparql.core.DatasetGraphWrapper ; import org.apache.jena.sparql.core.Quad ; import org.apache.jena.sparql.sse.SSE ; -import org.apache.jena.update.* ; +import org.apache.jena.update.UpdateAction; +import org.apache.jena.update.UpdateException; +import org.apache.jena.update.UpdateFactory; +import org.apache.jena.update.UpdateRequest; import org.apache.jena.vocabulary.OWL ; import org.apache.jena.vocabulary.RDF ; +import org.junit.AfterClass; +import org.junit.BeforeClass; import org.junit.Test ; // Most of the testing of SPARQL Update is scripts and uses the SPARQL-WG test suite. @@ -46,6 +53,19 @@ public class TestUpdateOperations extends BaseTest private DatasetGraph graphStore() { return DatasetGraphFactory.create() ; } private Node gName = SSE.parseNode("") ; + private static ErrorHandler eh; + + // Silence parser output. + @BeforeClass public static void beforeClass() { + eh = ErrorHandlerFactory.getDefaultErrorHandler(); + ErrorHandler silent = ErrorHandlerFactory.errorHandlerStrictSilent(); + ErrorHandlerFactory.setDefaultErrorHandler(silent); + } + + @AfterClass public static void afterClass() { + ErrorHandlerFactory.setDefaultErrorHandler(eh); + } + @Test public void load1() { DatasetGraph gs = graphStore() ; UpdateRequest req = UpdateFactory.create("LOAD <"+DIR+"/D.nt>") ; @@ -86,6 +106,81 @@ public void load4() { assertEquals(0, Iter.count(gs.find())) ; } + @Test(expected=UpdateException.class) + public void load6() { + DatasetGraph gs = graphStore() ; + UpdateRequest req = UpdateFactory.create("LOAD <"+DIR+"/D-bad.nq>") ; + UpdateAction.execute(req, gs) ; + assertEquals(0, Iter.count(gs.find())) ; + } + + @Test public void load7() { + DatasetGraph gs = graphStore() ; + UpdateRequest req = UpdateFactory.create("LOAD SILENT <"+DIR+"/D-bad.nq>") ; + UpdateAction.execute(req, gs) ; + assertEquals(0, Iter.count(gs.find())) ; + } + + @Test(expected=UpdateException.class) + public void load8() { + DatasetGraph gs = graphStore() ; + UpdateRequest req = UpdateFactory.create("LOAD <"+DIR+"/D-bad.nt> INTO GRAPH <"+gName.getURI()+">") ; + UpdateAction.execute(req, gs) ; + assertEquals(0, Iter.count(gs.find())) ; + } + + @Test public void load9() { + DatasetGraph gs = graphStore() ; + UpdateRequest req = UpdateFactory.create("LOAD SILENT <"+DIR+"/D-bad.nt> INTO GRAPH <"+gName.getURI()+">") ; + UpdateAction.execute(req, gs) ; + assertEquals(0, Iter.count(gs.find())) ; + } + + @Test(expected=UpdateException.class) + public void load10() { + DatasetGraph gs = graphStore() ; + UpdateRequest req = UpdateFactory.create("LOAD <"+DIR+"/D-quads.nt> INTO GRAPH <"+gName.getURI()+">") ; + UpdateAction.execute(req, gs) ; + assertEquals(0, Iter.count(gs.find())) ; + } + + @Test public void load11() { + DatasetGraph gs = graphStore() ; + UpdateRequest req = UpdateFactory.create("LOAD SILENT <"+DIR+"/D-quads.nt> INTO GRAPH <"+gName.getURI()+">") ; + UpdateAction.execute(req, gs) ; + assertEquals(0, Iter.count(gs.find())) ; + } + + @Test(expected=UpdateException.class) + public void load12() { + DatasetGraph gs = graphStore() ; + UpdateRequest req = UpdateFactory.create("LOAD <"+DIR+"/D-not-found.nt>") ; + UpdateAction.execute(req, gs) ; + assertEquals(0, Iter.count(gs.find())) ; + } + + @Test public void load13() { + DatasetGraph gs = graphStore() ; + UpdateRequest req = UpdateFactory.create("LOAD SILENT <"+DIR+"/D-not-found.nt>") ; + UpdateAction.execute(req, gs) ; + assertEquals(0, Iter.count(gs.find())) ; + } + + @Test(expected=UpdateException.class) + public void load14() { + DatasetGraph gs = graphStore() ; + UpdateRequest req = UpdateFactory.create("LOAD <"+DIR+"/D-not-found.nt> INTO GRAPH <"+gName.getURI()+">") ; + UpdateAction.execute(req, gs) ; + assertEquals(0, Iter.count(gs.find())) ; + } + + @Test public void load15() { + DatasetGraph gs = graphStore() ; + UpdateRequest req = UpdateFactory.create("LOAD SILENT <"+DIR+"/D-not-found.nt> INTO GRAPH <"+gName.getURI()+">") ; + UpdateAction.execute(req, gs) ; + assertEquals(0, Iter.count(gs.find())) ; + } + @Test public void insert_where_01() { Model m = ModelFactory.createDefaultModel(); Resource anon = m.createResource(); diff --git a/jena-arq/testing/Update/D-bad.nq b/jena-arq/testing/Update/D-bad.nq new file mode 100644 index 00000000000..58ca5b32f4a --- /dev/null +++ b/jena-arq/testing/Update/D-bad.nq @@ -0,0 +1,2 @@ + . +aaaaaaaaaaaaaaaaaa . diff --git a/jena-arq/testing/Update/D-bad.nt b/jena-arq/testing/Update/D-bad.nt new file mode 100644 index 00000000000..d7a9e8f458a --- /dev/null +++ b/jena-arq/testing/Update/D-bad.nt @@ -0,0 +1,3 @@ + . +aaaaaaaaa . + diff --git a/jena-arq/testing/Update/D-quads.nt b/jena-arq/testing/Update/D-quads.nt new file mode 100644 index 00000000000..a52ec902a9a --- /dev/null +++ b/jena-arq/testing/Update/D-quads.nt @@ -0,0 +1 @@ + .