Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,7 @@ public static <T> T getOrElseThrow(CompletableFuture<T> cf, HttpRequest httpRequ
}
}


/**
* MUST consume or close the input stream
* @see HttpLib#finish(HttpResponse)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import org.apache.jena.riot.web.HttpNames;
import org.apache.jena.sparql.core.Var;
import org.apache.jena.sparql.engine.binding.Binding;
import org.apache.jena.sparql.engine.dispatch.SparqlDispatcherRegistry;
import org.apache.jena.sparql.exec.http.Params;
import org.apache.jena.sparql.exec.http.QuerySendMode;
import org.apache.jena.sparql.syntax.syntaxtransform.QueryTransformOps;
Expand All @@ -46,7 +47,7 @@ public abstract class ExecHTTPBuilder<X, Y> {
protected String serviceURL = null;
private Query query = null;
protected String queryString = null;
protected boolean parseCheck = true;
protected Optional<Boolean> parseCheck = Optional.empty();
private HttpClient httpClient = null;
protected Map<String, String> httpHeaders = new HashMap<>();
protected Params params = Params.create();
Expand Down Expand Up @@ -84,10 +85,14 @@ public Y endpoint(String serviceURL) {

/** Whether to parse query strings passed to {@link #query(String)}. */
public Y parseCheck(boolean parseCheck) {
this.parseCheck = parseCheck;
this.parseCheck = Optional.of(parseCheck);
return thisBuilder();
}

protected boolean effectiveParseCheck() {
return SparqlDispatcherRegistry.effectiveParseCheck(parseCheck, contextAcc);
}

