Simplify DOMOperation{Service,Implementation} 22/74022/7
authorRobert Varga <robert.varga@pantheon.tech>
Fri, 13 Jul 2018 13:25:29 +0000 (15:25 +0200)
committerRobert Varga <robert.varga@pantheon.tech>
Fri, 13 Jul 2018 16:38:16 +0000 (18:38 +0200)
In order to seamlessly bridge Binding->DOM->Binding invocation
without incurring thread safety hits we need to have a way
for the operation implementations to give us a handle.

We therefore should not be bridging the result through a callback,
but rather via a FluentFuture -- eliminate DOMOperationCallback
and make the former bridge methods the only API.

Change-Id: I3d1064b95ca65b44909b27bf028d050594ecbee7
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
dom/mdsal-dom-api/src/main/java/org/opendaylight/mdsal/dom/api/DOMOperationAvailabilityExtension.java
dom/mdsal-dom-api/src/main/java/org/opendaylight/mdsal/dom/api/DOMOperationCallback.java [deleted file]
dom/mdsal-dom-api/src/main/java/org/opendaylight/mdsal/dom/api/DOMOperationImplementation.java
dom/mdsal-dom-api/src/main/java/org/opendaylight/mdsal/dom/api/DOMOperationService.java
dom/mdsal-dom-spi/src/main/java/org/opendaylight/mdsal/dom/spi/SimpleDOMOperationResult.java [new file with mode: 0644]

index 899868a8ef729b870eef5f7a89b98a899088d1eb..b3c8ecb3dc709df8fab35a809800a23d4ac7fb08 100644 (file)
@@ -10,7 +10,6 @@ package org.opendaylight.mdsal.dom.api;
 import com.google.common.annotations.Beta;
 import java.util.EventListener;
 import java.util.Set;
-import java.util.concurrent.Executor;
 import org.eclipse.jdt.annotation.NonNullByDefault;
 import org.opendaylight.yangtools.concepts.ListenerRegistration;
 import org.opendaylight.yangtools.yang.common.QName;
@@ -33,7 +32,7 @@ public interface DOMOperationAvailabilityExtension extends DOMOperationServiceEx
      *
      * <p>
      * Users should note that using a listener does not necessarily mean that
