Add DOMDataTreeQueryOperations 48/93348/3
authorRobert Varga <robert.varga@pantheon.tech>
Sun, 25 Oct 2020 17:17:42 +0000 (18:17 +0100)
committerRobert Varga <robert.varga@pantheon.tech>
Mon, 26 Oct 2020 00:42:48 +0000 (01:42 +0100)
DOMDataTreeQueryOperations exposes the ability to execute queries
on the backing datastore, much like one would execute a read.

mdsal-binding-dom-adapter is taught to recognize the interface and
use it to offload execution deeper. It still falls back to its
evaluation should the backing store not support this.

DOMStoreReadTransaction gained the ability to value expressions,
using a default implementation based om DOMQueryEvaluator.

Based on that capability, mdsal-dom-broker's transactions are
retrofitted to always provide evaluation locally.

JIRA: MDSAL-607
Change-Id: Ia20acf59870f47c8a84914e239dee82e2a56c1bb
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
binding/mdsal-binding-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/dom/adapter/AbstractForwardedTransaction.java
dom/mdsal-dom-api/src/main/java/org/opendaylight/mdsal/dom/api/DOMDataTreeQueryOperations.java [new file with mode: 0644]
dom/mdsal-dom-api/src/main/java/org/opendaylight/mdsal/dom/api/DOMDataTreeQueryReadTransaction.java [new file with mode: 0644]
dom/mdsal-dom-api/src/main/java/org/opendaylight/mdsal/dom/api/DOMDataTreeQueryReadWriteTransaction.java [new file with mode: 0644]
dom/mdsal-dom-broker/src/main/java/org/opendaylight/mdsal/dom/broker/DOMForwardedReadOnlyTransaction.java
dom/mdsal-dom-broker/src/main/java/org/opendaylight/mdsal/dom/broker/DOMForwardedReadWriteTransaction.java
dom/mdsal-dom-spi/src/main/java/org/opendaylight/mdsal/dom/spi/store/DOMStoreReadTransaction.java

index b7aa7da8cceaac61519ade547329f830938bd22a..7bcd2823daa7a14006e2c91dae36fb1e9e81e864 100644 (file)
@@ -19,9 +19,11 @@ import org.opendaylight.mdsal.binding.api.query.QueryExpression;
 import org.opendaylight.mdsal.binding.api.query.QueryResult;
 import org.opendaylight.mdsal.binding.dom.adapter.query.DefaultQuery;
 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
+import org.opendaylight.mdsal.dom.api.DOMDataTreeQueryOperations;
 import org.opendaylight.mdsal.dom.api.DOMDataTreeReadOperations;
 import org.opendaylight.mdsal.dom.api.DOMDataTreeTransaction;
 import org.opendaylight.mdsal.dom.api.query.DOMQuery;
+import org.opendaylight.mdsal.dom.api.query.DOMQueryResult;
 import org.opendaylight.mdsal.dom.spi.query.DOMQueryEvaluator;
 import org.opendaylight.mdsal.dom.spi.query.EagerDOMQueryResult;
 import org.opendaylight.yangtools.concepts.Delegator;
@@ -29,9 +31,12 @@ import org.opendaylight.yangtools.concepts.Identifiable;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 abstract class AbstractForwardedTransaction<T extends DOMDataTreeTransaction> implements Delegator<T>,
         Identifiable<Object> {
+    private static final Logger LOG = LoggerFactory.getLogger(AbstractForwardedTransaction.class);
 
     private final @NonNull AdapterContext adapterContext;
     private final @NonNull T delegate;
@@ -79,17 +84,26 @@ abstract class AbstractForwardedTransaction<T extends DOMDataTreeTransaction> im
         return readOps.exists(store, adapterContext.currentSerializer().toYangInstanceIdentifier(path));
     }
 
-    protected final <T extends @NonNull DataObject>  @NonNull FluentFuture<QueryResult<T>> doExecute(
+    protected final <T extends @NonNull DataObject> @NonNull FluentFuture<QueryResult<T>> doExecute(
             final DOMDataTreeReadOperations readOps, final @NonNull LogicalDatastoreType store,
             final @NonNull QueryExpression<T> query) {
         checkArgument(query instanceof DefaultQuery, "Unsupported query type %s", query);
         final DefaultQuery<T> defaultQuery = (DefaultQuery<T>) query;
 
-        final DOMQuery domQuery = defaultQuery.asDOMQuery();
+        final FluentFuture<DOMQueryResult> domResult = readOps instanceof DOMDataTreeQueryOperations
+            ? ((DOMDataTreeQueryOperations) readOps).execute(store, defaultQuery.asDOMQuery())
+                : fallbackExecute(readOps, store, defaultQuery.asDOMQuery());
+
+        return domResult.transform(defaultQuery::toQueryResult, MoreExecutors.directExecutor());
+    }
+
+    private static FluentFuture<DOMQueryResult> fallbackExecute(final @NonNull DOMDataTreeReadOperations readOps,
+            final @NonNull LogicalDatastoreType store, final @NonNull DOMQuery domQuery) {
+        LOG.trace("Fallback evaluation of {} on {}", domQuery, readOps);
         return readOps.read(store, domQuery.getRoot())
-            .transform(node -> node.map(
-                data -> DOMQueryEvaluator.evaluateOn(domQuery, data)).orElse(EagerDOMQueryResult.of()),
-                MoreExecutors.directExecutor())
-            .transform(defaultQuery::toQueryResult, MoreExecutors.directExecutor());
+            .transform(
+                node -> node.map(data -> DOMQueryEvaluator.evaluateOn(domQuery, data)).orElse(EagerDOMQueryResult.of()),
+                // TODO: execute on a dedicated thread pool
+                MoreExecutors.directExecutor());
     }
 }
