Add DOMOperationService and related interfaces 16/64516/19
authorJie Han <han.jie@zte.com.cn>
Thu, 19 Oct 2017 09:31:34 +0000 (17:31 +0800)
committerRobert Varga <robert.varga@pantheon.tech>
Tue, 10 Jul 2018 18:19:42 +0000 (20:19 +0200)
DOMOperationService supersedes DOMRpcService and unifies execution
of both RPCs and actions.

The design of this interface is inherently asynchronous, where the
system actually executing the action cannot be influenced by the
waiter blocking.

Change-Id: I8ff61f7b1d589cd3b7d32afba0cbd5042dbc5441
Signed-off-by: Jie Han <han.jie@zte.com.cn>
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
13 files changed:
dom/mdsal-dom-api/src/main/java/org/opendaylight/mdsal/dom/api/DOMOperationAvailabilityExtension.java [new file with mode: 0644]
dom/mdsal-dom-api/src/main/java/org/opendaylight/mdsal/dom/api/DOMOperationCallback.java [new file with mode: 0644]
dom/mdsal-dom-api/src/main/java/org/opendaylight/mdsal/dom/api/DOMOperationException.java [new file with mode: 0644]
dom/mdsal-dom-api/src/main/java/org/opendaylight/mdsal/dom/api/DOMOperationImplementation.java [new file with mode: 0644]
dom/mdsal-dom-api/src/main/java/org/opendaylight/mdsal/dom/api/DOMOperationInstance.java [new file with mode: 0644]
dom/mdsal-dom-api/src/main/java/org/opendaylight/mdsal/dom/api/DOMOperationNotAvailableException.java [new file with mode: 0644]
dom/mdsal-dom-api/src/main/java/org/opendaylight/mdsal/dom/api/DOMOperationProviderService.java [new file with mode: 0644]
dom/mdsal-dom-api/src/main/java/org/opendaylight/mdsal/dom/api/DOMOperationProviderServiceExtension.java [new file with mode: 0644]
dom/mdsal-dom-api/src/main/java/org/opendaylight/mdsal/dom/api/DOMOperationResult.java [new file with mode: 0644]
dom/mdsal-dom-api/src/main/java/org/opendaylight/mdsal/dom/api/DOMOperationService.java [new file with mode: 0644]
dom/mdsal-dom-api/src/main/java/org/opendaylight/mdsal/dom/api/DOMOperationServiceExtension.java [new file with mode: 0644]
dom/mdsal-dom-api/src/main/java/org/opendaylight/mdsal/dom/api/DOMRpcIdentifier.java
dom/mdsal-dom-api/src/main/java/org/opendaylight/mdsal/dom/api/DOMRpcService.java

