This is an automated email from the ASF dual-hosted git repository.
andy pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/jena.git
The following commit(s) were added to refs/heads/main by this push:
new 33d2fa0ff0 GH-3448: Choose HTTP headers for non-parsed sparql queries
based on API usage.
33d2fa0ff0 is described below
commit 33d2fa0ff02cf16c81926e11b1283c59f5b520aa
Author: Claus Stadler <[email protected]>
AuthorDate: Mon Sep 15 22:12:34 2025 +0200
GH-3448: Choose HTTP headers for non-parsed sparql queries based on API
usage.
---
.../org/apache/jena/http/sys/ExecHTTPBuilder.java | 53 ++++++-
.../jena/sparql/exec/http/QueryExecHTTP.java | 102 ++++++++++----
.../sparql/exec/http/QueryExecHTTPBuilder.java | 6 +-
.../exec/http/QueryExecutionHTTPBuilder.java | 6 +-
.../examples/RDFConnectionExampleDBpedia01.java | 55 ++++++++
.../java/org/apache/jena/rdflink/RDFLinkHTTP.java | 156 +++------------------
.../apache/jena/rdflink/RDFLinkHTTPBuilder.java | 1 +
.../jena/rdfconnection/TS_RDFConnection.java | 1 +
.../jena/rdfconnection/TestRDFConnectionHTTP.java | 99 -------------
.../TestRDFConnectionHTTPHeaders.java | 153 ++++++++++++++++++++
.../java/org/apache/jena/rdflink/TS_RDFLink.java | 1 +
.../jena/rdflink/TestRDFLinkHTTPHeaders.java | 97 +++++++++++++
12 files changed, 467 insertions(+), 263 deletions(-)
diff --git
a/jena-arq/src/main/java/org/apache/jena/http/sys/ExecHTTPBuilder.java
b/jena-arq/src/main/java/org/apache/jena/http/sys/ExecHTTPBuilder.java
index a7b3f6c471..c62c468534 100644
--- a/jena-arq/src/main/java/org/apache/jena/http/sys/ExecHTTPBuilder.java
+++ b/jena-arq/src/main/java/org/apache/jena/http/sys/ExecHTTPBuilder.java
@@ -25,6 +25,8 @@ import java.util.concurrent.TimeUnit;
import org.apache.jena.graph.Node;
import org.apache.jena.http.HttpEnv;
import org.apache.jena.query.*;
+import org.apache.jena.riot.WebContent;
+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.exec.http.Params;
@@ -50,8 +52,15 @@ public abstract class ExecHTTPBuilder<X, Y> {
protected Params params = Params.create();
private ContextAccumulator contextAcc =
ContextAccumulator.newBuilder(()->ARQ.getContext());
- // Accept choice by the application
- protected String appAcceptHeader = null;
+ // Accept choice by the application. Deprecated - Superseded by
acceptHeader(String) which sets all header fields explicitly.
+ @Deprecated(forRemoval = true)
+ protected String appAcceptHeader = null;
+
+ protected String selectAcceptHeader =
WebContent.defaultSparqlResultsHeader;
+ protected String askAcceptHeader = WebContent.defaultSparqlAskHeader;
+ protected String graphAcceptHeader = WebContent.defaultGraphAcceptHeader;
+ protected String datasetAcceptHeader =
WebContent.defaultDatasetAcceptHeader;
+
protected long timeout = -1;
protected TimeUnit timeoutUnit = null;
@@ -253,22 +262,58 @@ public abstract class ExecHTTPBuilder<X, Y> {
return thisBuilder();
}
+ /** Setting this header overrides any other header. */
public Y acceptHeader(String acceptHeader) {
Objects.requireNonNull(acceptHeader);
this.appAcceptHeader = acceptHeader;
+ this.selectAcceptHeader = acceptHeader;
+ this.askAcceptHeader = acceptHeader;
+ this.graphAcceptHeader = acceptHeader;
+ this.datasetAcceptHeader = acceptHeader;
+ return thisBuilder();
+ }
+
+ /** Set the HTTP {@code Accept:} header used to when making a SPARQL
Protocol SELECT query. */
+ public Y acceptHeaderSelectQuery(String acceptSelectHeader) {
+ this.selectAcceptHeader = acceptSelectHeader;
+ return thisBuilder();
+ }
+
+ /** Set the HTTP {@code Accept:} header used to when making a SPARQL
Protocol ASK query. */
+ public Y acceptHeaderAskQuery(String acceptAskHeader) {
+ this.askAcceptHeader = acceptAskHeader;
+ return thisBuilder();
+ }
+
+ /** Set the HTTP {@code Accept:} header used to fetch RDF graph using the
SPARQL CONSTRUCT and DESCRIBE query types. */
+ public Y acceptHeaderGraph(String acceptGraph) {
+ this.graphAcceptHeader = acceptGraph;
+ return thisBuilder();
+ }
+
+ /** Set the HTTP {@code Accept:} header used to when making a SPARQL
Protocol CONSTRUCT dataset query.
+ * This is a Jena extension. */
+ public Y acceptHeaderDataset(String acceptDataset) {
+ this.datasetAcceptHeader = acceptDataset;
return thisBuilder();
}
public Y httpHeader(String headerName, String headerValue) {
Objects.requireNonNull(headerName);
Objects.requireNonNull(headerValue);
- this.httpHeaders.put(headerName, headerValue);
+
+ // Special handling of an Accept-Header.
+ if (headerName.equals(HttpNames.hAccept)) {
+ acceptHeader(headerValue);
+ } else {
+ this.httpHeaders.put(headerName, headerValue);
+ }
return thisBuilder();
}
public Y httpHeaders(Map<String, String> headers) {
Objects.requireNonNull(headers);
- this.httpHeaders.putAll(headers);
+ headers.forEach(this::httpHeader);
return thisBuilder();
}
diff --git
a/jena-arq/src/main/java/org/apache/jena/sparql/exec/http/QueryExecHTTP.java
b/jena-arq/src/main/java/org/apache/jena/sparql/exec/http/QueryExecHTTP.java
index 9a1d52202d..953819a18b 100644
--- a/jena-arq/src/main/java/org/apache/jena/sparql/exec/http/QueryExecHTTP.java
+++ b/jena-arq/src/main/java/org/apache/jena/sparql/exec/http/QueryExecHTTP.java
@@ -100,15 +100,14 @@ public class QueryExecHTTP implements QueryExec {
private long readTimeout = -1;
private TimeUnit readTimeoutUnit = TimeUnit.MILLISECONDS;
- // Content Types: these list the standard formats and also include */*.
- private final String selectAcceptheader =
WebContent.defaultSparqlResultsHeader;
- private final String askAcceptHeader =
WebContent.defaultSparqlAskHeader;
- private final String describeAcceptHeader =
WebContent.defaultGraphAcceptHeader;
- private final String constructAcceptHeader =
WebContent.defaultGraphAcceptHeader;
- private final String datasetAcceptHeader =
WebContent.defaultDatasetAcceptHeader;
+ private final String selectAcceptHeader;
+ private final String askAcceptHeader;
+ private final String graphAcceptHeader;
+ private final String datasetAcceptHeader;
// If this is non-null, it overrides the use of any Content-Type above.
- private String appProvidedAcceptHeader = null;
+ @Deprecated(forRemoval = true) // Deprecated in favor of setting the other
header fields.
+ private String overrideAcceptHeader = null;
// Received content type
private String httpResponseContentType = null;
@@ -119,10 +118,45 @@ public class QueryExecHTTP implements QueryExec {
private HttpClient httpClient = HttpEnv.getDftHttpClient();
private Map<String, String> httpHeaders;
+ /**
+ * This constructor is superseded by the other one which has more
parameters.
+ * The recommended way to create instances of this class is via {@link
QueryExecHTTPBuilder}.
+ */
+ @Deprecated(forRemoval = true)
public QueryExecHTTP(String serviceURL, Query query, String queryString,
int urlLimit,
+ HttpClient httpClient, Map<String, String> httpHeaders, Params
params, Context context,
+ List<String> defaultGraphURIs, List<String> namedGraphURIs,
+ QuerySendMode sendMode, String overrideAcceptHeader,
+ long timeout, TimeUnit timeoutUnit) {
+ // Content Types: these list the standard formats and also include */*
+ this(serviceURL, query, queryString, urlLimit,
+ httpClient, httpHeaders, params, context,
+ defaultGraphURIs, namedGraphURIs,
+ sendMode,
+ dft(overrideAcceptHeader,
WebContent.defaultSparqlResultsHeader),
+ dft(overrideAcceptHeader, WebContent.defaultSparqlAskHeader),
+ dft(overrideAcceptHeader, WebContent.defaultGraphAcceptHeader),
+ dft(overrideAcceptHeader,
WebContent.defaultDatasetAcceptHeader),
+ timeout, timeoutUnit);
+
+ // Handling of legacy overrideAcceptHeader.
+ this.overrideAcceptHeader = overrideAcceptHeader;
+ // Important - handled as special case because the defaults vary by
query type.
+ if ( httpHeaders.containsKey(HttpNames.hAccept) ) {
+ if ( this.overrideAcceptHeader != null ) {
+ String acceptHeader = httpHeaders.get(HttpNames.hAccept);
+ this.overrideAcceptHeader = acceptHeader;
+ }
+ this.httpHeaders.remove(HttpNames.hAccept);
+ }
+ }
+
+ protected QueryExecHTTP(String serviceURL, Query query, String
queryString, int urlLimit,
HttpClient httpClient, Map<String, String>
httpHeaders, Params params, Context context,
List<String> defaultGraphURIs, List<String>
namedGraphURIs,
- QuerySendMode sendMode, String explicitAcceptHeader,
+ QuerySendMode sendMode,
+ String selectAcceptHeader, String askAcceptHeader,
+ String graphAcceptHeader, String datasetAcceptHeader,
long timeout, TimeUnit timeoutUnit) {
this.context = ( context == null ) ? ARQ.getContext().copy() :
context.copy();
this.service = serviceURL;
@@ -133,13 +167,10 @@ public class QueryExecHTTP implements QueryExec {
this.defaultGraphURIs = defaultGraphURIs;
this.namedGraphURIs = namedGraphURIs;
this.sendMode = Objects.requireNonNull(sendMode);
- this.appProvidedAcceptHeader = explicitAcceptHeader;
- // Important - handled as special case because the defaults vary by
query type.
- if ( httpHeaders.containsKey(HttpNames.hAccept) ) {
- if ( this.appProvidedAcceptHeader != null )
- this.appProvidedAcceptHeader =
httpHeaders.get(HttpNames.hAccept);
- this.httpHeaders.remove(HttpNames.hAccept);
- }
+ this.selectAcceptHeader = selectAcceptHeader;
+ this.askAcceptHeader = askAcceptHeader;
+ this.graphAcceptHeader = graphAcceptHeader;
+ this.datasetAcceptHeader = datasetAcceptHeader;
this.httpHeaders = httpHeaders;
this.params = params;
this.readTimeout = timeout;
@@ -147,9 +178,30 @@ public class QueryExecHTTP implements QueryExec {
this.httpClient = HttpLib.dft(httpClient, HttpEnv.getDftHttpClient());
}
- /** Getter for the appProvidedAcceptHeader. Only used for testing. */
+ public String getAcceptHeaderSelect() {
+ return selectAcceptHeader;
+ }
+
+ public String getAcceptHeaderAsk() {
+ return askAcceptHeader;
+ }
+
+ public String getAcceptHeaderDescribe() {
+ return graphAcceptHeader;
+ }
+
+ public String getAcceptHeaderConstructGraph() {
+ return graphAcceptHeader;
+ }
+
+ public String getAcceptHeaderConstructDataset() {
+ return datasetAcceptHeader;
+ }
+
+ /** Getter for the override accept header. Only used for testing. */
+ @Deprecated(forRemoval = true)
public String getAppProvidedAcceptHeader() {
- return appProvidedAcceptHeader;
+ return overrideAcceptHeader;
}
/** The Content-Type response header received (null before the remote
operation is attempted). */
@@ -167,7 +219,7 @@ public class QueryExecHTTP implements QueryExec {
private RowSet execRowSet() {
// Use the explicitly given header or the default selectAcceptheader
- String thisAcceptHeader = dft(appProvidedAcceptHeader,
selectAcceptheader);
+ String thisAcceptHeader = dft(overrideAcceptHeader,
selectAcceptHeader);
HttpRequest request = effectiveHttpRequest(thisAcceptHeader);
HttpResponse<InputStream> response = executeQuery(request);
@@ -214,7 +266,7 @@ public class QueryExecHTTP implements QueryExec {
public boolean ask() {
checkNotClosed();
check(QueryType.ASK);
- String thisAcceptHeader = dft(appProvidedAcceptHeader,
askAcceptHeader);
+ String thisAcceptHeader = dft(overrideAcceptHeader, askAcceptHeader);
HttpRequest request = effectiveHttpRequest(thisAcceptHeader);
HttpResponse<InputStream> response = executeQuery(request);
InputStream in = HttpLib.getInputStream(response);
@@ -262,14 +314,14 @@ public class QueryExecHTTP implements QueryExec {
public Graph construct(Graph graph) {
checkNotClosed();
check(QueryType.CONSTRUCT);
- return execGraph(graph, constructAcceptHeader);
+ return execGraph(graph, graphAcceptHeader);
}
@Override
public Iterator<Triple> constructTriples() {
checkNotClosed();
check(QueryType.CONSTRUCT);
- return execTriples(constructAcceptHeader);
+ return execTriples(graphAcceptHeader);
}
@Override
@@ -295,13 +347,13 @@ public class QueryExecHTTP implements QueryExec {
public Graph describe(Graph graph) {
checkNotClosed();
check(QueryType.DESCRIBE);
- return execGraph(graph, describeAcceptHeader);
+ return execGraph(graph, graphAcceptHeader);
}
@Override
public Iterator<Triple> describeTriples() {
checkNotClosed();
- return execTriples(describeAcceptHeader);
+ return execTriples(graphAcceptHeader);
}
private Graph execGraph(Graph graph, String acceptHeader) {
@@ -354,7 +406,7 @@ public class QueryExecHTTP implements QueryExec {
// ifNoContentType - some wild guess at the content type.
private Pair<InputStream, Lang> execRdfWorker(String contentType, String
ifNoContentType) {
checkNotClosed();
- String thisAcceptHeader = dft(appProvidedAcceptHeader, contentType);
+ String thisAcceptHeader = dft(overrideAcceptHeader, contentType);
HttpRequest request = effectiveHttpRequest(thisAcceptHeader);
HttpResponse<InputStream> response = executeQuery(request);
InputStream in = HttpLib.getInputStream(response);
@@ -382,7 +434,7 @@ public class QueryExecHTTP implements QueryExec {
public JsonArray execJson() {
checkNotClosed();
check(QueryType.CONSTRUCT_JSON);
- String thisAcceptHeader = dft(appProvidedAcceptHeader,
WebContent.contentTypeJSON);
+ String thisAcceptHeader = dft(overrideAcceptHeader,
WebContent.contentTypeJSON);
HttpRequest request = effectiveHttpRequest(thisAcceptHeader);
HttpResponse<InputStream> response = executeQuery(request);
InputStream in = HttpLib.getInputStream(response);
diff --git
a/jena-arq/src/main/java/org/apache/jena/sparql/exec/http/QueryExecHTTPBuilder.java
b/jena-arq/src/main/java/org/apache/jena/sparql/exec/http/QueryExecHTTPBuilder.java
index d861b7f5b5..86f0bba7e8 100644
---
a/jena-arq/src/main/java/org/apache/jena/sparql/exec/http/QueryExecHTTPBuilder.java
+++
b/jena-arq/src/main/java/org/apache/jena/sparql/exec/http/QueryExecHTTPBuilder.java
@@ -49,7 +49,11 @@ public class QueryExecHTTPBuilder extends
ExecHTTPBuilder<QueryExecHTTP, QueryEx
hClient, new HashMap<>(httpHeaders),
Params.create(params), cxt,
copyArray(defaultGraphURIs),
copyArray(namedGraphURIs),
- sendMode, appAcceptHeader,
+ sendMode,
+ selectAcceptHeader,
+ askAcceptHeader,
+ graphAcceptHeader,
+ datasetAcceptHeader,
timeout, timeoutUnit);
}
diff --git
a/jena-arq/src/main/java/org/apache/jena/sparql/exec/http/QueryExecutionHTTPBuilder.java
b/jena-arq/src/main/java/org/apache/jena/sparql/exec/http/QueryExecutionHTTPBuilder.java
index e962491291..fa8cc473c0 100644
---
a/jena-arq/src/main/java/org/apache/jena/sparql/exec/http/QueryExecutionHTTPBuilder.java
+++
b/jena-arq/src/main/java/org/apache/jena/sparql/exec/http/QueryExecutionHTTPBuilder.java
@@ -53,7 +53,11 @@ public class QueryExecutionHTTPBuilder
QueryExecHTTP qExec = new QueryExecHTTP(serviceURL, queryActual,
queryStringActual, urlLimit,
hClient, new
HashMap<>(httpHeaders), Params.create(params), cxt,
copyArray(defaultGraphURIs),
copyArray(namedGraphURIs),
- sendMode, appAcceptHeader,
+ sendMode,
+ selectAcceptHeader,
+ askAcceptHeader,
+ graphAcceptHeader,
+ datasetAcceptHeader,
timeout, timeoutUnit);
return new QueryExecutionHTTP(qExec);
}
diff --git
a/jena-examples/src/main/java/rdfconnection/examples/RDFConnectionExampleDBpedia01.java
b/jena-examples/src/main/java/rdfconnection/examples/RDFConnectionExampleDBpedia01.java
new file mode 100644
index 0000000000..d587fec47c
--- /dev/null
+++
b/jena-examples/src/main/java/rdfconnection/examples/RDFConnectionExampleDBpedia01.java
@@ -0,0 +1,55 @@
+package rdfconnection.examples;
+
+import java.util.List;
+
+import org.apache.jena.query.QueryExecution;
+import org.apache.jena.query.ResultSet;
+import org.apache.jena.query.ResultSetFormatter;
+import org.apache.jena.rdfconnection.RDFConnection;
+import org.apache.jena.rdfconnection.RDFConnectionRemote;
+import org.apache.jena.riot.WebContent;
+import org.apache.jena.sparql.resultset.ResultsFormat;
+
+/**
+ * Example that showcases querying DBpedia with disabled parse check and
+ * different accept headers.
+ * <p>
+ *
+ * The expected output should be similar to this snippet:
+ * <pre>
+ * Trying to query with content type: application/sparql-results+thrift
+ * Request failed: Not Acceptable
+ *
+ * Trying to query with content type: application/sparql-results+json
+ * -------------------------
+ * | l |
+ * =========================
+ * | "Jena (Framework)"@de |
+ * -------------------------
+ * </pre>
+ */
+public class RDFConnectionExampleDBpedia01 {
+ public static void main(String[] args) {
+ List<String> acceptHeaders =
List.of(WebContent.contentTypeResultsThrift, WebContent.contentTypeResultsJSON);
+
+ // Note that the query string uses the prefix 'rdfs:' without
declaring it.
+ // The DBpedia server can parse such a query against its configured
default prefixes.
+ String queryString = "SELECT * {
<http://dbpedia.org/resource/Apache_Jena> rdfs:label ?l } ORDER BY ?l LIMIT 1";
+
+ for (String acceptHeader : acceptHeaders) {
+ System.out.println("Trying to query with content type: " +
acceptHeader);
+ try (RDFConnection conn =
RDFConnectionRemote.service("http://dbpedia.org/sparql")
+
.acceptHeaderSelectQuery(acceptHeader).parseCheckSPARQL(false).build()) {
+ try (QueryExecution qe = conn.query(queryString)) {
+ ResultSet rs = qe.execSelect();
+ ResultSetFormatter.output(System.out, rs,
ResultsFormat.FMT_TEXT);
+ } catch (Exception e) {
+ System.out.println("Request failed: " + e.getMessage());
+ }
+ }
+ System.out.println();
+ }
+
+ System.out.println("Done.");
+ }
+}
diff --git
a/jena-rdfconnection/src/main/java/org/apache/jena/rdflink/RDFLinkHTTP.java
b/jena-rdfconnection/src/main/java/org/apache/jena/rdflink/RDFLinkHTTP.java
index 2a7006dc8f..b4edd28ece 100644
--- a/jena-rdfconnection/src/main/java/org/apache/jena/rdflink/RDFLinkHTTP.java
+++ b/jena-rdfconnection/src/main/java/org/apache/jena/rdflink/RDFLinkHTTP.java
@@ -26,10 +26,9 @@ import org.apache.jena.atlas.lib.InternalErrorException;
import org.apache.jena.graph.Graph;
import org.apache.jena.graph.Node;
import org.apache.jena.http.HttpEnv;
+import org.apache.jena.http.HttpLib;
import org.apache.jena.query.*;
-import org.apache.jena.rdfconnection.JenaConnectionException;
import org.apache.jena.riot.RDFFormat;
-import org.apache.jena.riot.WebContent;
import org.apache.jena.sparql.ARQException;
import org.apache.jena.sparql.core.DatasetGraph;
import org.apache.jena.sparql.core.Transactional;
@@ -43,7 +42,6 @@ import org.apache.jena.sparql.exec.http.QueryExecHTTPBuilder;
import org.apache.jena.sparql.exec.http.QuerySendMode;
import org.apache.jena.sparql.exec.http.UpdateExecHTTPBuilder;
import org.apache.jena.sparql.exec.http.UpdateSendMode;
-import org.apache.jena.sparql.util.Context;
import org.apache.jena.system.Txn;
import org.apache.jena.update.UpdateFactory;
import org.apache.jena.update.UpdateRequest;
@@ -74,7 +72,8 @@ public class RDFLinkHTTP implements RDFLink {
protected final String acceptDataset;
protected final String acceptSelectResult;
protected final String acceptAskResult;
- // All purpose SPARQL results header used if above specific cases do not
apply.
+
+ // Fallback all purpose SPARQL results header used if above specific cases
do not apply.
protected final String acceptSparqlResults;
// Whether to check SPARQL queries given as strings by parsing them.
@@ -107,7 +106,7 @@ public class RDFLinkHTTP implements RDFLink {
protected RDFLinkHTTP(Transactional txnLifecycle, HttpClient httpClient,
String destination,
String queryURL, String updateURL, String gspURL,
RDFFormat outputQuads, RDFFormat outputTriples,
String acceptDataset, String acceptGraph,
- String acceptSparqlResults,
+ String acceptSparqlResultsFallback,
String acceptSelectResult, String acceptAskResult,
boolean parseCheckQueries, boolean parseCheckUpdates,
QuerySendMode querySendMode, UpdateSendMode
updateSendMode) {
@@ -126,7 +125,7 @@ public class RDFLinkHTTP implements RDFLink {
this.outputTriples = outputTriples;
this.acceptDataset = acceptDataset;
this.acceptGraph = acceptGraph;
- this.acceptSparqlResults = acceptSparqlResults;
+ this.acceptSparqlResults = acceptSparqlResultsFallback;
this.acceptSelectResult = acceptSelectResult;
this.acceptAskResult = acceptAskResult;
this.parseCheckQueries = parseCheckQueries;
@@ -173,7 +172,7 @@ public class RDFLinkHTTP implements RDFLink {
@Override
public void queryRowSet(String queryString, Consumer<RowSet> rowSetAction)
{
Txn.executeRead(this, ()->{
- try ( QueryExec qExec = query(queryString, QueryType.SELECT) ) {
+ try ( QueryExec qExec = query(queryString) ) {
RowSet rs = qExec.select();
rowSetAction.accept(rs);
}
@@ -188,7 +187,7 @@ public class RDFLinkHTTP implements RDFLink {
@Override
public void querySelect(String queryString, Consumer<Binding> rowAction) {
Txn.executeRead(this, ()->{
- try ( QueryExec qExec = query(queryString, QueryType.SELECT) ) {
+ try ( QueryExec qExec = query(queryString) ) {
qExec.select().forEachRemaining(rowAction);
}
} );
@@ -199,7 +198,7 @@ public class RDFLinkHTTP implements RDFLink {
public Graph queryConstruct(String queryString) {
return
Txn.calculateRead(this, ()->{
- try ( QueryExec qExec = query(queryString,
QueryType.CONSTRUCT) ) {
+ try ( QueryExec qExec = query(queryString) ) {
return qExec.construct();
}
} );
@@ -210,7 +209,7 @@ public class RDFLinkHTTP implements RDFLink {
public Graph queryDescribe(String queryString) {
return
Txn.calculateRead(this, ()->{
- try ( QueryExec qExec = query(queryString, QueryType.DESCRIBE)
) {
+ try ( QueryExec qExec = query(queryString) ) {
return qExec.describe();
}
} );
@@ -221,33 +220,22 @@ public class RDFLinkHTTP implements RDFLink {
public boolean queryAsk(String queryString) {
return
Txn.calculateRead(this, ()->{
- try ( QueryExec qExec = query(queryString, QueryType.ASK) ) {
+ try ( QueryExec qExec = query(queryString) ) {
return qExec.ask();
}
} );
}
- /**
- * Operation that passed down the query type so the accept header can be
set without parsing the query string.
- * @param queryString
- * @param queryType
- * @return QueryExecution
- */
- protected QueryExec query(String queryString, QueryType queryType) {
- Objects.requireNonNull(queryString);
- return queryExec(null, queryString, queryType);
- }
-
@Override
public QueryExec query(String queryString) {
Objects.requireNonNull(queryString);
- return queryExec(null, queryString, null);
+ return queryExec(null, queryString);
}
@Override
public QueryExec query(Query query) {
Objects.requireNonNull(query);
- return queryExec(query, null, null);
+ return queryExec(query, null);
}
@Override
@@ -255,11 +243,11 @@ public class RDFLinkHTTP implements RDFLink {
return createQExecBuilder();
}
- /** Create the QExec initialized with a query object or string. */
- private QueryExec queryExec(Query query, String queryString, QueryType
queryType) {
- QueryExecHTTPBuilderOverRDFLinkHTTP builder = createQExecBuilder();
+ /** Create the QExec initialized with a query object or string. Only one
argument is non-null. */
+ private QueryExec queryExec(Query query, String queryString) {
+ QueryExecHTTPBuilder builder = createQExecBuilder();
if (queryString != null) {
- builder.queryStringValidated(queryString,
Syntax.defaultQuerySyntax, queryType);
+ builder.query(queryString);
}
if (query != null) {
builder.query(query);
@@ -267,117 +255,19 @@ public class RDFLinkHTTP implements RDFLink {
return QueryExecApp.create(builder, null, query, queryString);
}
- /**
- * An internal subclass of {@link QueryExecHTTPBuilder} that overrides
- * {@link #buildX(HttpClient, Query, String, Context)}
- * in order to have the accept header field derived based on this {@link
RDFLinkHTTP} configuration.
- */
- /* package */ class QueryExecHTTPBuilderOverRDFLinkHTTP
- extends QueryExecHTTPBuilder
- {
- /** The query type. Never null. */
- protected QueryType queryType = QueryType.UNKNOWN;
-
- /** The parsed query is only needed for setting the appropriate HTTP
header for construct quad queries. */
- protected Query parsedQuery = null;
-
- protected QueryExecHTTPBuilderOverRDFLinkHTTP() {
- super();
- }
-
- /** This method wraps {@link #queryString(String)} and sets the
additional attributes without further interpretation. */
- protected QueryExecHTTPBuilder queryString(String queryString,
QueryType queryType, Query parsedQuery) {
- super.queryString(queryString);
- this.queryType = queryType != null ? queryType : QueryType.UNKNOWN;
- this.parsedQuery = parsedQuery;
- return thisBuilder();
- }
-
- /** {@inheritDoc} */
- @Override
- public QueryExecHTTPBuilder queryString(String queryString) {
- return queryString(queryString, null, null);
- }
-
- /** This method is far only called from RDFLinkHTTP. It validates the
query string if parseCheckQueries is enabled. */
- protected QueryExecHTTPBuilder queryStringValidated(String
queryString, Syntax syntax, QueryType fallbackQueryType) {
- Query parsedQuery = parseCheck
- ? QueryFactory.create(queryString, syntax)
- : null;
-
- QueryType finalQueryType = parsedQuery != null ?
parsedQuery.queryType() : fallbackQueryType;
- return queryString(queryString, finalQueryType, parsedQuery);
- }
-
- @Override
- protected void setQuery(Query query, String queryStr) {
- super.setQuery(query, queryStr);
- parsedQuery = query;
- queryType = query == null ? QueryType.UNKNOWN : query.queryType();
- }
-
- @Override
- protected QueryExecHTTP buildX(HttpClient hClient, Query queryActual,
String queryStringActual, Context cxt) {
- // If the appAcceptHeader has not been explicitly set then derive
it.
- if (appAcceptHeader == null) {
- String requestAcceptHeader = null;
- // Use the most specific method.
- switch(queryType) {
- case SELECT :
- if ( acceptSelectResult != null )
- requestAcceptHeader =
RDFLinkHTTP.this.acceptSelectResult;
- break;
- case ASK :
- if ( acceptAskResult != null )
- requestAcceptHeader =
RDFLinkHTTP.this.acceptAskResult;
- break;
- case DESCRIBE :
- case CONSTRUCT :
- // Best effort to handle construct quads. Requires a
parsed query.
- if (parsedQuery != null &&
parsedQuery.isConstructQuad()) {
- if ( acceptDataset != null )
- requestAcceptHeader =
RDFLinkHTTP.this.acceptDataset;
- } else {
- if ( acceptGraph != null )
- requestAcceptHeader =
RDFLinkHTTP.this.acceptGraph;
- }
- break;
- case CONSTRUCT_JSON :
- requestAcceptHeader = WebContent.contentTypeJSON;
- break;
- case UNKNOWN :
- // All-purpose content type.
- if ( acceptSparqlResults != null ) {
- requestAcceptHeader =
RDFLinkHTTP.this.acceptSparqlResults;
- } else {
- // No idea! Set an "anything" and hope.
- // (Reasonable chance this is going to end up as
HTML though.)
- requestAcceptHeader = "*/*";
- }
- break;
- default :
- break;
- }
- // Make sure it was set somehow.
- if ( requestAcceptHeader == null )
- throw new JenaConnectionException("No Accept header");
-
- this.acceptHeader(requestAcceptHeader);
- }
-
- return super.buildX(hClient, queryActual, queryStringActual, cxt);
- }
- }
-
/**
* Create a builder, configured with the link setup.
*
* @param presetQueryType If non-null then the builder will force
execution with this query type.
*/
- private QueryExecHTTPBuilderOverRDFLinkHTTP createQExecBuilder() {
+ private QueryExecHTTPBuilder createQExecBuilder() {
checkQuery();
- QueryExecHTTPBuilderOverRDFLinkHTTP builder = new
QueryExecHTTPBuilderOverRDFLinkHTTP();
-
builder.endpoint(svcQuery).httpClient(httpClient).sendMode(querySendMode).parseCheck(parseCheckQueries);
+ QueryExecHTTPBuilder builder = QueryExecHTTP.newBuilder();
+
builder.endpoint(svcQuery).httpClient(httpClient).sendMode(querySendMode).parseCheck(parseCheckQueries)
+ .acceptHeaderSelectQuery(HttpLib.dft(acceptSelectResult,
acceptSparqlResults))
+ .acceptHeaderAskQuery(HttpLib.dft(acceptAskResult,
acceptSparqlResults))
+ .acceptHeaderGraph(HttpLib.dft(acceptGraph, acceptSparqlResults))
+ .acceptHeaderDataset(HttpLib.dft(acceptDataset,
acceptSparqlResults));
return builder;
}
diff --git
a/jena-rdfconnection/src/main/java/org/apache/jena/rdflink/RDFLinkHTTPBuilder.java
b/jena-rdfconnection/src/main/java/org/apache/jena/rdflink/RDFLinkHTTPBuilder.java
index 8db4740a58..2b77cbf862 100644
---
a/jena-rdfconnection/src/main/java/org/apache/jena/rdflink/RDFLinkHTTPBuilder.java
+++
b/jena-rdfconnection/src/main/java/org/apache/jena/rdflink/RDFLinkHTTPBuilder.java
@@ -55,6 +55,7 @@ public class RDFLinkHTTPBuilder {
protected RDFFormat outputQuads = HttpEnv.defaultQuadsFormat;
protected RDFFormat outputTriples = HttpEnv.defaultTriplesFormat;
+ // The acceptGraph header is used for SPARQL CONSTRUCT, DESCRIBE and GSP
GET.
protected String acceptGraph =
WebContent.defaultGraphAcceptHeader;
protected String acceptDataset =
WebContent.defaultDatasetAcceptHeader;
diff --git
a/jena-rdfconnection/src/test/java/org/apache/jena/rdfconnection/TS_RDFConnection.java
b/jena-rdfconnection/src/test/java/org/apache/jena/rdfconnection/TS_RDFConnection.java
index e13aefc42a..629de0d215 100644
---
a/jena-rdfconnection/src/test/java/org/apache/jena/rdfconnection/TS_RDFConnection.java
+++
b/jena-rdfconnection/src/test/java/org/apache/jena/rdfconnection/TS_RDFConnection.java
@@ -29,6 +29,7 @@ import org.junit.platform.suite.api.Suite;
, TestRDFConnectionLocalMRSW.class
, TestLibRDFConn.class
, TestRDFConnectionRewrapping.class
+ , TestRDFConnectionHTTPHeaders.class
})
public class TS_RDFConnection {}
diff --git
a/jena-rdfconnection/src/test/java/org/apache/jena/rdfconnection/TestRDFConnectionHTTP.java
b/jena-rdfconnection/src/test/java/org/apache/jena/rdfconnection/TestRDFConnectionHTTP.java
deleted file mode 100644
index 8f5b7220a0..0000000000
---
a/jena-rdfconnection/src/test/java/org/apache/jena/rdfconnection/TestRDFConnectionHTTP.java
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * 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.rdfconnection;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-
-import org.junit.jupiter.api.Test;
-
-import org.apache.jena.query.Query;
-import org.apache.jena.query.QueryExecution;
-import org.apache.jena.query.QueryFactory;
-import org.apache.jena.riot.WebContent;
-import org.apache.jena.sparql.exec.QueryExec;
-import org.apache.jena.sparql.exec.http.QueryExecHTTP;
-
-public class TestRDFConnectionHTTP {
-
- @Test
- public void test_select_01() {
- doAssert(WebContent.contentTypeXML, "SELECT * { ?s a ?o } LIMIT 10");
- }
-
- @Test
- public void test_ask_01() {
- doAssert(WebContent.contentTypeJSON, "ASK { ?s a ?o }");
- }
-
- @Test
- public void test_constructTriples_01() {
- doAssert(WebContent.contentTypeTurtle, "CONSTRUCT WHERE { ?s a ?o }
LIMIT 10");
- }
-
- @Test
- public void test_constructQuads_01() {
- doAssert(WebContent.contentTypeTriG, "CONSTRUCT WHERE { GRAPH ?g{ ?s a
?o } } LIMIT 10");
- }
-
- @Test
- public void test_describe_01() {
- doAssert(WebContent.contentTypeNTriples, "DESCRIBE <urn:x>");
- }
-
- private static RDFConnectionRemoteBuilder configureHeader(Query query,
String header, RDFConnectionRemoteBuilder builder) {
- return switch (query.queryType()) {
- case SELECT -> builder.acceptHeaderSelectQuery(header);
- case CONSTRUCT -> !query.isConstructQuad()
- ? builder.acceptHeaderGraph(header)
- : builder.acceptHeaderDataset(header);
- case DESCRIBE -> builder.acceptHeaderGraph(header);
- case ASK -> builder.acceptHeaderAskQuery(header);
- default -> throw new UnsupportedOperationException("Unhandled query
type for query: " + query);
- };
- }
-
- /** Test whether the constructed QueryExec instance has the expected HTTP
header set */
- private static void doAssert(String expectedHeader, String queryString) {
- Query query = QueryFactory.create(queryString);
-
- try (RDFConnection conn = configureHeader(query, expectedHeader,
RDFConnectionRemote.newBuilder())
- .queryEndpoint("https://www.example.org/sparql") // Should
never be resolved
- .build()) {
- try (QueryExecution qe = conn.query(queryString)) {
- QueryExecHTTP qeh = (QueryExecHTTP)QueryExec.adapt(qe);
- assertEquals(expectedHeader, qeh.getAppProvidedAcceptHeader());
- }
-
- try (QueryExecution qe =
conn.newQuery().query(queryString).build()) {
- QueryExecHTTP qeh = (QueryExecHTTP)QueryExec.adapt(qe);
- assertEquals(expectedHeader, qeh.getAppProvidedAcceptHeader());
- }
-
- try (QueryExecution qe = conn.query(query)) {
- QueryExecHTTP qeh = (QueryExecHTTP)QueryExec.adapt(qe);
- assertEquals(expectedHeader, qeh.getAppProvidedAcceptHeader());
- }
-
- try (QueryExecution qe = conn.newQuery().query(query).build()) {
- QueryExecHTTP qeh = (QueryExecHTTP)QueryExec.adapt(qe);
- assertEquals(expectedHeader, qeh.getAppProvidedAcceptHeader());
- }
- }
- }
-}
diff --git
a/jena-rdfconnection/src/test/java/org/apache/jena/rdfconnection/TestRDFConnectionHTTPHeaders.java
b/jena-rdfconnection/src/test/java/org/apache/jena/rdfconnection/TestRDFConnectionHTTPHeaders.java
new file mode 100644
index 0000000000..b9e3ddfd56
--- /dev/null
+++
b/jena-rdfconnection/src/test/java/org/apache/jena/rdfconnection/TestRDFConnectionHTTPHeaders.java
@@ -0,0 +1,153 @@
+/*
+ * 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.rdfconnection;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import org.apache.jena.query.QueryExecution;
+import org.apache.jena.sparql.exec.QueryExec;
+import org.apache.jena.sparql.exec.http.QueryExecHTTP;
+import org.apache.jena.sparql.exec.http.QueryExecutionHTTP;
+import org.apache.jena.sparql.exec.http.QueryExecutionHTTPBuilder;
+import org.junit.jupiter.api.Test;
+
+public class TestRDFConnectionHTTPHeaders {
+
+ /**
+ * Test whether connection headers are properly passed on to the query
execution.
+ * No query is actually executed.
+ */
+ @Test void test_headers_non_parsed() {
+ try (RDFConnection conn =
RDFConnectionRemote.service("urn:dummy-service")
+ .parseCheckSPARQL(false)
+ .acceptHeaderSelectQuery("s")
+ .acceptHeaderAskQuery("a")
+ .acceptHeaderGraph("g")
+ .acceptHeaderDataset("d")
+ .build()) {
+
+ try (QueryExecution qExec = conn.query("dummy query string")) {
+ QueryExecHTTP qe = (QueryExecHTTP)QueryExec.adapt(qExec);
+ assertEquals("s", qe.getAcceptHeaderSelect());
+ assertEquals("a", qe.getAcceptHeaderAsk());
+ assertEquals("g", qe.getAcceptHeaderDescribe());
+ assertEquals("g", qe.getAcceptHeaderConstructGraph());
+ assertEquals("d", qe.getAcceptHeaderConstructDataset());
+ }
+ }
+ }
+
+ @Test void test_headers_non_parsed_fallback() {
+ try (RDFConnection conn =
RDFConnectionRemote.service("urn:dummy-service")
+ .parseCheckSPARQL(false)
+ .acceptHeaderQuery("f") // fallback
+ .acceptHeaderSelectQuery(null)
+ .acceptHeaderAskQuery(null)
+ .acceptHeaderGraph(null)
+ .acceptHeaderDataset(null)
+ .build()) {
+
+ try (QueryExecution qExec = conn.query("dummy query string")) {
+ QueryExecHTTP qe = (QueryExecHTTP)QueryExec.adapt(qExec);
+ assertEquals("f", qe.getAcceptHeaderSelect());
+ assertEquals("f", qe.getAcceptHeaderAsk());
+ assertEquals("f", qe.getAcceptHeaderDescribe());
+ assertEquals("f", qe.getAcceptHeaderConstructGraph());
+ assertEquals("f", qe.getAcceptHeaderConstructDataset());
+ }
+ }
+ }
+
+ @Test void test_headers_parsed_fallback() {
+ try (RDFConnection conn =
RDFConnectionRemote.service("urn:dummy-service")
+ .acceptHeaderQuery("f") // fallback
+ .acceptHeaderSelectQuery(null)
+ .acceptHeaderAskQuery(null)
+ .acceptHeaderGraph(null)
+ .acceptHeaderDataset(null)
+ .build()) {
+
+ try (QueryExecution qExec = conn.newQuery()
+ .query("SELECT * { ?s ?p ?o }")
+ .build()) {
+ QueryExecHTTP qe = (QueryExecHTTP)QueryExec.adapt(qExec);
+ assertEquals("f", qe.getAcceptHeaderSelect());
+
+ assertEquals("f", qe.getAcceptHeaderAsk());
+ assertEquals("f", qe.getAcceptHeaderDescribe());
+ assertEquals("f", qe.getAcceptHeaderConstructGraph());
+ assertEquals("f", qe.getAcceptHeaderConstructDataset());
+ }
+ }
+ }
+
+ /**
+ * Setting an override-header on the builder should set all
+ * headers on the QueryExecHTTP instance to that override.
+ */
+ @Test
+ public void test_override_header_01() {
+ try (QueryExecutionHTTP qExec = QueryExecutionHTTPBuilder.create()
+ .endpoint("urn:dummy-service")
+ .queryString("SELECT * { ?s ?p ?o }")
+ .acceptHeader("o") // Override header
+ .build()) {
+ QueryExecHTTP qe = (QueryExecHTTP)QueryExec.adapt(qExec);
+ assertEquals("o", qe.getAcceptHeaderSelect());
+ assertEquals("o", qe.getAcceptHeaderAsk());
+ assertEquals("o", qe.getAcceptHeaderDescribe());
+ assertEquals("o", qe.getAcceptHeaderConstructGraph());
+ assertEquals("o", qe.getAcceptHeaderConstructDataset());
+ }
+ }
+
+ @Test
+ public void test_override_header_02() {
+ try (QueryExecutionHTTP qExec = QueryExecutionHTTPBuilder.create()
+ .endpoint("urn:dummy-service")
+ .queryString("SELECT * { ?s ?p ?o }")
+ .acceptHeader("o") // Override header first
+ .acceptHeaderGraph("g")
+ .build()) {
+ QueryExecHTTP qe = (QueryExecHTTP)QueryExec.adapt(qExec);
+ assertEquals("o", qe.getAcceptHeaderSelect());
+ assertEquals("o", qe.getAcceptHeaderAsk());
+ assertEquals("g", qe.getAcceptHeaderDescribe());
+ assertEquals("g", qe.getAcceptHeaderConstructGraph());
+ assertEquals("o", qe.getAcceptHeaderConstructDataset());
+ }
+ }
+
+ @Test
+ public void test_override_header_03() {
+ try (QueryExecutionHTTP qExec = QueryExecutionHTTPBuilder.create()
+ .endpoint("urn:dummy-service")
+ .queryString("SELECT * { ?s ?p ?o }")
+ .acceptHeaderGraph("g")
+ .acceptHeader("o") // Override header last - overrides prior
settings.
+ .build()) {
+ QueryExecHTTP qe = (QueryExecHTTP)QueryExec.adapt(qExec);
+ assertEquals("o", qe.getAcceptHeaderSelect());
+ assertEquals("o", qe.getAcceptHeaderAsk());
+ assertEquals("o", qe.getAcceptHeaderDescribe());
+ assertEquals("o", qe.getAcceptHeaderConstructGraph());
+ assertEquals("o", qe.getAcceptHeaderConstructDataset());
+ }
+ }
+}
diff --git
a/jena-rdfconnection/src/test/java/org/apache/jena/rdflink/TS_RDFLink.java
b/jena-rdfconnection/src/test/java/org/apache/jena/rdflink/TS_RDFLink.java
index 7a5ba43b3b..248c0a3844 100644
--- a/jena-rdfconnection/src/test/java/org/apache/jena/rdflink/TS_RDFLink.java
+++ b/jena-rdfconnection/src/test/java/org/apache/jena/rdflink/TS_RDFLink.java
@@ -28,6 +28,7 @@ import org.junit.platform.suite.api.Suite;
, TestRDFLinkLocalTxnMem.class
, TestRDFLinkLocalMRSW.class
, TestLibRDFLink.class
+ , TestRDFLinkHTTPHeaders.class
})
public class TS_RDFLink {}
diff --git
a/jena-rdfconnection/src/test/java/org/apache/jena/rdflink/TestRDFLinkHTTPHeaders.java
b/jena-rdfconnection/src/test/java/org/apache/jena/rdflink/TestRDFLinkHTTPHeaders.java
new file mode 100644
index 0000000000..e144f8eb27
--- /dev/null
+++
b/jena-rdfconnection/src/test/java/org/apache/jena/rdflink/TestRDFLinkHTTPHeaders.java
@@ -0,0 +1,97 @@
+/*
+ * 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.rdflink;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import org.apache.jena.sparql.exec.http.QueryExecHTTP;
+import org.apache.jena.sparql.exec.http.QueryExecHTTPBuilder;
+import org.junit.jupiter.api.Test;
+
+public class TestRDFLinkHTTPHeaders {
+
+ /**
+ * Test whether connection headers are properly passed on to the query
execution.
+ * No query is actually executed.
+ */
+ @Test void test_headers_parsed() {
+ try (RDFLink link = RDFLinkHTTP.service("urn:dummy-service")
+ .acceptHeaderSelectQuery("s")
+ .acceptHeaderAskQuery("a")
+ .acceptHeaderGraph("g")
+ .acceptHeaderDataset("d")
+ .build()) {
+
+ try (QueryExecHTTP qe = ((QueryExecHTTPBuilder)link.newQuery())
+ .query("SELECT * { ?s ?p ?o }")
+ .acceptHeaderSelectQuery("x").build()) {
+ assertEquals("x", qe.getAcceptHeaderSelect());
+
+ assertEquals("a", qe.getAcceptHeaderAsk());
+ assertEquals("g", qe.getAcceptHeaderDescribe());
+ assertEquals("g", qe.getAcceptHeaderConstructGraph());
+ assertEquals("d", qe.getAcceptHeaderConstructDataset());
+ }
+
+ try (QueryExecHTTP qe = ((QueryExecHTTPBuilder)link.newQuery())
+ .query("ASK { ?s ?p ?o }")
+ .acceptHeaderAskQuery("x").build()) {
+ assertEquals("x", qe.getAcceptHeaderAsk());
+
+ assertEquals("s", qe.getAcceptHeaderSelect());
+ assertEquals("g", qe.getAcceptHeaderDescribe());
+ assertEquals("g", qe.getAcceptHeaderConstructGraph());
+ assertEquals("d", qe.getAcceptHeaderConstructDataset());
+ }
+
+ try (QueryExecHTTP qe = ((QueryExecHTTPBuilder)link.newQuery())
+ .query("DESCRIBE <urn:x>")
+ .acceptHeaderGraph("x").build()) {
+ assertEquals("x", qe.getAcceptHeaderDescribe());
+ assertEquals("x", qe.getAcceptHeaderConstructGraph());
+
+ assertEquals("s", qe.getAcceptHeaderSelect());
+ assertEquals("a", qe.getAcceptHeaderAsk());
+ assertEquals("d", qe.getAcceptHeaderConstructDataset());
+ }
+
+ try (QueryExecHTTP qe = ((QueryExecHTTPBuilder)link.newQuery())
+ .query("CONSTRUCT WHERE { ?s ?p ?o }")
+ .acceptHeaderGraph("x").build()) {
+ assertEquals("x", qe.getAcceptHeaderConstructGraph());
+ assertEquals("x", qe.getAcceptHeaderDescribe());
+
+ assertEquals("s", qe.getAcceptHeaderSelect());
+ assertEquals("a", qe.getAcceptHeaderAsk());
+ assertEquals("d", qe.getAcceptHeaderConstructDataset());
+ }
+
+ try (QueryExecHTTP qe = ((QueryExecHTTPBuilder)link.newQuery())
+ .query("CONSTRUCT WHERE { GRAPH ?g { ?s ?p ?o } }")
+ .acceptHeaderDataset("x").build()) {
+ assertEquals("x", qe.getAcceptHeaderConstructDataset());
+
+ assertEquals("s", qe.getAcceptHeaderSelect());
+ assertEquals("a", qe.getAcceptHeaderAsk());
+ assertEquals("g", qe.getAcceptHeaderDescribe());
+ assertEquals("g", qe.getAcceptHeaderConstructGraph());
+ }
+ }
+ }
+}