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/05 12:06:15 UTC

[jena] branch main updated: gh-1407: Support for context-local QueryEngineRegistries

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 9d089e8d3f gh-1407: Support for context-local QueryEngineRegistries
     new a5678f850c Merge pull request #1392 from Aklakan/queryengineregistry
9d089e8d3f is described below

commit 9d089e8d3f0744e666263f56a3ad2a18dd3a949d
Author: Claus Stadler <Ra...@googlemail.com>
AuthorDate: Sun Jun 19 17:10:14 2022 +0200

    gh-1407: Support for context-local QueryEngineRegistries
---
 .../apache/jena/query/QueryExecutionFactory.java   |  2 +-
 .../java/org/apache/jena/sparql/ARQConstants.java  |  4 +
 .../jena/sparql/engine/QueryEngineRegistry.java    | 48 ++++++++++-
 .../jena/sparql/exec/QueryExecDatasetBuilder.java  |  2 +-
 .../sparql/engine/TestQueryEngineFromContext.java  | 99 ++++++++++++++++++++++
 5 files changed, 150 insertions(+), 5 deletions(-)

diff --git a/jena-arq/src/main/java/org/apache/jena/query/QueryExecutionFactory.java b/jena-arq/src/main/java/org/apache/jena/query/QueryExecutionFactory.java
index fbad883b65..258864b93e 100644
--- a/jena-arq/src/main/java/org/apache/jena/query/QueryExecutionFactory.java
+++ b/jena-arq/src/main/java/org/apache/jena/query/QueryExecutionFactory.java
@@ -436,7 +436,7 @@ public class QueryExecutionFactory
             context = new Context(ARQ.getContext());
         if ( input == null )
             input = BindingRoot.create();
-        QueryEngineFactory f = QueryEngineRegistry.get().find(query, dataset, context);
+        QueryEngineFactory f = QueryEngineRegistry.findFactory(query, dataset, context);
         if ( f == null )
             return null;
         return f.create(query, dataset, input, context);
diff --git a/jena-arq/src/main/java/org/apache/jena/sparql/ARQConstants.java b/jena-arq/src/main/java/org/apache/jena/sparql/ARQConstants.java
index 08e1d90685..d534025682 100644
--- a/jena-arq/src/main/java/org/apache/jena/sparql/ARQConstants.java
+++ b/jena-arq/src/main/java/org/apache/jena/sparql/ARQConstants.java
@@ -284,6 +284,10 @@ public class ARQConstants
     public static final Symbol registryDescribeHandlers =
         SystemARQ.allocSymbol("registryDescribeHandlers") ;
 
+    /** The query engine registry key */
+    public static final Symbol registryQueryEngines =
+        SystemARQ.allocSymbol("registryQueryEngines") ;
+
     /** The function library registry key */
     public static final Symbol registryFunctions =
         SystemARQ.allocSymbol("registryFunctions") ;
diff --git a/jena-arq/src/main/java/org/apache/jena/sparql/engine/QueryEngineRegistry.java b/jena-arq/src/main/java/org/apache/jena/sparql/engine/QueryEngineRegistry.java
index 8439fa8bcb..9969b6f619 100644
--- a/jena-arq/src/main/java/org/apache/jena/sparql/engine/QueryEngineRegistry.java
+++ b/jena-arq/src/main/java/org/apache/jena/sparql/engine/QueryEngineRegistry.java
@@ -22,6 +22,7 @@ import java.util.ArrayList;
 import java.util.List;
 
 import org.apache.jena.query.Query;
+import org.apache.jena.sparql.ARQConstants;
 import org.apache.jena.sparql.algebra.Op;
 import org.apache.jena.sparql.core.DatasetGraph;
 import org.apache.jena.sparql.engine.main.QueryEngineMain;
@@ -42,7 +43,48 @@ public class QueryEngineRegistry
         return registry;
     }
 