diff --git a/dom/mdsal-dom-api/src/main/java/org/opendaylight/mdsal/dom/api/DOMDataTreeQueryOperations.java b/dom/mdsal-dom-api/src/main/java/org/opendaylight/mdsal/dom/api/DOMDataTreeQueryOperations.java
new file mode 100644 (file)
index 0000000..0cf2199
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2020 PANTHEON.tech, s.r.o. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.mdsal.dom.api;
+
+import com.google.common.annotations.Beta;
+import com.google.common.util.concurrent.FluentFuture;
+import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
+import org.opendaylight.mdsal.common.api.ReadFailedException;
+import org.opendaylight.mdsal.dom.api.query.DOMQuery;
+import org.opendaylight.mdsal.dom.api.query.DOMQueryResult;
+
+/**
+ * Query-like operations supported by {@link DOMDataTreeReadTransaction} and {@link DOMDataTreeReadWriteTransaction}.
+ * This interface defines the operations without a tie-in with lifecycle management.
+ */
+@Beta
+public interface DOMDataTreeQueryOperations {
+    /**
+     * Executes a query on the provided logical data store.
+     *
+     * @param store Logical data store from which read should occur.
+     * @param query DOMQuery to execute
+     * @return a FluentFuture containing the result of the query. The Future blocks until the operation is complete.
+     *         Once complete:
+     *         <ul>
+     *           <li>The Future returns the result of the query</li>
+     *           <li>If the query execution fails, the Future will fail with a {@link ReadFailedException} or
+     *               an exception derived from ReadFailedException.
+     *            </li>
+     *         </ul>
+     * @throws NullPointerException if any of the arguments is null
+     * @throws IllegalArgumentException if the query is not supported
+     */
+    FluentFuture<DOMQueryResult> execute(LogicalDatastoreType store, DOMQuery query);
+}
diff --git a/dom/mdsal-dom-api/src/main/java/org/opendaylight/mdsal/dom/api/DOMDataTreeQueryReadTransaction.java b/dom/mdsal-dom-api/src/main/java/org/opendaylight/mdsal/dom/api/DOMDataTreeQueryReadTransaction.java
new file mode 100644 (file)
index 0000000..d362714
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2020 PANTHEON.tech, s.r.o. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.mdsal.dom.api;
+
+import com.google.common.annotations.Beta;
+
+/**
+ * A {@link DOMDataTreeReadTransaction} which can also perform {@link DOMDataTreeQueryOperations}.
+ */
+@Beta
+public interface DOMDataTreeQueryReadTransaction extends DOMDataTreeReadTransaction, DOMDataTreeQueryOperations {
+
+}
diff --git a/dom/mdsal-dom-api/src/main/java/org/opendaylight/mdsal/dom/api/DOMDataTreeQueryReadWriteTransaction.java b/dom/mdsal-dom-api/src/main/java/org/opendaylight/mdsal/dom/api/DOMDataTreeQueryReadWriteTransaction.java
new file mode 100644 (file)
index 0000000..8d41e19
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2020 PANTHEON.tech, s.r.o. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.mdsal.dom.api;
+
+import com.google.common.annotations.Beta;
+
+/**
+ * A {@link DOMDataTreeReadWriteTransaction} which can also perform {@link DOMDataTreeQueryOperations}.
+ */
+@Beta
+public interface DOMDataTreeQueryReadWriteTransaction
+        extends DOMDataTreeReadWriteTransaction, DOMDataTreeQueryOperations {
+
+}
index a4cbd5d3d1e3e5519ae0932fee8a8b14b78831b3..76ef4ba8810458061d2c5aa167c4ee7ab8658d0f 100644 (file)
@@ -11,7 +11,9 @@ import com.google.common.util.concurrent.FluentFuture;
 import java.util.Map;
 import java.util.Optional;
 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
-import org.opendaylight.mdsal.dom.api.DOMDataTreeReadTransaction;
+import org.opendaylight.mdsal.dom.api.DOMDataTreeQueryReadTransaction;
+import org.opendaylight.mdsal.dom.api.query.DOMQuery;
+import org.opendaylight.mdsal.dom.api.query.DOMQueryResult;
 import org.opendaylight.mdsal.dom.spi.store.DOMStoreReadTransaction;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