/** Set the query - this also sets the query string to agree with the query argument. */
public Y query(Query query) {
Objects.requireNonNull(query);
Expand All @@ -102,14 +107,14 @@ public Y query(Query query) {
*/
public Y query(String queryStr) {
Objects.requireNonNull(queryStr);
Query query = parseCheck ? QueryFactory.create(queryStr) : null;
Query query = effectiveParseCheck() ? QueryFactory.create(queryStr) : null;
setQuery(query, queryStr);
return thisBuilder();
}

public Y query(String queryStr, Syntax syntax) {
Objects.requireNonNull(queryStr);
Query query = QueryFactory.create(queryStr, syntax);
Query query = effectiveParseCheck() ? QueryFactory.create(queryStr, syntax) : null;
setQuery(query, queryStr);
return thisBuilder();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,13 @@
import java.net.http.HttpClient;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import org.apache.jena.graph.Node;
import org.apache.jena.http.HttpEnv;
import org.apache.jena.query.ARQ;
import org.apache.jena.sparql.core.Var;
import org.apache.jena.sparql.engine.binding.Binding;
import org.apache.jena.sparql.engine.dispatch.SparqlDispatcherRegistry;
import org.apache.jena.sparql.exec.http.Params;
import org.apache.jena.sparql.exec.http.UpdateSendMode;
import org.apache.jena.sparql.syntax.syntaxtransform.UpdateTransformOps;
Expand All @@ -37,110 +37,14 @@
import org.apache.jena.sys.JenaSystem;
import org.apache.jena.update.Update;
import org.apache.jena.update.UpdateException;
import org.apache.jena.update.UpdateFactory;
import org.apache.jena.update.UpdateRequest;

public abstract class ExecUpdateHTTPBuilder<X, Y> {

/** Update element. Either an Update object or a string. */
private record UpdateElt(Update update, String updateString) {
UpdateElt(Update update) { this(Objects.requireNonNull(update), null); }
UpdateElt(String updateString) { this(null, Objects.requireNonNull(updateString)); }
boolean isParsed() { return update != null; }

@Override
public String toString() {
return isParsed()
? new UpdateRequest(update()).toString() // Reuse UpdateRequest's serialization approach
: updateString();
}
}

/** Accumulator for update elements. Can build an overall string or UpdateRequest from the elements. */
private class UpdateEltAcc implements Iterable<UpdateElt> {
/** Delimiter for joining multiple SPARQL update strings into a single one.
* The delimiter takes into account that the last line of a statement may be a single-line-comment. */
public static final String DELIMITER = "\n;\n";

private List<UpdateElt> updateOperations = new ArrayList<>();
private List<UpdateElt> updateOperationsView = Collections.unmodifiableList(updateOperations);
private boolean isParsed = true; // True iff there are no strings in updateOperations

public boolean isParsed() {
return isParsed;
}

public void add(UpdateElt updateElt) {
isParsed = isParsed && updateElt.isParsed();
updateOperations.add(updateElt);
}

public void add(Update update) {
add(new UpdateElt(update));
}

/** Add a string by parsing it. */
public void add(String updateRequestString) {
UpdateRequest updateRequest = UpdateFactory.create(updateRequestString);
add(updateRequest);
}

public void add(UpdateRequest updateRequest) {
updateRequest.getOperations().forEach(this::add);
}

/** Add a string without parsing it. */
public void addString(String updateRequestString) {
add(new UpdateElt(updateRequestString));
}

/** Attempt to build an UpdateRequest from the state of this accumulator. Attempts to parse any string elements. */
public UpdateRequest buildUpdateRequest() {
return addToUpdateRequest(new UpdateRequest());
}

public UpdateRequest addToUpdateRequest(UpdateRequest updateRequest) {
for (UpdateElt elt : updateOperations) {
if (elt.isParsed()) {
updateRequest.add(elt.update());
} else {
try {
updateRequest.add(elt.updateString());
} catch (Exception e) {
// Expose the string that failed to parse
e.addSuppressed(new RuntimeException("Failed to parse: " + elt.updateString()));
throw e;
}
}
}
return updateRequest;
}

public void clear() {
updateOperations.clear();
isParsed = true;
}

public boolean isEmpty() {
return updateOperations.isEmpty();
}

@Override
public Iterator<UpdateElt> iterator() {
return updateOperationsView.iterator();
}

public String buildString() {
return updateOperations.stream()
.map(UpdateElt::toString)
.collect(Collectors.joining(DELIMITER));
}
}

static { JenaSystem.init(); }

protected String serviceURL;
protected boolean parseCheck = true;
protected Optional<Boolean> parseCheck = Optional.empty();
private UpdateEltAcc updateEltAcc = new UpdateEltAcc();

protected Params params = Params.create();
Expand Down Expand Up @@ -173,7 +77,7 @@ public Y update(UpdateRequest updateRequest) {

public Y update(String updateRequestString) {
Objects.requireNonNull(updateRequestString);
if (parseCheck) {
if (effectiveParseCheck()) {
updateEltAcc.add(updateRequestString);
} else {
updateEltAcc.addString(updateRequestString);
Expand Down Expand Up @@ -201,10 +105,14 @@ public Y updateString(String updateString) {
}

public Y parseCheck(boolean parseCheck) {
this.parseCheck = parseCheck;
this.parseCheck = Optional.of(parseCheck);
return thisBuilder();
}

protected boolean effectiveParseCheck() {
return SparqlDispatcherRegistry.effectiveParseCheck(parseCheck, contextAcc);
}

public Y substitution(Binding binding) {
binding.forEach(this.substitutionMap::put);
return thisBuilder();
Expand Down
38 changes: 38 additions & 0 deletions jena-arq/src/main/java/org/apache/jena/http/sys/UpdateElt.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* 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.http.sys;

import java.util.Objects;

import org.apache.jena.update.Update;
import org.apache.jena.update.UpdateRequest;

/** Update element. Either an Update object or a string. */
record UpdateElt(Update update, String updateString) {
UpdateElt(Update update) { this(Objects.requireNonNull(update), null); }
UpdateElt(String updateString) { this(null, Objects.requireNonNull(updateString)); }
boolean isParsed() { return update != null; }

@Override
public String toString() {
return isParsed()
? new UpdateRequest(update()).toString() // Reuse UpdateRequest's serialization approach
: updateString();
}
}
110 changes: 110 additions & 0 deletions jena-arq/src/main/java/org/apache/jena/http/sys/UpdateEltAcc.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
/*
* 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.http.sys;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.stream.Collectors;

import org.apache.jena.update.Update;
import org.apache.jena.update.UpdateFactory;
import org.apache.jena.update.UpdateRequest;

/** Accumulator for update elements. Can build an overall string or UpdateRequest from the elements. */
public class UpdateEltAcc implements Iterable<UpdateElt> {
/** Delimiter for joining multiple SPARQL update strings into a single one.
* The delimiter takes into account that the last line of a statement may be a single-line-comment. */
public static final String DELIMITER = "\n;\n";

private List<UpdateElt> updateOperations = new ArrayList<>();
private List<UpdateElt> updateOperationsView = Collections.unmodifiableList(updateOperations);
private boolean isParsed = true; // True iff there are no strings in updateOperations

public boolean isParsed() {
return isParsed;
}

public void add(UpdateElt updateElt) {
isParsed = isParsed && updateElt.isParsed();
updateOperations.add(updateElt);
}

public void add(Update update) {
add(new UpdateElt(update));
}

/** Add a string by parsing it. */
public void add(String updateRequestString) {
UpdateRequest updateRequest = UpdateFactory.create(updateRequestString);
add(updateRequest);
}

public void add(UpdateRequest updateRequest) {
updateRequest.getOperations().forEach(this::add);
}

/** Add a string without parsing it. */
public void addString(String updateRequestString) {
add(new UpdateElt(updateRequestString));
}

/** Attempt to build an UpdateRequest from the state of this accumulator. Attempts to parse any string elements. */
public UpdateRequest buildUpdateRequest() {
return addToUpdateRequest(new UpdateRequest());
}

public UpdateRequest addToUpdateRequest(UpdateRequest updateRequest) {
for (UpdateElt elt : updateOperations) {
if (elt.isParsed()) {
updateRequest.add(elt.update());
} else {
try {
updateRequest.add(elt.updateString());
} catch (Exception e) {
// Expose the string that failed to parse
e.addSuppressed(new RuntimeException("Failed to parse: " + elt.updateString()));
throw e;
}
}
}
return updateRequest;
}

public void clear() {
updateOperations.clear();
isParsed = true;
}

public boolean isEmpty() {
return updateOperations.isEmpty();
}

@Override
public Iterator<UpdateElt> iterator() {
return updateOperationsView.iterator();
}

public String buildString() {
return updateOperations.stream()
.map(UpdateElt::toString)
.collect(Collectors.joining(DELIMITER));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,11 @@ public static void sendGraphToStream(Graph graph, StreamRDF stream, String baseU
stream.base(baseURI);
if ( prefixMap != null )
sendPrefixesToStream(prefixMap, stream) ;
sendGraphTriplesToStream(graph, stream);
}

/** Send only the triples of graph to a StreamRDF */
public static void sendGraphTriplesToStream(Graph graph, StreamRDF stream) {
Copy link
Member

@afs afs Aug 14, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This duplictates sendTriplesToStream.

Suggestion - move the triples sending code to sendTriplesToStream, call sendTriplesToStream from sendGraphToStream(graph, stream, base, prefixes) and drop sendGraphToStream(graph, stream).

To me, sendGraphToStream(graph, stream) does imply all the graph is sent - but the prefixes aren't which is why its sendTriplesToStream.

ExtendedIterator<Triple> iter = graph.find(null, null, null) ;
try {
StreamRDFOps.sendTriplesToStream(iter, stream) ;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,12 @@ public class ARQConstants
public static final Symbol registryExtensions =
SystemARQ.allocSymbol("registryExtensions") ;

public static void init() {}
public static final Symbol registrySparqlDispatchers =
SystemARQ.allocSymbol("registrySparqlDispatchers") ;

/** Symbol for disabling parse checks of queries and updates when executing them against a dataset */
public static final Symbol parseCheck =
SystemARQ.allocSymbol("parseCheck") ;

public static void init() {}
}
Loading