-    private QueryEngineRegistry() { }
+    /** If there is a registry in the context then return it otherwise yield the global instance */
+    static public QueryEngineRegistry chooseRegistry(Context context)
+    {
+        QueryEngineRegistry result = get(context);
+        if (result == null) {
+            result = get();
+        }
+        return result;
+    }
+
+    /** Get the query engine registry from the context or null if there is none.
+     *  Returns null if the context is null. */
+    static public QueryEngineRegistry get(Context context)
+    {
+        QueryEngineRegistry result = context == null
+                ? null
+                : context.get(ARQConstants.registryQueryEngines);
+        return result;
+    }
+
+    static public void set(Context context, QueryEngineRegistry registry)
+    {
+        context.set(ARQConstants.registryQueryEngines, registry);
+    }
+
+    public QueryEngineRegistry copy() {
+        QueryEngineRegistry result = new QueryEngineRegistry();
+        result.factories.addAll(factories);
+        return result;
+    }
+
+    /** Create a copy of the registry from the context or return a new instance */
+    public static QueryEngineRegistry copyFrom(Context context) {
+        QueryEngineRegistry tmp = get(context);
+        QueryEngineRegistry result = tmp != null
+                ? tmp.copy()
+                : new QueryEngineRegistry();
+
+        return result;
+    }
+
+    public QueryEngineRegistry() { }
 
     private static synchronized void init()
     {
@@ -59,7 +101,7 @@ public class QueryEngineRegistry
      */
 
     public static QueryEngineFactory findFactory(Query query, DatasetGraph dataset, Context context)
-    { return get().find(query, dataset, context); }
+    { return chooseRegistry(context).find(query, dataset, context); }
 
     /** Locate a suitable factory for this algebra expression
      *  and dataset from the default registry
@@ -71,7 +113,7 @@ public class QueryEngineRegistry
      */
 
     public static QueryEngineFactory findFactory(Op op, DatasetGraph dataset, Context context)
-    { return get().find(op, dataset, context); }
+    { return chooseRegistry(context).find(op, dataset, context); }
 
     /** Locate a suitable factory for this query and dataset
      *
diff --git a/jena-arq/src/main/java/org/apache/jena/sparql/exec/QueryExecDatasetBuilder.java b/jena-arq/src/main/java/org/apache/jena/sparql/exec/QueryExecDatasetBuilder.java
index 6553769e97..71b4622aa7 100644
--- a/jena-arq/src/main/java/org/apache/jena/sparql/exec/QueryExecDatasetBuilder.java
+++ b/jena-arq/src/main/java/org/apache/jena/sparql/exec/QueryExecDatasetBuilder.java
@@ -220,7 +220,7 @@ public class QueryExecDatasetBuilder implements QueryExecMod, QueryExecBuilder {
         query.setResultVars();
         Context cxt = getContext();
 
-        QueryEngineFactory qeFactory = QueryEngineRegistry.get().find(query, dataset, cxt);
+        QueryEngineFactory qeFactory = QueryEngineRegistry.findFactory(query, dataset, cxt);
         if ( qeFactory == null ) {
             Log.warn(QueryExecDatasetBuilder.class, "Failed to find a QueryEngineFactory");
             return null;
diff --git a/jena-arq/src/test/java/org/apache/jena/sparql/engine/TestQueryEngineFromContext.java b/jena-arq/src/test/java/org/apache/jena/sparql/engine/TestQueryEngineFromContext.java
new file mode 100644
index 0000000000..fa5d1faaab
--- /dev/null
+++ b/jena-arq/src/test/java/org/apache/jena/sparql/engine/TestQueryEngineFromContext.java
@@ -0,0 +1,99 @@
+/**
+ * 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.engine;
+
+import java.util.Collections;
+import java.util.Iterator;
+
+import org.apache.jena.graph.Node;
+import org.apache.jena.graph.NodeFactory;
+import org.apache.jena.query.Dataset;
+import org.apache.jena.query.DatasetFactory;
+import org.apache.jena.query.QueryExecution;
+import org.apache.jena.query.QueryExecutionFactory;
+import org.apache.jena.query.ResultSetFormatter;
+import org.apache.jena.sparql.core.DatasetGraph;
+import org.apache.jena.sparql.core.DatasetGraphMap;
+import org.apache.jena.sparql.core.Quad;
+import org.apache.jena.sparql.engine.main.QC;
+import org.apache.jena.sparql.engine.main.QueryEngineMainQuad;
+import org.apache.jena.sparql.engine.main.solver.OpExecutorQuads;
+import org.apache.jena.sparql.util.Context;
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * The default query engine evaluates GRAPH ?g { ?s ?p ?o } with
+ * a call to listGraphNodes() which suppresses calls to find(g, s, p, o).
+ * Custom query engines may be able to use indices within find() to
+ * efficiently determine candidate graphs.
+ *
+ * This class tests registration of a custom query engine factory.
+ *
+ */
+public class TestQueryEngineFromContext {
+
+    private class DatasetGraphForTesting
+        extends DatasetGraphMap
+    {
+        @Override
+        public Iterator<Quad> find(Node g, Node s, Node p, Node o) {
+            Node x = NodeFactory.createURI("urn:x");
+            return Collections.singleton(Quad.create(x, x, x, x)).iterator();
+        }
+
+        @Override
+        public Iterator<Node> listGraphNodes() {
+            throw new UnsupportedOperationException("Evaluation of 'GRAPH ?g { ?s ?p ?o }' using QueryEngineMainQuad"
+                    + "with OpExecutorQuads must not result in listGraphNodes to be called");
+        }
+    }
+
+    @Test(expected = UnsupportedOperationException.class)
+    public void testWithDefaultQueryEngine() {
+        DatasetGraph testSetup = new DatasetGraphForTesting();
+        Dataset ds = DatasetFactory.wrap(testSetup);
+
+        try (QueryExecution qe = QueryExecutionFactory.create("SELECT * { GRAPH ?g { ?s ?p ?o } }", ds)) {
+            // Expected to fail with default query engine
+            ResultSetFormatter.consume(qe.execSelect());
+        }
+    }
+
+    @Test
+    public void testWithCustomQueryEngine() {
+
+        DatasetGraph testSetup = new DatasetGraphForTesting();
+        Dataset ds = DatasetFactory.wrap(testSetup);
+
+        try (QueryExecution qe = QueryExecutionFactory.create("SELECT * { GRAPH ?g { ?s ?p ?o } }", ds)) {
+            Context cxt = qe.getContext();
+            QC.setFactory(cxt, OpExecutorQuads::new);
+
+            QueryEngineRegistry reg = new QueryEngineRegistry();
+            reg.add(QueryEngineMainQuad.getFactory());
+            QueryEngineRegistry.set(cxt, reg);
+
+
+            int rows = ResultSetFormatter.consume(qe.execSelect());
+            Assert.assertEquals(1, rows);
+        }
+    }
+
+}