Introduce restconf.server.{api,spi,mdsal}
[netconf.git] / restconf / restconf-nb / src / main / java / org / opendaylight / restconf / nb / rfc8040 / rests / transactions / RestconfStrategy.java
index e9c5da5fd6741c6d90e0527c88d2aabbe066e3cb..a755b139e4b6e1f3962157209833b68705f4a43d 100644 (file)
@@ -10,10 +10,12 @@ package org.opendaylight.restconf.nb.rfc8040.rests.transactions;
 import static com.google.common.base.Verify.verifyNotNull;
 import static java.util.Objects.requireNonNull;
 
+import com.google.common.collect.ImmutableMap;
 import com.google.common.util.concurrent.FutureCallback;
 import com.google.common.util.concurrent.Futures;
 import com.google.common.util.concurrent.ListenableFuture;
 import com.google.common.util.concurrent.MoreExecutors;
+import java.net.URI;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
@@ -42,6 +44,9 @@ import org.opendaylight.restconf.common.patch.PatchContext;
 import org.opendaylight.restconf.common.patch.PatchStatusContext;
 import org.opendaylight.restconf.common.patch.PatchStatusEntity;
 import org.opendaylight.restconf.nb.rfc8040.Insert;
+import org.opendaylight.restconf.server.spi.OperationInput;
+import org.opendaylight.restconf.server.spi.OperationOutput;
+import org.opendaylight.restconf.server.spi.RpcImplementation;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.with.defaults.rev110601.WithDefaultsMode;
 import org.opendaylight.yangtools.yang.common.Empty;
 import org.opendaylight.yangtools.yang.common.ErrorTag;
@@ -111,10 +116,13 @@ public abstract class RestconfStrategy {
     private static final Logger LOG = LoggerFactory.getLogger(RestconfStrategy.class);
 
     private final @NonNull EffectiveModelContext modelContext;
-    private final @Nullable DOMRpcService rpcService;
+    private final @NonNull ImmutableMap<QName, RpcImplementation> localRpcs;
+    private final DOMRpcService rpcService;
 
-    RestconfStrategy(final EffectiveModelContext modelContext, final @Nullable DOMRpcService rpcService) {
+    RestconfStrategy(final EffectiveModelContext modelContext, final ImmutableMap<QName, RpcImplementation> localRpcs,
+            final @Nullable DOMRpcService rpcService) {
         this.modelContext = requireNonNull(modelContext);
+        this.localRpcs = requireNonNull(localRpcs);
         this.rpcService = rpcService;
     }
 
@@ -1038,42 +1046,45 @@ public abstract class RestconfStrategy {
             y -> builder.addChild((T) prepareData(y.getValue(), stateMap.get(y.getKey()))));
     }
 
-    public @NonNull RestconfFuture<Optional<ContainerNode>> invokeRpc(final QName type, final ContainerNode input) {
-        final var ret = new SettableRestconfFuture<Optional<ContainerNode>>();
-
-        final var local = rpcService;
+    public @NonNull RestconfFuture<OperationOutput> invokeRpc(final URI restconfURI, final QName type,
+            final OperationInput input) {
+        final var local = localRpcs.get(type);
         if (local != null) {
-            Futures.addCallback(local.invokeRpc(requireNonNull(type), requireNonNull(input)),
-                new FutureCallback<DOMRpcResult>() {
-                    @Override
-                    public void onSuccess(final DOMRpcResult response) {
-                        final var errors = response.errors();
-                        if (errors.isEmpty()) {
-                            ret.set(Optional.ofNullable(response.value()));
-                        } else {
-                            LOG.debug("RPC invocation reported {}", response.errors());
-                            ret.setFailure(new RestconfDocumentedException("RPC implementation reported errors", null,
-                                response.errors()));
-                        }
-                    }
-
-                    @Override
-                    public void onFailure(final Throwable cause) {
-                        LOG.debug("RPC invocation failed, cause");
-                        if (cause instanceof RestconfDocumentedException ex) {
-                            ret.setFailure(ex);
-                        } else {
-                            // TODO: YangNetconfErrorAware if we ever get into a broader invocation scope
-                            ret.setFailure(new RestconfDocumentedException(cause,
-                                new RestconfError(ErrorType.RPC, ErrorTag.OPERATION_FAILED, cause.getMessage())));
-                        }
-                    }
-                }, MoreExecutors.directExecutor());
-        } else {
+            return local.invoke(restconfURI, input);
+        }
+        if (rpcService == null) {
             LOG.debug("RPC invocation is not available");
-            ret.setFailure(new RestconfDocumentedException("RPC invocation is not available",
+            return RestconfFuture.failed(new RestconfDocumentedException("RPC invocation is not available",
                 ErrorType.PROTOCOL, ErrorTag.OPERATION_NOT_SUPPORTED));
         }
+
+        final var ret = new SettableRestconfFuture<OperationOutput>();
+        Futures.addCallback(rpcService.invokeRpc(requireNonNull(type), input.input()),
+            new FutureCallback<DOMRpcResult>() {
+                @Override
+                public void onSuccess(final DOMRpcResult response) {
+                    final var errors = response.errors();
+                    if (errors.isEmpty()) {
+                        ret.set(input.newOperationOutput(response.value()));
+                    } else {
+                        LOG.debug("RPC invocation reported {}", response.errors());
+                        ret.setFailure(new RestconfDocumentedException("RPC implementation reported errors", null,
+                            response.errors()));
+                    }
+                }
+
+                @Override
+                public void onFailure(final Throwable cause) {
+                    LOG.debug("RPC invocation failed, cause");
+                    if (cause instanceof RestconfDocumentedException ex) {
+                        ret.setFailure(ex);
+                    } else {
+                        // TODO: YangNetconfErrorAware if we ever get into a broader invocation scope
+                        ret.setFailure(new RestconfDocumentedException(cause,
+                            new RestconfError(ErrorType.RPC, ErrorTag.OPERATION_FAILED, cause.getMessage())));
+                    }
+                }
+            }, MoreExecutors.directExecutor());
         return ret;
     }
 }