You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jena.apache.org by an...@apache.org on 2022/07/03 15:26:38 UTC
[jena] branch main updated: gh-1387: Bulk extension for service executor plugin system
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 b2ed4de743 gh-1387: Bulk extension for service executor plugin system
new db4a7505ef Merge pull request #1388 from Aklakan/gh-1387
b2ed4de743 is described below
commit b2ed4de743feeae48c82bcd4384341ea4b17282a
Author: Claus Stadler <Ra...@googlemail.com>
AuthorDate: Mon May 16 08:36:10 2022 +0200
gh-1387: Bulk extension for service executor plugin system
---
.../apache/jena/sparql/engine/QueryIterator.java | 6 +-
.../apache/jena/sparql/engine/main/OpExecutor.java | 3 +-
.../engine/main/iterator/QueryIterService.java | 19 +--
.../jena/sparql/service/ServiceExecution.java | 13 +-
.../sparql/service/ServiceExecutorFactory.java | 26 ++--
.../sparql/service/ServiceExecutorRegistry.java | 159 ++++++++++++++++++---
.../ChainingServiceExecutorBulk.java} | 20 ++-
.../ServiceExecutorBulk.java} | 20 ++-
.../bulk/ServiceExecutorBulkOverRegistry.java | 79 ++++++++++
.../service/bulk/ServiceExecutorBulkToSingle.java | 53 +++++++
.../ChainingServiceExecutor.java} | 12 +-
.../single/ChainingServiceExecutorWrapper.java | 59 ++++++++
.../ServiceExecutor.java} | 10 +-
.../ServiceExecutorDecorator.java} | 32 +++--
.../sparql/service/single/ServiceExecutorHttp.java | 72 ++++++++++
.../single/ServiceExecutorOverRegistry.java | 69 +++++++++
.../examples/service/CustomServiceExecutor.java | 52 +++++--
.../apache/jena/sparql/exec/http/TestService.java | 8 +-
.../test/service/TestCustomServiceExecutor.java | 14 +-
.../apache/jena/test/service/TestServiceExec.java | 4 +-
20 files changed, 604 insertions(+), 126 deletions(-)
diff --git a/jena-arq/src/main/java/org/apache/jena/sparql/engine/QueryIterator.java b/jena-arq/src/main/java/org/apache/jena/sparql/engine/QueryIterator.java
index 3b3821af03..a0f6003c86 100644
--- a/jena-arq/src/main/java/org/apache/jena/sparql/engine/QueryIterator.java
+++ b/jena-arq/src/main/java/org/apache/jena/sparql/engine/QueryIterator.java
@@ -18,15 +18,13 @@
package org.apache.jena.sparql.engine;
-import java.util.Iterator ;
-
-import org.apache.jena.atlas.lib.Closeable ;
+import org.apache.jena.atlas.iterator.IteratorCloseable;
import org.apache.jena.sparql.engine.binding.Binding ;
import org.apache.jena.sparql.util.PrintSerializable ;
/** Root of query iterators in ARQ. */
-public interface QueryIterator extends Closeable, Iterator<Binding>, PrintSerializable
+public interface QueryIterator extends IteratorCloseable<Binding>, PrintSerializable
{
/** Get next binding */
public Binding nextBinding() ;
diff --git a/jena-arq/src/main/java/org/apache/jena/sparql/engine/main/OpExecutor.java b/jena-arq/src/main/java/org/apache/jena/sparql/engine/main/OpExecutor.java
index 1e0785f5ac..fbd3e98fc0 100644
--- a/jena-arq/src/main/java/org/apache/jena/sparql/engine/main/OpExecutor.java
+++ b/jena-arq/src/main/java/org/apache/jena/sparql/engine/main/OpExecutor.java
@@ -45,6 +45,7 @@ import org.apache.jena.sparql.expr.Expr ;
import org.apache.jena.sparql.expr.ExprList ;
import org.apache.jena.sparql.procedure.ProcEval ;
import org.apache.jena.sparql.procedure.Procedure ;
+import org.apache.jena.sparql.service.ServiceExecutorRegistry;
/**
* Turn an Op expression into an execution of QueryIterators.
@@ -305,7 +306,7 @@ public class OpExecutor
}
protected QueryIterator execute(OpService opService, QueryIterator input) {
- return new QueryIterService(input, opService, execCxt) ;
+ return ServiceExecutorRegistry.exec(input, opService, execCxt);
}
// Quad form, "GRAPH ?g {}" Flip back to OpGraph.
diff --git a/jena-arq/src/main/java/org/apache/jena/sparql/engine/main/iterator/QueryIterService.java b/jena-arq/src/main/java/org/apache/jena/sparql/engine/main/iterator/QueryIterService.java
index 8dd38171aa..bc276e3aef 100644
--- a/jena-arq/src/main/java/org/apache/jena/sparql/engine/main/iterator/QueryIterService.java
+++ b/jena-arq/src/main/java/org/apache/jena/sparql/engine/main/iterator/QueryIterService.java
@@ -31,12 +31,15 @@ import org.apache.jena.sparql.engine.iterator.QueryIterRepeatApply;
import org.apache.jena.sparql.engine.iterator.QueryIterSingleton;
import org.apache.jena.sparql.engine.main.QC ;
import org.apache.jena.sparql.exec.http.Service;
-import org.apache.jena.sparql.service.ServiceExecution;
-import org.apache.jena.sparql.service.ServiceExecutorFactory;
import org.apache.jena.sparql.service.ServiceExecutorRegistry;
+import org.apache.jena.sparql.service.single.ChainingServiceExecutor;
import org.apache.jena.sparql.util.Context;
-
+/**
+ * This class continues to exist for compatibility with legacy service extensions.
+ * New code should register extensions at a {@link ServiceExecutorRegistry}.
+ */
+@Deprecated(since = "4.6.0")
public class QueryIterService extends QueryIterRepeatApply
{
protected OpService opService ;
@@ -59,20 +62,21 @@ public class QueryIterService extends QueryIterRepeatApply
ExecutionContext execCxt = getExecContext();
Context cxt = execCxt.getContext();
ServiceExecutorRegistry registry = ServiceExecutorRegistry.get(cxt);
- ServiceExecution svcExec = null;
+ QueryIterator svcExec = null;
OpService substitutedOp = (OpService)QC.substitute(opService, outerBinding);
try {
// ---- Find handler
if ( registry != null ) {
- for ( ServiceExecutorFactory factory : registry.getFactories() ) {
+ // FIXME This needs to be updated for chainable executors
+ for ( ChainingServiceExecutor factory : registry.getSingleChain() ) {
// Internal consistency check
if ( factory == null ) {
Log.warn(this, "SERVICE <" + opService.getService().toString() + ">: Null item in custom ServiceExecutionRegistry");
continue;
}
- svcExec = factory.createExecutor(substitutedOp, opService, outerBinding, execCxt);
+ svcExec = factory.createExecution(substitutedOp, opService, outerBinding, execCxt, null);
if ( svcExec != null )
break;
}
@@ -81,8 +85,7 @@ public class QueryIterService extends QueryIterRepeatApply
// ---- Execute
if ( svcExec == null )
throw new QueryExecException("No SERVICE handler");
- QueryIterator qIter = svcExec.exec();
- qIter = QueryIter.makeTracked(qIter, getExecContext());
+ QueryIterator qIter = QueryIter.makeTracked(svcExec, getExecContext());
// Need to put the outerBinding as parent to every binding of the service call.
// There should be no variables in common because of the OpSubstitute.substitute
return new QueryIterCommonParent(qIter, outerBinding, getExecContext());
diff --git a/jena-arq/src/main/java/org/apache/jena/sparql/service/ServiceExecution.java b/jena-arq/src/main/java/org/apache/jena/sparql/service/ServiceExecution.java
index 025ee921a9..e6d386169e 100644
--- a/jena-arq/src/main/java/org/apache/jena/sparql/service/ServiceExecution.java
+++ b/jena-arq/src/main/java/org/apache/jena/sparql/service/ServiceExecution.java
@@ -19,14 +19,15 @@
package org.apache.jena.sparql.service;
import org.apache.jena.sparql.engine.QueryIterator;
-import org.apache.jena.sparql.engine.main.iterator.QueryIterService;
-/**
- * Execution of a SERVICE clause in the context of {@link QueryIterService} applying an input binding.
- * @see ServiceExecutorFactory
+/**
+ * Execution of a SERVICE clause in the context of {@link QueryIterService} applying an input binding.s
+ * @see ServiceExecutor
* @see ServiceExecutorRegistry
- */
+ *
+ * @deprecated Deprecated in favor of QueryIterators that initialize lazily
+ */
+@Deprecated(since = "4.6.0")
public interface ServiceExecution {
public QueryIterator exec();
}
-
diff --git a/jena-arq/src/main/java/org/apache/jena/sparql/service/ServiceExecutorFactory.java b/jena-arq/src/main/java/org/apache/jena/sparql/service/ServiceExecutorFactory.java
index ee55d7a45b..0bdb01846b 100644
--- a/jena-arq/src/main/java/org/apache/jena/sparql/service/ServiceExecutorFactory.java
+++ b/jena-arq/src/main/java/org/apache/jena/sparql/service/ServiceExecutorFactory.java
@@ -22,17 +22,21 @@ import org.apache.jena.sparql.algebra.op.OpService;
import org.apache.jena.sparql.engine.ExecutionContext;
import org.apache.jena.sparql.engine.QueryIterator;
import org.apache.jena.sparql.engine.binding.Binding;
+import org.apache.jena.sparql.service.single.ChainingServiceExecutor;
+import org.apache.jena.sparql.service.single.ServiceExecutor;
-/**
- * Interface for custom handling of service execution requests.
- */
+/** Compatibility interface. Consider migrating legacy code to {@link ChainingServiceExecutor} or {@link ServiceExecutor} */
+@Deprecated(since = "4.6.0")
@FunctionalInterface
-public interface ServiceExecutorFactory {
- /**
- * If this factory cannot handle the execution request then this method should return null.
- * Otherwise, a {@link ServiceExecution} with the corresponding {@link QueryIterator} is returned.
- *
- * @return A QueryIterator if this factory can handle the request, or null otherwise.
- */
- public ServiceExecution createExecutor(OpService opExecute, OpService original, Binding binding, ExecutionContext execCxt);
+public interface ServiceExecutorFactory
+ extends ServiceExecutor
+{
+ @Override
+ default QueryIterator createExecution(OpService opExecute, OpService original, Binding binding, ExecutionContext execCxt) {
+ ServiceExecution svcExec = createExecutor(opExecute, original, binding, execCxt);
+ QueryIterator result = svcExec == null ? null : svcExec.exec();
+ return result;
+ }
+
+ ServiceExecution createExecutor(OpService opExecute, OpService original, Binding binding, ExecutionContext execCxt);
}
diff --git a/jena-arq/src/main/java/org/apache/jena/sparql/service/ServiceExecutorRegistry.java b/jena-arq/src/main/java/org/apache/jena/sparql/service/ServiceExecutorRegistry.java
index 71f4964abb..6390889bc9 100644
--- a/jena-arq/src/main/java/org/apache/jena/sparql/service/ServiceExecutorRegistry.java
+++ b/jena-arq/src/main/java/org/apache/jena/sparql/service/ServiceExecutorRegistry.java
@@ -19,18 +19,41 @@
package org.apache.jena.sparql.service;
import java.util.ArrayList;
+import java.util.Iterator;
import java.util.List;
import java.util.Objects;
import org.apache.jena.query.ARQ;
import org.apache.jena.sparql.ARQConstants;
+import org.apache.jena.sparql.algebra.op.OpService;
+import org.apache.jena.sparql.engine.ExecutionContext;
+import org.apache.jena.sparql.engine.QueryIterator;
+import org.apache.jena.sparql.service.bulk.ChainingServiceExecutorBulk;
+import org.apache.jena.sparql.service.bulk.ServiceExecutorBulk;
+import org.apache.jena.sparql.service.bulk.ServiceExecutorBulkOverRegistry;
+import org.apache.jena.sparql.service.single.ChainingServiceExecutor;
+import org.apache.jena.sparql.service.single.ChainingServiceExecutorWrapper;
+import org.apache.jena.sparql.service.single.ServiceExecutor;
+import org.apache.jena.sparql.service.single.ServiceExecutorHttp;
import org.apache.jena.sparql.util.Context;
-import org.apache.jena.sparql.exec.http.*;
+/**
+ * Registry for service executors that can be extended with custom ones.
+ * Bulk and single (=non-bulk) executors are maintained in two separate lists.
+ *
+ * Default execution will always start with the bulk list first.
+ * Once that list is exhausted by means of all bulk executors having delegated the request,
+ * then the non-bulk ones will be considered.
+ * There is no need to explicitly register a bulk-to-non-bulk bridge.
+ */
public class ServiceExecutorRegistry
{
- // A list of custom service executors which are tried in the given order
- List<ServiceExecutorFactory> registry = new ArrayList<>();
+ // A list of bulk service executors which are tried in the given order
+ List<ChainingServiceExecutorBulk> bulkChain = new ArrayList<>();
+
+ // A list of single (non-bulk) service executors which are tried in the given order
+ // This list is only considered after after the bulk registry
+ List<ChainingServiceExecutor> singleChain = new ArrayList<>();
public static ServiceExecutorRegistry standardRegistry()
{
@@ -38,16 +61,25 @@ public class ServiceExecutorRegistry
return reg ;
}
- /** A "call with SPARQL query" service execution factory. */
- public static ServiceExecutorFactory httpService = (op, opx, binding, execCxt) -> ()->Service.exec(op, execCxt.getContext());
+ /** A "call with SPARQL query" service executor. */
+ public static ServiceExecutor httpService = new ServiceExecutorHttp();
+
+ /** Blindly adds the default executor(s); concretely adds the http executor */
+ public static void initWithDefaults(ServiceExecutorRegistry registry) {
+ registry.add(httpService);
+ }
public static void init() {
// Initialize if there is no registry already set
- ServiceExecutorRegistry reg = new ServiceExecutorRegistry() ;
- reg.add(httpService);
+ ServiceExecutorRegistry reg = new ServiceExecutorRegistry();
+ initWithDefaults(reg);
set(ARQ.getContext(), reg) ;
}
+ /**
+ * Return the global instance from the ARQ context; create that instance if needed.
+ * Never returns null.
+ */
public static ServiceExecutorRegistry get()
{
// Initialize if there is no registry already set
@@ -61,6 +93,16 @@ public class ServiceExecutorRegistry
return reg ;
}
+ /** Return the registry from the given context if present; otherwise return the global one */
+ public static ServiceExecutorRegistry chooseRegistry(Context context) {
+ ServiceExecutorRegistry result = ServiceExecutorRegistry.get(context);
+ if (result == null) {
+ result = get();
+ }
+ return result;
+ }
+
+ /** Return the registry from the given context only; null if there is none */
public static ServiceExecutorRegistry get(Context context)
{
if ( context == null )
@@ -76,29 +118,102 @@ public class ServiceExecutorRegistry
public ServiceExecutorRegistry()
{}
- /** Create an independent copy of the registry */
- public ServiceExecutorRegistry copy() {
- ServiceExecutorRegistry result = new ServiceExecutorRegistry();
- result.getFactories().addAll(getFactories());
- return result;
+ /*
+ * Non-bulk API
+ */
+
+ /** Prepend the given service executor as a link to the per-binding chain */
+ public ServiceExecutorRegistry addSingleLink(ChainingServiceExecutor f) {
+ Objects.requireNonNull(f) ;
+ singleChain.add(0, f) ;
+ return this;
+ }
+
+ /** Remove the given service executor from the per-binding chain */
+ public ServiceExecutorRegistry removeSingleLink(ChainingServiceExecutor f) {
+ singleChain.remove(f) ;
+ return this;
+ }
+
+ /** Wraps the given service executor as a chaining one and prepends it
+ * to the non-bulk chain via {@link #addSingleLink(ChainingServiceExecutor)} */
+ public ServiceExecutorRegistry add(ServiceExecutor f) {
+ Objects.requireNonNull(f) ;
+ return addSingleLink(new ChainingServiceExecutorWrapper(f));
}
- /** Insert a service executor factory. Must not be null. */
- public ServiceExecutorRegistry add(ServiceExecutorFactory f) {
+ /** Remove a given service executor - internally attempts to unwrap every chaining service executor */
+ public ServiceExecutorRegistry remove(ServiceExecutor f) {
+ Iterator<ChainingServiceExecutor> it = singleChain.iterator();
+ while (it.hasNext()) {
+ ChainingServiceExecutor cse = it.next();
+ if (cse instanceof ChainingServiceExecutorWrapper) {
+ ChainingServiceExecutorWrapper wrapper = (ChainingServiceExecutorWrapper)cse;
+ ServiceExecutor delegate = wrapper.getDelegate();
+ if (Objects.equals(delegate, f)) {
+ it.remove();
+ }
+ }
+ }
+ return this;
+ }
+
+ /** Retrieve the actual list of per-binding executors; allows for re-ordering */
+ public List<ChainingServiceExecutor> getSingleChain() {
+ return singleChain;
+ }
+
+ /*
+ * Bulk API
+ */
+
+ /** Add a chaining bulk executor as a link to the executor chain */
+ public ServiceExecutorRegistry addBulkLink(ChainingServiceExecutorBulk f) {
Objects.requireNonNull(f) ;
- registry.add(0, f) ;
+ bulkChain.add(0, f) ;
return this;
}
- /** Remove the given service executor factory. */
- public ServiceExecutorRegistry remove(ServiceExecutorFactory f) {
- registry.remove(f) ;
+ /** Remove the given service executor */
+ public ServiceExecutorRegistry removeBulkLink(ChainingServiceExecutorBulk f) {
+ bulkChain.remove(f) ;
return this;
}
- /** Retrieve the actual list of factories; allows for re-ordering */
- public List<ServiceExecutorFactory> getFactories() {
- return registry;
+ /** Retrieve the actual list of bulk executors; allows for re-ordering */
+ public List<ChainingServiceExecutorBulk> getBulkChain() {
+ return bulkChain;
}
-}
\ No newline at end of file
+ /*
+ * Utility
+ */
+
+ /** Create an independent copy of the registry */
+ public ServiceExecutorRegistry copy() {
+ ServiceExecutorRegistry result = new ServiceExecutorRegistry();
+ result.getSingleChain().addAll(getSingleChain());
+ result.getBulkChain().addAll(getBulkChain());
+ return result;
+ }
+
+ /** Return a copy of the registry in the context (if present) or a fresh instance */
+ public ServiceExecutorRegistry copyFrom(Context cxt) {
+ ServiceExecutorRegistry tmp = ServiceExecutorRegistry.get(cxt);
+ ServiceExecutorRegistry result = tmp == null ? new ServiceExecutorRegistry() : tmp.copy();
+ return result;
+ }
+
+ /*
+ * Execution
+ */
+
+ /** Execute an OpService w.r.t. the execCxt's service executor registry */
+ public static QueryIterator exec(QueryIterator input, OpService opService, ExecutionContext execCxt) {
+ Context cxt = execCxt.getContext();
+ ServiceExecutorRegistry registry = ServiceExecutorRegistry.chooseRegistry(cxt);
+ ServiceExecutorBulk serviceExecutor = new ServiceExecutorBulkOverRegistry(registry);
+ QueryIterator qIter = serviceExecutor.createExecution(opService, input, execCxt);
+ return qIter;
+ }
+}
diff --git a/jena-arq/src/main/java/org/apache/jena/sparql/service/ServiceExecutorFactory.java b/jena-arq/src/main/java/org/apache/jena/sparql/service/bulk/ChainingServiceExecutorBulk.java
similarity index 59%
copy from jena-arq/src/main/java/org/apache/jena/sparql/service/ServiceExecutorFactory.java
copy to jena-arq/src/main/java/org/apache/jena/sparql/service/bulk/ChainingServiceExecutorBulk.java
index ee55d7a45b..36bef79a3f 100644
--- a/jena-arq/src/main/java/org/apache/jena/sparql/service/ServiceExecutorFactory.java
+++ b/jena-arq/src/main/java/org/apache/jena/sparql/service/bulk/ChainingServiceExecutorBulk.java
@@ -16,23 +16,21 @@
* limitations under the License.
*/
-package org.apache.jena.sparql.service;
+package org.apache.jena.sparql.service.bulk;
import org.apache.jena.sparql.algebra.op.OpService;
import org.apache.jena.sparql.engine.ExecutionContext;
import org.apache.jena.sparql.engine.QueryIterator;
-import org.apache.jena.sparql.engine.binding.Binding;
-/**
- * Interface for custom handling of service execution requests.
- */
-@FunctionalInterface
-public interface ServiceExecutorFactory {
+/** Interface for custom service execution extensions that handle
+ * the iterator over the input bindings themselves */
+public interface ChainingServiceExecutorBulk {
/**
- * If this factory cannot handle the execution request then this method should return null.
- * Otherwise, a {@link ServiceExecution} with the corresponding {@link QueryIterator} is returned.
+ * If this executor cannot handle the createExecution request then it should delegate
+ * to the chain's @{code createExecution} method and return its result.
+ * In any case, a {@link QueryIterator} needs to be returned.
*
- * @return A QueryIterator if this factory can handle the request, or null otherwise.
+ * @return A non-null {@link QueryIterator} for the execution of the given OpService expression.
*/
- public ServiceExecution createExecutor(OpService opExecute, OpService original, Binding binding, ExecutionContext execCxt);
+ public QueryIterator createExecution(OpService opService, QueryIterator input, ExecutionContext execCxt, ServiceExecutorBulk chain);
}
diff --git a/jena-arq/src/main/java/org/apache/jena/sparql/service/ServiceExecutorFactory.java b/jena-arq/src/main/java/org/apache/jena/sparql/service/bulk/ServiceExecutorBulk.java
similarity index 59%
copy from jena-arq/src/main/java/org/apache/jena/sparql/service/ServiceExecutorFactory.java
copy to jena-arq/src/main/java/org/apache/jena/sparql/service/bulk/ServiceExecutorBulk.java
index ee55d7a45b..d19ccc52d1 100644
--- a/jena-arq/src/main/java/org/apache/jena/sparql/service/ServiceExecutorFactory.java
+++ b/jena-arq/src/main/java/org/apache/jena/sparql/service/bulk/ServiceExecutorBulk.java
@@ -16,23 +16,19 @@
* limitations under the License.
*/
-package org.apache.jena.sparql.service;
+package org.apache.jena.sparql.service.bulk;
import org.apache.jena.sparql.algebra.op.OpService;
import org.apache.jena.sparql.engine.ExecutionContext;
import org.apache.jena.sparql.engine.QueryIterator;
-import org.apache.jena.sparql.engine.binding.Binding;
+import org.apache.jena.sparql.service.ServiceExecutorRegistry;
/**
- * Interface for custom handling of service execution requests.
+ * Interface for abstracting {@link OpService} execution.
+ *
+ * Custom extensions should provide implementations of {@link ChainingServiceExecutorBulk}
+ * and register them with {@link ServiceExecutorRegistry#addBulkLink(ChainingServiceExecutorBulk)}.
*/
-@FunctionalInterface
-public interface ServiceExecutorFactory {
- /**
- * If this factory cannot handle the execution request then this method should return null.
- * Otherwise, a {@link ServiceExecution} with the corresponding {@link QueryIterator} is returned.
- *
- * @return A QueryIterator if this factory can handle the request, or null otherwise.
- */
- public ServiceExecution createExecutor(OpService opExecute, OpService original, Binding binding, ExecutionContext execCxt);
+public interface ServiceExecutorBulk {
+ public QueryIterator createExecution(OpService opService, QueryIterator input, ExecutionContext execCxt);
}
diff --git a/jena-arq/src/main/java/org/apache/jena/sparql/service/bulk/ServiceExecutorBulkOverRegistry.java b/jena-arq/src/main/java/org/apache/jena/sparql/service/bulk/ServiceExecutorBulkOverRegistry.java
new file mode 100644
index 0000000000..300a54e01b
--- /dev/null
+++ b/jena-arq/src/main/java/org/apache/jena/sparql/service/bulk/ServiceExecutorBulkOverRegistry.java
@@ -0,0 +1,79 @@
+/*
+ * 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.sparql.service.bulk;
+
+import java.util.List;
+
+import org.apache.jena.query.QueryException;
+import org.apache.jena.sparql.algebra.op.OpService;
+import org.apache.jena.sparql.engine.ExecutionContext;
+import org.apache.jena.sparql.engine.QueryIterator;
+import org.apache.jena.sparql.service.ServiceExecutorRegistry;
+import org.apache.jena.sparql.service.single.ServiceExecutor;
+import org.apache.jena.sparql.service.single.ServiceExecutorOverRegistry;
+
+/**
+ * Factory for service executions w.r.t. a {@link ServiceExecutorRegistry}.
+ * The {@link #createExecution(OpService, QueryIterator, ExecutionContext)} method
+ * delegates the request to all executors in order of their registration.
+ */
+public class ServiceExecutorBulkOverRegistry
+ implements ServiceExecutorBulk
+{
+ protected ServiceExecutorRegistry registry;
+
+ /** Position in the chain */
+ protected int pos;
+
+ public ServiceExecutorBulkOverRegistry(ServiceExecutorRegistry registry) {
+ this(registry, 0);
+ }
+
+ public ServiceExecutorBulkOverRegistry(ServiceExecutorRegistry registry, int pos) {
+ super();
+ this.registry = registry;
+ this.pos = pos;
+ }
+
+ @Override
+ public QueryIterator createExecution(OpService opService, QueryIterator input, ExecutionContext execCxt) {
+ if (registry == null) {
+ throw new QueryException("No service executor registry configured");
+ }
+
+ QueryIterator result;
+
+ List<ChainingServiceExecutorBulk> factories = registry.getBulkChain();
+ int n = factories.size();
+ if (pos >= n) {
+ // Chain to the single registry
+ ServiceExecutor singleExecutor = new ServiceExecutorOverRegistry(registry);
+ ServiceExecutorBulk bridge = new ServiceExecutorBulkToSingle(singleExecutor);
+ result = bridge.createExecution(opService, input, execCxt);
+
+ // Alternatively we could require for the bridge to be explicitly registered
+ // throw new QueryException("No more elements in service executor chain (pos=" + pos + ", chain size=" + n + ")");
+ } else {
+ ChainingServiceExecutorBulk factory = factories.get(pos);
+ ServiceExecutorBulk next = new ServiceExecutorBulkOverRegistry(registry, pos + 1);
+ result = factory.createExecution(opService, input, execCxt, next);
+ }
+ return result;
+ }
+}
diff --git a/jena-arq/src/main/java/org/apache/jena/sparql/service/bulk/ServiceExecutorBulkToSingle.java b/jena-arq/src/main/java/org/apache/jena/sparql/service/bulk/ServiceExecutorBulkToSingle.java
new file mode 100644
index 0000000000..fc3bd61719
--- /dev/null
+++ b/jena-arq/src/main/java/org/apache/jena/sparql/service/bulk/ServiceExecutorBulkToSingle.java
@@ -0,0 +1,53 @@
+/*
+ * 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.sparql.service.bulk;
+
+import org.apache.jena.sparql.algebra.op.OpService;
+import org.apache.jena.sparql.engine.ExecutionContext;
+import org.apache.jena.sparql.engine.QueryIterator;
+import org.apache.jena.sparql.engine.binding.Binding;
+import org.apache.jena.sparql.engine.iterator.QueryIterRepeatApply;
+import org.apache.jena.sparql.engine.main.QC;
+import org.apache.jena.sparql.service.single.ServiceExecutor;
+
+/** Bridge from bulk to individual binding level*/
+public class ServiceExecutorBulkToSingle
+ implements ServiceExecutorBulk
+{
+ protected ServiceExecutor delegate;
+
+ public ServiceExecutorBulkToSingle(ServiceExecutor delegate) {
+ super();
+ this.delegate = delegate;
+ }
+
+ @Override
+ public QueryIterator createExecution(OpService original, QueryIterator input,
+ ExecutionContext execCxt) {
+
+ return new QueryIterRepeatApply(input, execCxt) {
+ @Override
+ protected QueryIterator nextStage(Binding binding) {
+ OpService opExecute = (OpService)QC.substitute(original, binding);
+ QueryIterator qIter = delegate.createExecution(opExecute, original, binding, execCxt);
+ return qIter;
+ }
+ };
+ }
+}
diff --git a/jena-arq/src/main/java/org/apache/jena/sparql/service/ServiceExecutorFactory.java b/jena-arq/src/main/java/org/apache/jena/sparql/service/single/ChainingServiceExecutor.java
similarity index 75%
copy from jena-arq/src/main/java/org/apache/jena/sparql/service/ServiceExecutorFactory.java
copy to jena-arq/src/main/java/org/apache/jena/sparql/service/single/ChainingServiceExecutor.java
index ee55d7a45b..b3c8aac95a 100644
--- a/jena-arq/src/main/java/org/apache/jena/sparql/service/ServiceExecutorFactory.java
+++ b/jena-arq/src/main/java/org/apache/jena/sparql/service/single/ChainingServiceExecutor.java
@@ -16,23 +16,19 @@
* limitations under the License.
*/
-package org.apache.jena.sparql.service;
+package org.apache.jena.sparql.service.single;
import org.apache.jena.sparql.algebra.op.OpService;
import org.apache.jena.sparql.engine.ExecutionContext;
import org.apache.jena.sparql.engine.QueryIterator;
import org.apache.jena.sparql.engine.binding.Binding;
-/**
- * Interface for custom handling of service execution requests.
- */
-@FunctionalInterface
-public interface ServiceExecutorFactory {
+public interface ChainingServiceExecutor {
/**
* If this factory cannot handle the execution request then this method should return null.
- * Otherwise, a {@link ServiceExecution} with the corresponding {@link QueryIterator} is returned.
+ * Otherwise, a {@link QueryIterator} is returned.
*
* @return A QueryIterator if this factory can handle the request, or null otherwise.
*/
- public ServiceExecution createExecutor(OpService opExecute, OpService original, Binding binding, ExecutionContext execCxt);
+ public QueryIterator createExecution(OpService opExecute, OpService opOriginal, Binding binding, ExecutionContext execCxt, ServiceExecutor chain);
}
diff --git a/jena-arq/src/main/java/org/apache/jena/sparql/service/single/ChainingServiceExecutorWrapper.java b/jena-arq/src/main/java/org/apache/jena/sparql/service/single/ChainingServiceExecutorWrapper.java
new file mode 100644
index 0000000000..f27c0770b2
--- /dev/null
+++ b/jena-arq/src/main/java/org/apache/jena/sparql/service/single/ChainingServiceExecutorWrapper.java
@@ -0,0 +1,59 @@
+/*
+ * 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.sparql.service.single;
+
+import org.apache.jena.sparql.algebra.op.OpService;
+import org.apache.jena.sparql.engine.ExecutionContext;
+import org.apache.jena.sparql.engine.QueryIterator;
+import org.apache.jena.sparql.engine.binding.Binding;
+import org.apache.jena.sparql.service.ServiceExecutorRegistry;
+
+/**
+ * Turns a ServiceExecutor into a chaining one.
+ * Mainly used by {@link ServiceExecutorRegistry} for wrapping
+ * non-chaining service executors.
+ * If the executor returns null then the next link in the chain will be tried.
+ */
+public class ChainingServiceExecutorWrapper
+ implements ChainingServiceExecutor
+{
+ protected ServiceExecutor executor;
+
+ public ChainingServiceExecutorWrapper(ServiceExecutor executor) {
+ super();
+ this.executor = executor;
+ }
+
+ public ServiceExecutor getDelegate() {
+ return executor;
+ }
+
+ @Override
+ public QueryIterator createExecution(OpService opExecute, OpService opOriginal, Binding binding,
+ ExecutionContext execCxt, ServiceExecutor chain) {
+
+ QueryIterator qIter = executor.createExecution(opExecute, opOriginal, binding, execCxt);
+ QueryIterator result = qIter != null
+ ? qIter
+ : chain.createExecution(opExecute, opOriginal, binding, execCxt);
+
+ return result;
+ }
+
+}
diff --git a/jena-arq/src/main/java/org/apache/jena/sparql/service/ServiceExecutorFactory.java b/jena-arq/src/main/java/org/apache/jena/sparql/service/single/ServiceExecutor.java
similarity index 76%
copy from jena-arq/src/main/java/org/apache/jena/sparql/service/ServiceExecutorFactory.java
copy to jena-arq/src/main/java/org/apache/jena/sparql/service/single/ServiceExecutor.java
index ee55d7a45b..c43f805e25 100644
--- a/jena-arq/src/main/java/org/apache/jena/sparql/service/ServiceExecutorFactory.java
+++ b/jena-arq/src/main/java/org/apache/jena/sparql/service/single/ServiceExecutor.java
@@ -16,7 +16,7 @@
* limitations under the License.
*/
-package org.apache.jena.sparql.service;
+package org.apache.jena.sparql.service.single;
import org.apache.jena.sparql.algebra.op.OpService;
import org.apache.jena.sparql.engine.ExecutionContext;
@@ -24,15 +24,15 @@ import org.apache.jena.sparql.engine.QueryIterator;
import org.apache.jena.sparql.engine.binding.Binding;
/**
- * Interface for custom handling of service execution requests.
+ * Interface for handling service execution requests on a per-binding level.
*/
@FunctionalInterface
-public interface ServiceExecutorFactory {
+public interface ServiceExecutor {
/**
* If this factory cannot handle the execution request then this method should return null.
- * Otherwise, a {@link ServiceExecution} with the corresponding {@link QueryIterator} is returned.
+ * Otherwise, a {@link QueryIterator} is returned.
*
* @return A QueryIterator if this factory can handle the request, or null otherwise.
*/
- public ServiceExecution createExecutor(OpService opExecute, OpService original, Binding binding, ExecutionContext execCxt);
+ public QueryIterator createExecution(OpService opExecute, OpService original, Binding binding, ExecutionContext execCxt);
}
diff --git a/jena-arq/src/main/java/org/apache/jena/sparql/service/ServiceExecutorFactory.java b/jena-arq/src/main/java/org/apache/jena/sparql/service/single/ServiceExecutorDecorator.java
similarity index 58%
copy from jena-arq/src/main/java/org/apache/jena/sparql/service/ServiceExecutorFactory.java
copy to jena-arq/src/main/java/org/apache/jena/sparql/service/single/ServiceExecutorDecorator.java
index ee55d7a45b..f5db12bf7e 100644
--- a/jena-arq/src/main/java/org/apache/jena/sparql/service/ServiceExecutorFactory.java
+++ b/jena-arq/src/main/java/org/apache/jena/sparql/service/single/ServiceExecutorDecorator.java
@@ -16,23 +16,29 @@
* limitations under the License.
*/
-package org.apache.jena.sparql.service;
+package org.apache.jena.sparql.service.single;
import org.apache.jena.sparql.algebra.op.OpService;
import org.apache.jena.sparql.engine.ExecutionContext;
import org.apache.jena.sparql.engine.QueryIterator;
import org.apache.jena.sparql.engine.binding.Binding;
-/**
- * Interface for custom handling of service execution requests.
- */
-@FunctionalInterface
-public interface ServiceExecutorFactory {
- /**
- * If this factory cannot handle the execution request then this method should return null.
- * Otherwise, a {@link ServiceExecution} with the corresponding {@link QueryIterator} is returned.
- *
- * @return A QueryIterator if this factory can handle the request, or null otherwise.
- */
- public ServiceExecution createExecutor(OpService opExecute, OpService original, Binding binding, ExecutionContext execCxt);
+/** Form a service executor from a base service executor and a 'chain' that acts as a decorator */
+public class ServiceExecutorDecorator
+ implements ServiceExecutor
+{
+ protected ServiceExecutor base;
+ protected ChainingServiceExecutor decorator;
+
+ public ServiceExecutorDecorator(ServiceExecutor base, ChainingServiceExecutor decorator) {
+ super();
+ this.base = base;
+ this.decorator = decorator;
+ }
+
+ @Override
+ public QueryIterator createExecution(OpService opExecute, OpService original, Binding binding,
+ ExecutionContext execCxt) {
+ return decorator.createExecution(opExecute, original, binding, execCxt, base);
+ }
}
diff --git a/jena-arq/src/main/java/org/apache/jena/sparql/service/single/ServiceExecutorHttp.java b/jena-arq/src/main/java/org/apache/jena/sparql/service/single/ServiceExecutorHttp.java
new file mode 100644
index 0000000000..89e92e69c8
--- /dev/null
+++ b/jena-arq/src/main/java/org/apache/jena/sparql/service/single/ServiceExecutorHttp.java
@@ -0,0 +1,72 @@
+/*
+ * 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.sparql.service.single;
+
+import org.apache.jena.atlas.logging.Log;
+import org.apache.jena.query.QueryExecException;
+import org.apache.jena.riot.out.NodeFmtLib;
+import org.apache.jena.sparql.algebra.op.OpService;
+import org.apache.jena.sparql.engine.ExecutionContext;
+import org.apache.jena.sparql.engine.QueryIterator;
+import org.apache.jena.sparql.engine.binding.Binding;
+import org.apache.jena.sparql.engine.iterator.QueryIter;
+import org.apache.jena.sparql.engine.iterator.QueryIterCommonParent;
+import org.apache.jena.sparql.engine.iterator.QueryIterSingleton;
+import org.apache.jena.sparql.exec.http.Service;
+import org.apache.jena.sparql.util.Context;
+
+/** The default HTTP service executor implementation */
+public class ServiceExecutorHttp
+ implements ServiceExecutor
+{
+ @Override
+ public QueryIterator createExecution(OpService opExecute, OpService opOriginal, Binding binding,
+ ExecutionContext execCxt) {
+
+ Context context = execCxt.getContext();
+ if ( context.isFalse(Service.httpServiceAllowed) )
+ throw new QueryExecException("SERVICE not allowed") ;
+ // Old name.
+ if ( context.isFalse(Service.serviceAllowed) )
+ throw new QueryExecException("SERVICE not allowed") ;
+
+ boolean silent = opExecute.getSilent();
+
+ try {
+ QueryIterator qIter = Service.exec(opExecute, context);
+
+ // ---- Execute
+ if ( qIter == null )
+ throw new QueryExecException("No SERVICE handler");
+
+ qIter = QueryIter.makeTracked(qIter, execCxt);
+ // Need to put the outerBinding as parent to every binding of the service call.
+ // There should be no variables in common because of the OpSubstitute.substitute
+ return new QueryIterCommonParent(qIter, binding, execCxt);
+ } catch (RuntimeException ex) {
+ if ( silent ) {
+ Log.warn(this, "SERVICE " + NodeFmtLib.strTTL(opExecute.getService()) + " : " + ex.getMessage());
+ // Return the input
+ return QueryIterSingleton.create(binding, execCxt);
+
+ }
+ throw ex;
+ }
+ }
+}
diff --git a/jena-arq/src/main/java/org/apache/jena/sparql/service/single/ServiceExecutorOverRegistry.java b/jena-arq/src/main/java/org/apache/jena/sparql/service/single/ServiceExecutorOverRegistry.java
new file mode 100644
index 0000000000..d9d55f01c1
--- /dev/null
+++ b/jena-arq/src/main/java/org/apache/jena/sparql/service/single/ServiceExecutorOverRegistry.java
@@ -0,0 +1,69 @@
+/*
+ * 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.sparql.service.single;
+
+import java.util.List;
+
+import org.apache.jena.query.QueryException;
+import org.apache.jena.sparql.algebra.op.OpService;
+import org.apache.jena.sparql.engine.ExecutionContext;
+import org.apache.jena.sparql.engine.QueryIterator;
+import org.apache.jena.sparql.engine.binding.Binding;
+import org.apache.jena.sparql.engine.iterator.QueryIterRoot;
+import org.apache.jena.sparql.service.ServiceExecutorRegistry;
+
+/** Abstraction of a registry's single chain as a service executor */
+public class ServiceExecutorOverRegistry
+ implements ServiceExecutor
+{
+ protected ServiceExecutorRegistry registry;
+
+ /** Position in the chain */
+ protected int pos;
+
+ public ServiceExecutorOverRegistry(ServiceExecutorRegistry registry) {
+ this(registry, 0);
+ }
+
+ public ServiceExecutorOverRegistry(ServiceExecutorRegistry registry, int pos) {
+ super();
+ this.registry = registry;
+ this.pos = pos;
+ }
+
+ @Override
+ public QueryIterator createExecution(OpService opExecute, OpService original, Binding binding, ExecutionContext execCxt) {
+ List<ChainingServiceExecutor> factories = registry.getSingleChain();
+ int n = factories.size();
+ if (pos >= n) {
+ if (opExecute.getSilent()) {
+ return QueryIterRoot.create(execCxt);
+ } else {
+ throw new QueryException("No more elements in service executor chain (pos=" + pos + ", chain size=" + n + ")");
+ }
+ }
+
+ ChainingServiceExecutor factory = factories.get(pos);
+
+ ServiceExecutor next = new ServiceExecutorOverRegistry(registry, pos + 1);
+ QueryIterator result = factory.createExecution(opExecute, original, binding, execCxt, next);
+
+ return result;
+ }
+}
diff --git a/jena-examples/src/main/java/arq/examples/service/CustomServiceExecutor.java b/jena-examples/src/main/java/arq/examples/service/CustomServiceExecutor.java
index da95fd5596..cc21c622f4 100644
--- a/jena-examples/src/main/java/arq/examples/service/CustomServiceExecutor.java
+++ b/jena-examples/src/main/java/arq/examples/service/CustomServiceExecutor.java
@@ -18,25 +18,24 @@
package arq.examples.service;
-import java.util.Collections;
-
import org.apache.jena.graph.Node;
import org.apache.jena.graph.NodeFactory;
import org.apache.jena.query.ARQ;
import org.apache.jena.query.Dataset;
import org.apache.jena.query.DatasetFactory;
import org.apache.jena.sparql.algebra.op.OpService;
-import org.apache.jena.sparql.engine.iterator.QueryIterPlainWrapper;
+import org.apache.jena.sparql.engine.iterator.QueryIterRoot;
import org.apache.jena.sparql.exec.QueryExec;
import org.apache.jena.sparql.exec.QueryExecDatasetBuilder;
-import org.apache.jena.sparql.service.ServiceExecutorFactory;
import org.apache.jena.sparql.service.ServiceExecutorRegistry;
+import org.apache.jena.sparql.service.single.ChainingServiceExecutor;
+import org.apache.jena.sparql.service.single.ServiceExecutor;
import org.apache.jena.sparql.util.Context;
import org.apache.jena.sparql.util.QueryExecUtils;
public class CustomServiceExecutor {
- /** Query for resources having the label "Apache Jena"en */
+ /** Query for resources having the label "Apache Jena"en */
public static final String QUERY_STR = String.join("\n",
"PREFIX wd: <http://www.wikidata.org/entity/>",
"PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>",
@@ -49,11 +48,15 @@ public class CustomServiceExecutor {
" }",
"}");
+ public static final Node WIKIDATA = NodeFactory.createURI("http://query.wikidata.org/sparql");
+ public static final Node DBPEDIA = NodeFactory.createURI("http://dbpedia.org/sparql");
+
public static void main(String[] args) {
Dataset dataset = DatasetFactory.empty();
conventionalExec(dataset);
+ relayWikidataToDBpediaChaining(dataset);
relayWikidataToDBpedia(dataset);
suppressRemoteRequests(dataset);
}
@@ -71,21 +74,43 @@ public class CustomServiceExecutor {
*/
}
- /** Relay requests for Wikidata to DBpedia instead */
- public static void relayWikidataToDBpedia(Dataset dataset) {
- Node WIKIDATA = NodeFactory.createURI("http://query.wikidata.org/sparql");
- Node DBPEDIA = NodeFactory.createURI("http://dbpedia.org/sparql");
+ /** Relay requests for Wikidata to DBpedia instead. Modern variant using chaining. */
+ public static void relayWikidataToDBpediaChaining(Dataset dataset) {
+ ChainingServiceExecutor relaySef = (opExecute, original, binding, execCxt, chain) -> {
+ if (opExecute.getService().equals(WIKIDATA)) {
+ opExecute = new OpService(DBPEDIA, opExecute.getSubOp(), opExecute.getSilent());
+ }
+ return chain.createExecution(opExecute, original, binding, execCxt);
+ };
+
+ Context cxt = ARQ.getContext().copy();
+ ServiceExecutorRegistry registry = ServiceExecutorRegistry.get(cxt).copy();
+ registry.addSingleLink(relaySef);
+
+ ServiceExecutorRegistry.set(cxt, registry);
+ execQueryAndShowResult(dataset, QUERY_STR, cxt);
+
+ /*
+ * -------------------
+ * | s |
+ * ===================
+ * | dbr:Apache_Jena |
+ * -------------------
+ */
+ }
- ServiceExecutorFactory relaySef = (opExecute, original, binding, execCxt) -> {
+ /** Relay requests for Wikidata to DBpedia instead. Non-chaining legacy variant. */
+ public static void relayWikidataToDBpedia(Dataset dataset) {
+ ServiceExecutor relaySef = (opExecute, original, binding, execCxt) -> {
if (opExecute.getService().equals(WIKIDATA)) {
opExecute = new OpService(DBPEDIA, opExecute.getSubOp(), opExecute.getSilent());
- return ServiceExecutorRegistry.httpService.createExecutor(opExecute, original, binding, execCxt);
+ return ServiceExecutorRegistry.httpService.createExecution(opExecute, original, binding, execCxt);
}
return null;
};
Context cxt = ARQ.getContext().copy();
- ServiceExecutorRegistry registry = new ServiceExecutorRegistry();
+ ServiceExecutorRegistry registry = ServiceExecutorRegistry.get(cxt).copy();
registry.add(relaySef);
ServiceExecutorRegistry.set(cxt, registry);
@@ -102,8 +127,7 @@ public class CustomServiceExecutor {
/** Suppress remote requests - make any SERVICE request return the input binding */
public static void suppressRemoteRequests(Dataset dataset) {
- ServiceExecutorFactory noop = (opExecute, original, binding, execCxt) ->
- () -> QueryIterPlainWrapper.create(Collections.singleton(binding).iterator());
+ ServiceExecutor noop = (opExecute, original, binding, execCxt) -> QueryIterRoot.create(execCxt);
Context cxt = ARQ.getContext().copy();
ServiceExecutorRegistry registry = new ServiceExecutorRegistry();
diff --git a/jena-integration-tests/src/test/java/org/apache/jena/sparql/exec/http/TestService.java b/jena-integration-tests/src/test/java/org/apache/jena/sparql/exec/http/TestService.java
index 0d27915d94..eb29b989d6 100644
--- a/jena-integration-tests/src/test/java/org/apache/jena/sparql/exec/http/TestService.java
+++ b/jena-integration-tests/src/test/java/org/apache/jena/sparql/exec/http/TestService.java
@@ -46,7 +46,7 @@ import org.apache.jena.sparql.core.DatasetGraphZero;
import org.apache.jena.sparql.engine.QueryIterator;
import org.apache.jena.sparql.engine.binding.Binding;
import org.apache.jena.sparql.engine.http.QueryExceptionHTTP;
-import org.apache.jena.sparql.engine.main.iterator.QueryIterService;
+import org.apache.jena.sparql.service.ServiceExecutorRegistry;
import org.apache.jena.sparql.exec.QueryExec;
import org.apache.jena.sparql.exec.RowSet;
import org.apache.jena.sparql.sse.SSE;
@@ -108,7 +108,7 @@ public class TestService {
}
// Remember the initial settings.
- static String logLevelQueryIterService = LogCtl.getLevel(QueryIterService.class);
+ static String logLevelQueryIterService = LogCtl.getLevel(ServiceExecutorRegistry.class);
static String logLevelFuseki = LogCtl.getLevel(Fuseki.class);
@BeforeClass public static void beforeClass() {
@@ -185,7 +185,7 @@ public class TestService {
}
@Test public void service_query_silent_no_service() {
- logOnlyErrors(QueryIterService.class, ()->{
+ logOnlyErrors(ServiceExecutorRegistry.class, ()->{
DatasetGraph dsg = env.dsg();
String queryString = "SELECT * { SERVICE SILENT <"+SERVICE+"JUNK> { VALUES ?X { 1 2 } }} ";
try ( RDFLink link = RDFLinkFactory.connect(localDataset()) ) {
@@ -201,7 +201,7 @@ public class TestService {
}
@Test public void service_query_silent_nosite() {
- logOnlyErrors(QueryIterService.class, ()->{
+ logOnlyErrors(ServiceExecutorRegistry.class, ()->{
DatasetGraph dsg = env.dsg();
String queryString = "SELECT * { SERVICE SILENT <http://nosuchsite/> { VALUES ?X { 1 2 } }} ";
try ( RDFLink link = RDFLinkFactory.connect(localDataset()) ) {
diff --git a/jena-integration-tests/src/test/java/org/apache/jena/test/service/TestCustomServiceExecutor.java b/jena-integration-tests/src/test/java/org/apache/jena/test/service/TestCustomServiceExecutor.java
index 97b01f401e..144547f6b9 100644
--- a/jena-integration-tests/src/test/java/org/apache/jena/test/service/TestCustomServiceExecutor.java
+++ b/jena-integration-tests/src/test/java/org/apache/jena/test/service/TestCustomServiceExecutor.java
@@ -32,10 +32,9 @@ import org.apache.jena.riot.resultset.ResultSetLang;
import org.apache.jena.sparql.algebra.Table;
import org.apache.jena.sparql.core.Var;
import org.apache.jena.sparql.engine.binding.Binding;
-import org.apache.jena.sparql.engine.main.iterator.QueryIterService;
import org.apache.jena.sparql.resultset.ResultSetCompare;
-import org.apache.jena.sparql.service.ServiceExecutorFactory;
import org.apache.jena.sparql.service.ServiceExecutorRegistry;
+import org.apache.jena.sparql.service.single.ServiceExecutor;
import org.apache.jena.sparql.sse.SSE;
import org.junit.Assert;
import org.junit.Test;
@@ -46,15 +45,16 @@ public class TestCustomServiceExecutor {
/** A custom service factory that yields the above table for any request
* to urn:customService */
- static ServiceExecutorFactory factory = (op, opOriginal, binding, execCxt) ->
+ static ServiceExecutor factory = (op, opOriginal, binding, execCxt) ->
op.getService().getURI().equals("urn:customService")
- ? ()->table.iterator(execCxt)
+ ? table.iterator(execCxt)
: null;
static ServiceExecutorRegistry customRegistry = new ServiceExecutorRegistry().add(factory);
@Test
public void testGlobalServiceExecutorRegistry() {
+ int sizeBefore = ServiceExecutorRegistry.get().getSingleChain().size();
ServiceExecutorRegistry.get().add(factory);
try {
@@ -62,6 +62,10 @@ public class TestCustomServiceExecutor {
} finally {
// Better eventually remove the global registration
ServiceExecutorRegistry.get().remove(factory);
+ int sizeAfter = ServiceExecutorRegistry.get().getSingleChain().size();
+
+ // Perform a sanity check
+ Assert.assertEquals("Removal of a registration failed", sizeBefore, sizeAfter);
}
}
@@ -98,7 +102,7 @@ public class TestCustomServiceExecutor {
*/
@Test
public void testIllegalServiceIri2() {
- Class<?> logClass = QueryIterService.class;
+ Class<?> logClass = ServiceExecutorRegistry.class;
String logLevel = LogCtl.getLevel(logClass);
try {
LogCtl.setLevel(logClass, "ERROR");
diff --git a/jena-integration-tests/src/test/java/org/apache/jena/test/service/TestServiceExec.java b/jena-integration-tests/src/test/java/org/apache/jena/test/service/TestServiceExec.java
index cc5d30c610..0077034429 100644
--- a/jena-integration-tests/src/test/java/org/apache/jena/test/service/TestServiceExec.java
+++ b/jena-integration-tests/src/test/java/org/apache/jena/test/service/TestServiceExec.java
@@ -27,7 +27,7 @@ import org.apache.jena.query.*;
import org.apache.jena.sparql.core.DatasetGraph;
import org.apache.jena.sparql.core.DatasetGraphFactory;
import org.apache.jena.sparql.engine.http.QueryExceptionHTTP;
-import org.apache.jena.sparql.engine.main.iterator.QueryIterService;
+import org.apache.jena.sparql.service.ServiceExecutorRegistry;
import org.apache.jena.sparql.sse.SSE;
import org.junit.BeforeClass;
import org.junit.Test;
@@ -72,7 +72,7 @@ public class TestServiceExec {
@Test
public void service_exec_3() {
- Class<?> logClass = QueryIterService.class;
+ Class<?> logClass = ServiceExecutorRegistry.class;
String logLevel = LogCtl.getLevel(logClass);
try {
LogCtl.setLevel(logClass, "ERROR");