-     * {@link DOMOperationService#invokeRpc(QName, ContainerNode, DOMOperationCallback, Executor)} and
+     * {@link DOMOperationService#invokeRpc(QName, ContainerNode)} and
      * {@link DOMOperationService#invokeAction(SchemaPath, DOMDataTreeIdentifier, ContainerNode)} will not report
      * a failure due to {@link DOMOperationNotAvailableException} and need to be ready to handle it.
      *
diff --git a/dom/mdsal-dom-api/src/main/java/org/opendaylight/mdsal/dom/api/DOMOperationCallback.java b/dom/mdsal-dom-api/src/main/java/org/opendaylight/mdsal/dom/api/DOMOperationCallback.java
deleted file mode 100644 (file)
index 536764a..0000000
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Copyright (c) 2018 Pantheon Technologies, 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 static java.util.Objects.requireNonNull;
-
-import com.google.common.annotations.Beta;
-import com.google.common.util.concurrent.SettableFuture;
-import java.util.concurrent.CompletableFuture;
-import java.util.function.Consumer;
-import org.eclipse.jdt.annotation.NonNullByDefault;
-import org.opendaylight.yangtools.concepts.CheckedValue;
-
-/**
- * A callback to be executed when an operation invocation completes. This interface is modeled as a {@link Consumer}
- * of {@link CheckedValue}, which needs to be unwrapped.
- *
- * <p>
- * Alternatively, you can use {@link #of(Consumer, Consumer)} utility method, which provides the equivalent
- * dispatch with a nicer interface:
- * <code>
- *     DOMOperationCallback callback = DOMOperationCallback.of((success) -&gt; {
- *         // ... code to handle success ...
- *     }, (failure) -&gt; {
- *         // ... code to handle failure ...
- *     });
- * </code>
- *
- * <p>
- * Finally, you can create a bridging {@link DOMOperationCallback} through either
- * {@link #completingFuture(SettableFuture)} or {@link #completingFuture(CompletableFuture)}.
- *
- * @author Robert Varga
- */
-@Beta
-@NonNullByDefault
-@FunctionalInterface
-public interface DOMOperationCallback extends Consumer<CheckedValue<DOMOperationResult, DOMOperationException>> {
-    /**
-     * Create a DOMOperationCallback composed of two separate consumers, one for success and one for failure.
-     *
-     * @param onSuccess Callback to invoke on success
-     * @param onFailure Callback to invoke on failure
-     * @return A {@link DOMOperationCallback} which delegates to provided methods
-     * @throws NullPointerException if any of the arguments is null
-     */
-    static DOMOperationCallback of(final Consumer<DOMOperationResult> onSuccess,
-            final Consumer<DOMOperationException> onFailure) {
-        requireNonNull(onSuccess);
-        requireNonNull(onFailure);
-        return result -> {
-            if (result.isPresent()) {
-                onSuccess.accept(result.get());
-            } else {
-                onFailure.accept(result.getException());
-            }
-        };
-    }
-
-    /**
-     * Create a {@link DOMOperationCallback} which completes the specified future.
-     *
-     * @param future {@link CompletableFuture} to complete
-     * @return A {@link DOMOperationCallback}
-     * @throws NullPointerException if any of the arguments is null
-     */
-    static DOMOperationCallback completingFuture(final CompletableFuture<DOMOperationResult> future) {
-        requireNonNull(future);
-        return of(future::complete, future::completeExceptionally);
-    }
-
-    /**
-     * Create a {@link DOMOperationCallback} which completes the specified future.
-     *
-     * @param future {@link SettableFuture} to complete
-     * @return A {@link DOMOperationCallback}
-     * @throws NullPointerException if any of the arguments is null
-     */
-    static DOMOperationCallback completingFuture(final SettableFuture<DOMOperationResult> future) {
-        requireNonNull(future);
-        return of(future::set, future::setException);
-    }
-}
index 1b44315a1958d39b0844bf3f3b532a547ff36879..18a5f83caa19a3a375147e4116fae7fcdb3ce62a 100644 (file)
@@ -8,7 +8,7 @@
 package org.opendaylight.mdsal.dom.api;
 
 import com.google.common.annotations.Beta;
-import java.util.concurrent.Executor;
+import com.google.common.util.concurrent.FluentFuture;
 import org.eclipse.jdt.annotation.NonNullByDefault;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
@@ -36,12 +36,10 @@ public interface DOMOperationImplementation {
          *             top of the conceptual {@link StoreTreeNode}.
          * @param path {@link DOMDataTreeIdentifier} of parent data node which action attached to.
          * @param input Input arguments
-         * @param callback Callback to invoke with the invocation result
-         * @param callbackExecutor Executor to use for executing the callback
+         * @return A FluentFuture which completes with the result of invocation
          * @throws NullPointerException if any of the arguments is null
          */
-        void invokeAction(SchemaPath type, DOMDataTreeIdentifier path, ContainerNode input,
-                DOMOperationCallback callback, Executor callbackExecutor);
+        FluentFuture<DOMOperationResult> invokeAction(SchemaPath type, DOMDataTreeIdentifier path, ContainerNode input);
     }
 
     /**
@@ -54,11 +52,10 @@ public interface DOMOperationImplementation {
          *
          * @param type QName of the RPC to be invoked
          * @param input Input arguments
-         * @param callback Callback to invoke with the invocation result
-         * @param callbackExecutor Executor to use for executing the callback
+         * @return A FluentFuture which completes with the result of invocation
          * @throws NullPointerException if any of the arguments is null
          */
-        void invokeRpc(QName type, ContainerNode input, DOMOperationCallback callback, Executor callbackExecutor);
+        FluentFuture<DOMOperationResult> invokeRpc(QName type, ContainerNode input);
     }
 
     /**
index 27d30b9f37ae5faa0f5385729299e36e50889199..33535b0b11134a884dea4bf0f35dc7cadaf4995f 100644 (file)
@@ -7,12 +7,8 @@
  */
 package org.opendaylight.mdsal.dom.api;
 
-import static com.google.common.util.concurrent.MoreExecutors.directExecutor;
-
 import com.google.common.annotations.Beta;
 import com.google.common.util.concurrent.FluentFuture;
-import com.google.common.util.concurrent.SettableFuture;
-import java.util.concurrent.Executor;
 import org.eclipse.jdt.annotation.NonNullByDefault;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
@@ -29,18 +25,6 @@ import org.opendaylight.yangtools.yang.model.api.SchemaPath;
 @Beta
 @NonNullByDefault
 public interface DOMOperationService extends DOMExtensibleService<DOMOperationService, DOMOperationServiceExtension> {
-    /**
-     * Initiate invocation of an RPC. This method is guaranteed to not block on any external resources.
-     *
-     * @param type QName of the RPC to be invoked
-     * @param input Input arguments
-     * @param callback Callback to invoke with the invocation result
-     * @param callbackExecutor Executor to use for executing the callback
-     * @throws NullPointerException if any of the arguments is null
-     */
-    void invokeRpc(QName type, ContainerNode input, DOMOperationCallback callback,
-            Executor callbackExecutor);
-
     /**
      * Initiate invocation of an RPC. This method is guaranteed to not block on any external resources.
      *
@@ -49,25 +33,7 @@ public interface DOMOperationService extends DOMExtensibleService<DOMOperationSe
      * @return A FluentFuture which completes with the result of invocation
      * @throws NullPointerException if any of the arguments is null
      */
-    default FluentFuture<DOMOperationResult> invokeRpc(final QName type, final ContainerNode input) {
-        final SettableFuture<DOMOperationResult> future = SettableFuture.create();
-        invokeRpc(type, input, DOMOperationCallback.completingFuture(future), directExecutor());
-        return future;
-    }
-
-    /**
-     * Initiate invocation of an Action. This method is guaranteed to not block on any external resources.
-     *
-     * @param type SchemaPath of the action to be invoked. This path refers to an effective action instantiated on top
-     *             of the conceptual {@link StoreTreeNode}.
-     * @param path {@link DOMDataTreeIdentifier} of parent data node which action attached to.
-     * @param input Input argument
-     * @param callback Callback to invoke with the invocation result
-     * @param callbackExecutor Executor to use for executing the callback
-     * @throws NullPointerException if any of the arguments is null
-     */
-    void invokeAction(SchemaPath type, DOMDataTreeIdentifier path, ContainerNode input, DOMOperationCallback callback,
-            Executor callbackExecutor);
+    FluentFuture<DOMOperationResult> invokeRpc(QName type, ContainerNode input);
 
     /**
      * Initiate invocation of an Action. This method is guaranteed to not block on any external resources.
@@ -79,10 +45,5 @@ public interface DOMOperationService extends DOMExtensibleService<DOMOperationSe
      * @return A FluentFuture which completes with the result of invocation
      * @throws NullPointerException if any of the arguments is null
      */
-    default FluentFuture<DOMOperationResult> invokeAction(final SchemaPath type, final DOMDataTreeIdentifier path,
-            final ContainerNode input) {
-        final SettableFuture<DOMOperationResult> future = SettableFuture.create();
-        invokeAction(type, path, input, DOMOperationCallback.completingFuture(future), directExecutor());
-        return future;
-    }
+    FluentFuture<DOMOperationResult> invokeAction(SchemaPath type, DOMDataTreeIdentifier path, ContainerNode input);
 }
diff --git a/dom/mdsal-dom-spi/src/main/java/org/opendaylight/mdsal/dom/spi/SimpleDOMOperationResult.java b/dom/mdsal-dom-spi/src/main/java/org/opendaylight/mdsal/dom/spi/SimpleDOMOperationResult.java
new file mode 100644 (file)
index 0000000..67b449f
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2018 Pantheon Technologies, 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.spi;
+
+import static java.util.Objects.requireNonNull;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.MoreObjects;
+import com.google.common.base.MoreObjects.ToStringHelper;
+import com.google.common.collect.ImmutableList;
+import java.util.Collection;
+import java.util.Optional;
+import javax.annotation.concurrent.ThreadSafe;
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
+import org.opendaylight.mdsal.dom.api.DOMOperationResult;
+import org.opendaylight.yangtools.concepts.Immutable;
+import org.opendaylight.yangtools.yang.common.RpcError;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+
+@Beta
+@NonNullByDefault
+@ThreadSafe
+public final class SimpleDOMOperationResult implements DOMOperationResult, Immutable {
+    private final Collection<RpcError> errors;
+    private final @Nullable ContainerNode output;
+
+    private SimpleDOMOperationResult(final Collection<RpcError> errors, final @Nullable ContainerNode output) {
+        this.errors = ImmutableList.copyOf(errors);
+        this.output = null;
+    }
+
+    public SimpleDOMOperationResult(final Collection<RpcError> errors) {
+        this(errors, null);
+    }
+
+    public SimpleDOMOperationResult(final ContainerNode output, final Collection<RpcError> errors) {
+        this(errors, requireNonNull(output));
+    }
+
+    @Override
+    public Collection<RpcError> getErrors() {
+        return errors;
+    }
+
+    @Override
+    public Optional<ContainerNode> getOutput() {
+        return (Optional) Optional.<@Nullable ContainerNode>ofNullable(output);
+    }
+
+    @Override
+    public String toString() {
+        final ToStringHelper helper = MoreObjects.toStringHelper(this).omitNullValues().add("output", output);
+        if (!errors.isEmpty()) {
+            helper.add("errors", errors);
+        }
+        return helper.toString();
+    }
+}
\ No newline at end of file