blob: 29509743d066df0e2ba90352fcf5c70bddc860d1 [file] [log] [blame]
/*
* 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;
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.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;
/**
* 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 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()
{
ServiceExecutorRegistry reg = get(ARQ.getContext()) ;
return reg ;
}
/** 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();
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
ServiceExecutorRegistry reg = get(ARQ.getContext()) ;
if ( reg == null )
{
init() ;
reg = get(ARQ.getContext()) ;
}
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 )
return null ;
return (ServiceExecutorRegistry)context.get(ARQConstants.registryServiceExecutors) ;
}
public static void set(Context context, ServiceExecutorRegistry reg)
{
context.set(ARQConstants.registryServiceExecutors, reg) ;
}
/**
* Copies the origin registry into a new one, or makes a fresh instance if the specified registry is {@code null}.
* @param from {@link ServiceExecutorRegistry} or {@code null}
* @return {@link ServiceExecutorRegistry} a new instance
*/
public static ServiceExecutorRegistry createFrom(ServiceExecutorRegistry from) {
ServiceExecutorRegistry res = new ServiceExecutorRegistry();
if (from != null) {
res.bulkChain.addAll(from.bulkChain);
res.singleChain.addAll(from.singleChain);
}
return res;
}
public ServiceExecutorRegistry()
{}
/*
* 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));
}
/** 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) ;
bulkChain.add(0, f) ;
return this;
}
/** Remove the given service executor */
public ServiceExecutorRegistry removeBulkLink(ChainingServiceExecutorBulk f) {
bulkChain.remove(f) ;
return this;
}
/** Retrieve the actual list of bulk executors; allows for re-ordering */
public List<ChainingServiceExecutorBulk> getBulkChain() {
return bulkChain;
}
/*
* 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
* @deprecated To be removed. Moved to {@link ServiceExec#exec}.
*/
@Deprecated(forRemoval = true, since = "4.9.0")
public static QueryIterator exec(QueryIterator input, OpService opService, ExecutionContext execCxt) {
return ServiceExec.exec(input, opService, execCxt);
}
}