diff --git a/dom/mdsal-dom-api/src/main/java/org/opendaylight/mdsal/dom/api/DOMOperationAvailabilityExtension.java b/dom/mdsal-dom-api/src/main/java/org/opendaylight/mdsal/dom/api/DOMOperationAvailabilityExtension.java
new file mode 100644 (file)
index 0000000..cb805c7
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * 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 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;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+
+/**
+ * An {@link DOMOperationServiceExtension} exposed by {@link DOMOperationService}s which allow their users to listen
+ * for operations becoming available.
+ *
+ * @author Robert Varga
+ */
+@Beta
+@NonNullByDefault
+public interface DOMOperationAvailabilityExtension extends DOMOperationServiceExtension {
+    /**
+     * Register a {@link AvailabilityListener} with this service to receive notifications about operation
+     * implementations becoming (un)available. The listener will be invoked with the current implementations reported
+     * and will be kept uptodate as implementations come and go.
+     *
+     * <p>
+     * Users should note that using a listener does not necessarily mean that
+     * {@link DOMOperationService#invokeRpc(QName, NormalizedNode, DOMOperationCallback, Executor)} and
+     * {@link DOMOperationService#invokeAction(SchemaPath, DOMDataTreeIdentifier, NormalizedNode)} will not report
+     * a failure due to {@link DOMOperationNotAvailableException} and need to be ready to handle it.
+     *
+     * <p>
+     * Implementations are encouraged to take reasonable precautions to prevent this scenario from occurring.
+     *
+     * @param listener {@link AvailabilityListener} instance to register
+     * @return A {@link ListenerRegistration} representing this registration. Performing a
+     *         {@link ListenerRegistration#close()} will cancel it.
+     * @throws NullPointerException if {@code listener} is null
+     */
+    <T extends AvailabilityListener> ListenerRegistration<T> registerAvailabilityListener(T listener);
+
+    /**
+     * An {@link EventListener} used to track Operation implementations becoming (un)available
+     * to a {@link DOMOperationService}.
+     */
+    interface AvailabilityListener extends EventListener {
+        /**
+         * Method invoked whenever an operation type becomes available or unavailable. There are two sets reported,
+         * removed and added. To reconstruct the state, first apply removed and then added operations, like this:
+         *
+         * <code>
+         *     Set&lt;AvailableOperation&lt;?&gt;&gt; operations;
+         *     operations.removeAll(removed);
+         *     operations.addAll(added);
+         * </code>
+         *
+         * @param removed operations which disappeared
+         * @param added operations which became available
+         */
+        void onOperationsChanged(Set<DOMOperationInstance<?>> removed, Set<DOMOperationInstance<?>> added);
+
+        /**
+         * Implementation filtering method. This method is useful for forwarding operation implementations,
+         * which need to ensure they do not re-announce their own implementations. Without this method
+         * a forwarder which registers an implementation would be notified of its own implementation,
+         * potentially re-exporting it as local -- hence creating a forwarding loop.
+         *
+         * @param impl Operation implementation being registered
+         * @return False if the implementation should not be reported, defaults to true.
+         */
+        default boolean acceptsImplementation(final DOMOperationImplementation impl) {
+            return true;
+        }
+    }
+}
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
new file mode 100644 (file)
index 0000000..536764a
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * 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);
+    }
+}
diff --git a/dom/mdsal-dom-api/src/main/java/org/opendaylight/mdsal/dom/api/DOMOperationException.java b/dom/mdsal-dom-api/src/main/java/org/opendaylight/mdsal/dom/api/DOMOperationException.java
new file mode 100644 (file)
index 0000000..5d2c2b6
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * 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 com.google.common.annotations.Beta;
+import org.eclipse.jdt.annotation.NonNullByDefault;
+
+/**
+ * Base class for failures that can occur during operation invocation. This covers transport and protocol-level
+ * failures, not implementation-reported errors, which are part of {@link DOMOperationResult}.
+ *
+ * @author Robert Varga
+ */
+@Beta
+@NonNullByDefault
+public abstract class DOMOperationException extends Exception {
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * Construct an new instance with a message and an empty cause.
+     *
+     * @param message Exception message
+     */
+    protected DOMOperationException(final String message) {
+        super(message);
+    }
+
+    /**
+     * Construct an new instance with a message and a cause.
+     *
+     * @param message Exception message
+     * @param cause Chained cause
+     */
+    protected DOMOperationException(final String message, final Throwable cause) {
+        super(message, cause);
+    }
+}
diff --git a/dom/mdsal-dom-api/src/main/java/org/opendaylight/mdsal/dom/api/DOMOperationImplementation.java b/dom/mdsal-dom-api/src/main/java/org/opendaylight/mdsal/dom/api/DOMOperationImplementation.java
new file mode 100644 (file)
index 0000000..0f599dc
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * 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 com.google.common.annotations.Beta;
+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.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.StoreTreeNode;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+
+/**
+ * Interface implemented by an individual operation implementation. This API allows for dispatch implementations, e.g.
+ * an individual object handling a multitude of operations.
+ *
+ * @author Robert Varga
+ */
+@Beta
+@NonNullByDefault
+public interface DOMOperationImplementation {
+    /**
+     * An implementation of an {@code action}.
+     */
+    @FunctionalInterface
+    interface Action {
+        /**
+         * Initiate invocation of the RPC. Implementations of this method are expected to not block.
+         *
+         * @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 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 invokeAction(SchemaPath type, DOMDataTreeIdentifier path, NormalizedNode<?, ?> input,
+                DOMOperationCallback callback, Executor callbackExecutor);
+    }
+
+    /**
+     * An implementation of an {@code rpc}.
+     */
+    @FunctionalInterface
+    interface Rpc {
+        /**
+         * Initiate invocation of the RPC. Implementations of this method are expected to not block.
+         *
+         * @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, NormalizedNode<?, ?> input, DOMOperationCallback callback,
+                Executor callbackExecutor);
+    }
+
+    /**
+     * Return the relative invocation cost of this implementation. Default implementation returns 0.
+     *
+     * @return Non-negative cost of invoking this implementation.
+     */
+    default long invocationCost() {
+        return 0;
+    }
+}
diff --git a/dom/mdsal-dom-api/src/main/java/org/opendaylight/mdsal/dom/api/DOMOperationInstance.java b/dom/mdsal-dom-api/src/main/java/org/opendaylight/mdsal/dom/api/DOMOperationInstance.java
new file mode 100644 (file)
index 0000000..c163aa9
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ * 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 com.google.common.base.Preconditions.checkArgument;
+import static java.util.Objects.requireNonNull;
+
+import com.google.common.base.MoreObjects;
+import com.google.common.base.MoreObjects.ToStringHelper;
+import com.google.common.collect.ImmutableSet;
+import java.util.Objects;
+import java.util.Set;
+import org.eclipse.jdt.annotation.Nullable;
+import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
+import org.opendaylight.yangtools.concepts.Immutable;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+
+/**
+ * An operation (RPC or action) which is subject to availability. This is a common superclass for {@link Action} and
+ * {@link Rpc}.
+ *
+ * @param <T> type of operation type
+ */
+public abstract class DOMOperationInstance<T> implements Immutable {
+    public static final class Action extends DOMOperationInstance<SchemaPath> {
+        private final Set<DOMDataTreeIdentifier> dataTrees;
+
+        Action(final SchemaPath type, final Set<DOMDataTreeIdentifier> dataTrees) {
+            super(type);
+            this.dataTrees = ImmutableSet.copyOf(dataTrees);
+            checkArgument(!dataTrees.isEmpty());
+        }
+
+        /**
+         * Return the set of data trees on which this action is available. Note that
+         * {@link DOMDataTreeIdentifier#getRootIdentifier()} may be a wildcard.
+         *
+         * @return Set of trees on which this action is available.
+         */
+        public Set<DOMDataTreeIdentifier> getDataTrees() {
+            return dataTrees;
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(getType(), dataTrees);
+        }
+
+        @Override
+        public boolean equals(final @Nullable Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            if (!(obj instanceof Action)) {
+                return false;
+            }
+            final Action other = (Action) obj;
+            return getType().equals(other.getType()) && dataTrees.equals(other.dataTrees);
+        }
+
+        @Override
+        ToStringHelper addToStringAttributes(final ToStringHelper helper) {
+            return helper.add("dataTrees", dataTrees);
+        }
+    }
+
+    public static final class Rpc extends DOMOperationInstance<QName> {
+        Rpc(final QName type) {
+            super(type);
+        }
+
+        @Override
+        public int hashCode() {
+            return getType().hashCode();
+        }
+
+        @Override
+        public boolean equals(final @Nullable Object obj) {
+            return this == obj || obj instanceof Rpc && getType().equals(((Rpc) obj).getType());
+        }
+    }
+
+    private final T type;
+
+    DOMOperationInstance(final T type) {
+        this.type = requireNonNull(type);
+    }
+
+    public static Action actionOf(final SchemaPath type, final Set<DOMDataTreeIdentifier> dataTrees) {
+        return new Action(type, dataTrees);
+    }
+
+    public static Action actionOf(final SchemaPath type, final DOMDataTreeIdentifier... dataTrees) {
+        return actionOf(type, ImmutableSet.copyOf(dataTrees));
+    }
+
+    public static Action actionOf(final SchemaPath type, final LogicalDatastoreType datastore,
+            final YangInstanceIdentifier path) {
+        return actionOf(type, ImmutableSet.of(new DOMDataTreeIdentifier(datastore, path)));
+    }
+
+    public static Rpc rpcOf(final QName type) {
+        return new Rpc(type);
+    }
+
+    /**
+     * Return the operation type.
+     *
+     * @return operation type.
+     */
+    public final T getType() {
+        return type;
+    }
+
+    @Override
+    public abstract int hashCode();
+
+    @Override
+    public abstract boolean equals(@Nullable Object obj);
+
+    @Override
+    public final String toString() {
+        return addToStringAttributes(MoreObjects.toStringHelper(this)).toString();
+    }
+
+    ToStringHelper addToStringAttributes(final ToStringHelper helper) {
+        return helper.add("type", type);
+    }
+}
\ No newline at end of file
diff --git a/dom/mdsal-dom-api/src/main/java/org/opendaylight/mdsal/dom/api/DOMOperationNotAvailableException.java b/dom/mdsal-dom-api/src/main/java/org/opendaylight/mdsal/dom/api/DOMOperationNotAvailableException.java
new file mode 100644 (file)
index 0000000..91c261f
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * 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 org.eclipse.jdt.annotation.NonNullByDefault;
+
+/**
+ * Exception indicating that no implementation of the requested operation is available.
+ */
+@Beta
+@NonNullByDefault
+public final class DOMOperationNotAvailableException extends DOMOperationException {
+    private static final long serialVersionUID = 1L;
+
+    public DOMOperationNotAvailableException(final String format, final Object... args) {
+        super(String.format(format, args));
+    }
+
+    public DOMOperationNotAvailableException(final Throwable cause, final String format, final Object... args) {
+        super(String.format(format, args), requireNonNull(cause));
+    }
+}
diff --git a/dom/mdsal-dom-api/src/main/java/org/opendaylight/mdsal/dom/api/DOMOperationProviderService.java b/dom/mdsal-dom-api/src/main/java/org/opendaylight/mdsal/dom/api/DOMOperationProviderService.java
new file mode 100644 (file)
index 0000000..9b60c52
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2017 Cisco Systems, Inc. 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.collect.ImmutableSet;
+import java.util.Set;
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.opendaylight.yangtools.concepts.ObjectRegistration;
+
+/**
+ * A {@link DOMService} which allows registration of operation implementations with a conceptual
+ * router. The client counterpart of this service is {@link DOMOperationService}.
+ */
+@Beta
+@NonNullByDefault
+public interface DOMOperationProviderService
+        extends DOMExtensibleService<DOMOperationProviderService, DOMOperationProviderServiceExtension> {
+    /**
+     * Register an {@link DOMOperationImplementation.Action} object with this service.
+     *
+     * @param implementation action implementation, must not be null
+     * @param instances Set of supported operation identifiers. Must not be null, empty, or contain a null element.
+     * @return A {@link ObjectRegistration} object, guaranteed to be non-null.
+     * @throws NullPointerException if implementation or types is null
+     * @throws IllegalArgumentException if {@code instances} is empty
+     */
+    <T extends DOMOperationImplementation.Action> ObjectRegistration<T> registerActionImplementation(T implementation,
+            Set<DOMOperationInstance.Action> instances);
+
+    default <T extends DOMOperationImplementation.Action> ObjectRegistration<T> registerActionImplementation(
+            final T implementation, final DOMOperationInstance.Action... instances) {
+        return registerActionImplementation(implementation, ImmutableSet.copyOf(instances));
+    }
+
+    /**
+     * Register an {@link DOMOperationImplementation.Rpc} object with this service.
+     *
+     * @param implementation RPC implementation, must not be null
+     * @param instances Set of supported operation identifiers. Must not be null, empty, or contain a null element.
+     * @return A {@link ObjectRegistration} object, guaranteed to be non-null.
+     * @throws NullPointerException if implementation or types is null
+     * @throws IllegalArgumentException if {@code instances} is empty
+     */
+    <T extends DOMOperationImplementation.Rpc> ObjectRegistration<T> registerRpcImplementation(T implementation,
+            Set<DOMOperationInstance.Rpc> instances);
+
+    default <T extends DOMOperationImplementation.Rpc> ObjectRegistration<T> registerRpcImplementation(
+            final T implementation, final DOMOperationInstance.Rpc... instances) {
+        return registerRpcImplementation(implementation, ImmutableSet.copyOf(instances));
+    }
+}
diff --git a/dom/mdsal-dom-api/src/main/java/org/opendaylight/mdsal/dom/api/DOMOperationProviderServiceExtension.java b/dom/mdsal-dom-api/src/main/java/org/opendaylight/mdsal/dom/api/DOMOperationProviderServiceExtension.java
new file mode 100644 (file)
index 0000000..e8aed30
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * 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 com.google.common.annotations.Beta;
+import org.eclipse.jdt.annotation.NonNullByDefault;
+
+/**
+ * Marker interface for extensions of {@link DOMOperationProviderService}.
+ *
+ * @author Robert Varga
+ */
+@Beta
+@NonNullByDefault
+public interface DOMOperationProviderServiceExtension
+    extends DOMServiceExtension<DOMOperationProviderService, DOMOperationProviderServiceExtension> {
+
+}
diff --git a/dom/mdsal-dom-api/src/main/java/org/opendaylight/mdsal/dom/api/DOMOperationResult.java b/dom/mdsal-dom-api/src/main/java/org/opendaylight/mdsal/dom/api/DOMOperationResult.java
new file mode 100644 (file)
index 0000000..ea6306e
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * 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 com.google.common.annotations.Beta;
+import java.util.Collection;
+import java.util.Optional;
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.opendaylight.yangtools.yang.common.RpcError;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+
+/**
+ * Interface defining a result of an operation invocation.
+ *
+ * @author Robert Varga
+ */
+@Beta
+@NonNullByDefault
+public interface DOMOperationResult {
+    /**
+     * Returns a set of errors and warnings which occurred during processing the call.
+     *
+     * @return a Collection of {@link RpcError}, guaranteed to be non-null. In case no errors are reported, an empty
+     *         collection is returned.
+     */
+    Collection<RpcError> getErrors();
+
+    /**
+     * Returns the value result of the call.
+     *
+     * @return Invocation result, absent if the operation has not produced a result. This might be the case if the
+     *         operation does not produce a result, or if it failed.
+     */
+    Optional<NormalizedNode<?, ?>> getOutput();
+}
diff --git a/dom/mdsal-dom-api/src/main/java/org/opendaylight/mdsal/dom/api/DOMOperationService.java b/dom/mdsal-dom-api/src/main/java/org/opendaylight/mdsal/dom/api/DOMOperationService.java
new file mode 100644 (file)
index 0000000..da07334
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * 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 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.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.StoreTreeNode;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+
+/**
+ * A {@link DOMService} which allows clients to invoke Actions and RPCs. The conceptual model of this service is that
+ * of a dynamic router, where the set of available Operation services can change dynamically. The service allows users
+ * to add a listener to track the process of Actions and RPCs becoming available.
+ *
+ * @author Robert Varga
+ */
+@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, NormalizedNode<?, ?> input, DOMOperationCallback callback,
+            Executor callbackExecutor);
+
+    /**
+     * 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
+     * @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 NormalizedNode<?, ?> 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,
+            NormalizedNode<?, ?> input, DOMOperationCallback callback, Executor callbackExecutor);
+
+    /**
+     * 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
+     * @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 NormalizedNode<?, ?> input) {
+        final SettableFuture<DOMOperationResult> future = SettableFuture.create();
+        invokeAction(type, path, input, DOMOperationCallback.completingFuture(future), directExecutor());
+        return future;
+    }
+}
diff --git a/dom/mdsal-dom-api/src/main/java/org/opendaylight/mdsal/dom/api/DOMOperationServiceExtension.java b/dom/mdsal-dom-api/src/main/java/org/opendaylight/mdsal/dom/api/DOMOperationServiceExtension.java
new file mode 100644 (file)
index 0000000..ac955cd
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * 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 com.google.common.annotations.Beta;
+import org.eclipse.jdt.annotation.NonNullByDefault;
+
+/**
+ * Marker interface for extensions of {@link DOMOperationService}.
+ *
+ * @author Robert Varga
+ */
+@Beta
+@NonNullByDefault
+public interface DOMOperationServiceExtension
+    extends DOMServiceExtension<DOMOperationService, DOMOperationServiceExtension> {
+
+}
index cc3e3ccb6c21f848af0611cfb950bf8e97d71b94..a336ecec6e5d6ddeceeefdaa8a6764173f0a9552 100644 (file)
@@ -16,10 +16,9 @@ import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
 
 /**
- * Identifier of a RPC context. This is an extension of the YANG RPC, which
- * always has global context. It allows an RPC to have a instance identifier
- * attached, so that there can be multiple implementations bound to different
- * contexts concurrently.
+ * Identifier of a RPC context. This is an extension of the YANG RPC, which always has global context. It allows an RPC
+ * to have a instance identifier attached, so that there can be multiple implementations bound to different contexts
+ * concurrently.
  */
 public abstract class DOMRpcIdentifier {
     private static final class Global extends DOMRpcIdentifier {
@@ -76,9 +75,9 @@ public abstract class DOMRpcIdentifier {
             @Nullable final YangInstanceIdentifier contextReference) {
         if (contextReference == null || contextReference.isEmpty()) {
             return new Global(type);
-        } else {
-            return new Local(type, contextReference);
         }
+
+        return new Local(type, contextReference);
     }
 
     /**
index a977ece8e235df64c451262238fe68719b34ec0b..997f94c720e8a78df9a014e3b3edfe15cdfbc32a 100644 (file)
@@ -15,11 +15,11 @@ import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
 
 /**
- * A {@link DOMService} which allows clients to invoke RPCs. The conceptual model of this
- * service is that of a dynamic router, where the set of available RPC services can change
- * dynamically. The service allows users to add a listener to track the process of
- * RPCs becoming available.
+ * A {@link DOMService} which allows clients to invoke RPCs. The conceptual model of this service is that of a dynamic
+ * router, where the set of available RPC services can change dynamically. The service allows users to add a listener
+ * to track the process of RPCs becoming available.
  */
+// FIXME: once we have a DOMOperationService implementation, deprecate this interface
 public interface DOMRpcService extends DOMService {
     /**
      * Initiate invocation of an RPC. This method is guaranteed to not block on any external