@@ -22,9 +24,9 @@ import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
  * {@link LogicalDatastoreType} type parameter in
  * {@link #read(LogicalDatastoreType, YangInstanceIdentifier)}.
  */
-class DOMForwardedReadOnlyTransaction extends
-        AbstractDOMForwardedCompositeTransaction<LogicalDatastoreType, DOMStoreReadTransaction> implements
-        DOMDataTreeReadTransaction {
+class DOMForwardedReadOnlyTransaction
+        extends AbstractDOMForwardedCompositeTransaction<LogicalDatastoreType, DOMStoreReadTransaction>
+        implements DOMDataTreeQueryReadTransaction {
 
     protected DOMForwardedReadOnlyTransaction(final Object identifier,
             final Map<LogicalDatastoreType, DOMStoreReadTransaction> backingTxs) {
@@ -42,6 +44,11 @@ class DOMForwardedReadOnlyTransaction extends
         return getSubtransaction(store).exists(path);
     }
 
+    @Override
+    public FluentFuture<DOMQueryResult> execute(final LogicalDatastoreType store, final DOMQuery query) {
+        return getSubtransaction(store).execute(query);
+    }
+
     @Override
     public void close() {
         closeSubtransactions();
index d9205baef4222a53da3c66952e15d587c714725f..e1978dfd588d57d4422c03492bf9532ae30a4ac2 100644 (file)
@@ -11,7 +11,9 @@ import com.google.common.util.concurrent.FluentFuture;
 import java.util.Map;
 import java.util.Optional;
 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
-import org.opendaylight.mdsal.dom.api.DOMDataTreeReadWriteTransaction;
+import org.opendaylight.mdsal.dom.api.DOMDataTreeQueryReadWriteTransaction;
+import org.opendaylight.mdsal.dom.api.query.DOMQuery;
+import org.opendaylight.mdsal.dom.api.query.DOMQueryResult;
 import org.opendaylight.mdsal.dom.spi.store.DOMStoreReadWriteTransaction;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
@@ -36,7 +38,7 @@ import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
  * underlying transactions.
  */
 final class DOMForwardedReadWriteTransaction extends DOMForwardedWriteTransaction<DOMStoreReadWriteTransaction>
-        implements DOMDataTreeReadWriteTransaction {
+        implements DOMDataTreeQueryReadWriteTransaction {
 
     DOMForwardedReadWriteTransaction(final Object identifier,
         final Map<LogicalDatastoreType, DOMStoreReadWriteTransaction> backingTxs,
@@ -54,4 +56,9 @@ final class DOMForwardedReadWriteTransaction extends DOMForwardedWriteTransactio
     public FluentFuture<Boolean> exists(final LogicalDatastoreType store, final YangInstanceIdentifier path) {
         return getSubtransaction(store).exists(path);
     }
+
+    @Override
+    public FluentFuture<DOMQueryResult> execute(final LogicalDatastoreType store, final DOMQuery query) {
+        return getSubtransaction(store).execute(query);
+    }
 }
index 0b22cef46e1525cee889661a128ad288462bcf58..b5e41e3f74454fe3d809da9cc6c6c2603f3e4602 100644 (file)
@@ -8,8 +8,14 @@
 package org.opendaylight.mdsal.dom.spi.store;
 
 import com.google.common.util.concurrent.FluentFuture;
+import com.google.common.util.concurrent.MoreExecutors;
 import java.util.Optional;
+import org.eclipse.jdt.annotation.NonNull;
 import org.opendaylight.mdsal.common.api.ReadFailedException;
+import org.opendaylight.mdsal.dom.api.query.DOMQuery;
+import org.opendaylight.mdsal.dom.api.query.DOMQueryResult;
+import org.opendaylight.mdsal.dom.spi.query.DOMQueryEvaluator;
+import org.opendaylight.mdsal.dom.spi.query.EagerDOMQueryResult;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
 
@@ -55,4 +61,30 @@ public interface DOMStoreReadTransaction extends DOMStoreTransaction {
      *         </ul>
      */
     FluentFuture<Boolean> exists(YangInstanceIdentifier path);
+
+    /**
+     * Executes a query on the provided logical data store.
+     *
+     * <p>
+     * Default operation invokes {@code read(query.getRoot())} and then executes the result with
+     * {@link DOMQueryEvaluator}. Implementations are encouraged to provide a more efficient implementation as
+     * appropriate.
+     *
+     * @param query DOMQuery to execute
+     * @return a FluentFuture containing the result of the query. The Future blocks until the operation is complete.
+     *         Once complete:
+     *         <ul>
+     *           <li>The Future returns the result of the query</li>
+     *           <li>If the query execution fails, the Future will fail with a {@link ReadFailedException} or
+     *               an exception derived from ReadFailedException.
+     *            </li>
+     *         </ul>
+     * @throws NullPointerException if any of the arguments is null
+     * @throws IllegalArgumentException if the query is not supported
+     */
+    default @NonNull FluentFuture<DOMQueryResult> execute(final DOMQuery query) {
+        return read(query.getRoot()).transform(
+            node -> node.map(data -> DOMQueryEvaluator.evaluateOn(query, data)).orElse(EagerDOMQueryResult.of()),
+            MoreExecutors.directExecutor());
+    }
 }