Schema determination is asynchronous
[netconf.git] / plugins / netconf-client-mdsal / src / main / java / org / opendaylight / netconf / client / mdsal / spi / SchemalessNetconfDeviceRpc.java
1 /*
2  * Copyright (c) 2016 Cisco Systems, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.netconf.client.mdsal.spi;
9
10 import com.google.common.util.concurrent.FutureCallback;
11 import com.google.common.util.concurrent.Futures;
12 import com.google.common.util.concurrent.ListenableFuture;
13 import com.google.common.util.concurrent.MoreExecutors;
14 import com.google.common.util.concurrent.SettableFuture;
15 import org.eclipse.jdt.annotation.NonNull;
16 import org.opendaylight.mdsal.dom.api.DOMRpcImplementationNotAvailableException;
17 import org.opendaylight.mdsal.dom.api.DOMRpcResult;
18 import org.opendaylight.netconf.api.messages.NetconfMessage;
19 import org.opendaylight.netconf.client.mdsal.api.RemoteDeviceCommunicator;
20 import org.opendaylight.netconf.client.mdsal.api.RemoteDeviceId;
21 import org.opendaylight.netconf.client.mdsal.api.RemoteDeviceServices.Rpcs;
22 import org.opendaylight.netconf.client.mdsal.api.RpcTransformer;
23 import org.opendaylight.netconf.client.mdsal.api.SchemalessRpcService;
24 import org.opendaylight.netconf.client.mdsal.impl.BaseRpcSchemalessTransformer;
25 import org.opendaylight.netconf.client.mdsal.impl.SchemalessMessageTransformer;
26 import org.opendaylight.yangtools.yang.common.QName;
27 import org.opendaylight.yangtools.yang.common.RpcResult;
28 import org.opendaylight.yangtools.yang.common.YangConstants;
29 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
30
31 /**
32  * Invokes RPC by sending NETCONF message via listener. Also transforms result from NetconfMessage to CompositeNode.
33  */
34 public final class SchemalessNetconfDeviceRpc implements Rpcs.Schemaless {
35     private final @NonNull SchemalessRpcService schemalessRpcService;
36     private final RemoteDeviceCommunicator listener;
37     private final BaseRpcSchemalessTransformer baseRpcTransformer;
38     private final SchemalessMessageTransformer schemalessTransformer;
39     private final RemoteDeviceId deviceId;
40
41     public SchemalessNetconfDeviceRpc(final RemoteDeviceId deviceId, final RemoteDeviceCommunicator listener,
42             final BaseRpcSchemalessTransformer baseRpcTransformer,
43             final SchemalessMessageTransformer messageTransformer) {
44         this.deviceId = deviceId;
45         this.listener = listener;
46         this.baseRpcTransformer = baseRpcTransformer;
47         schemalessTransformer = messageTransformer;
48         schemalessRpcService = (type, input) -> handleRpc(type, input, schemalessTransformer);
49     }
50
51     @Override
52     public ListenableFuture<? extends DOMRpcResult> invokeNetconf(final QName type, final ContainerNode input) {
53         if (!isBaseRpc(type)) {
54             throw new IllegalArgumentException("Cannot handle " + type);
55         }
56         return handleRpc(type, input, baseRpcTransformer);
57     }
58
59     @Override
60     public SchemalessRpcService schemalessRpcService() {
61         return schemalessRpcService;
62     }
63
64     private @NonNull <I, R> ListenableFuture<R> handleRpc(final @NonNull QName type,
65             final @NonNull I input, final RpcTransformer<I, R> transformer) {
66         final var delegateFuture = listener.sendRequest(transformer.toRpcRequest(type, input), type);
67         final var ret = SettableFuture.<R>create();
68         Futures.addCallback(delegateFuture, new FutureCallback<>() {
69             @Override
70             public void onSuccess(final RpcResult<NetconfMessage> result) {
71                 ret.set(transformer.toRpcResult(result, type));
72             }
73
74             @Override
75             public void onFailure(final Throwable cause) {
76                 ret.setException(new DOMRpcImplementationNotAvailableException(cause,
77                     "Unable to invoke rpc %s on device %s", type, deviceId));
78             }
79         }, MoreExecutors.directExecutor());
80         return ret;
81     }
82
83     private static boolean isBaseRpc(final QName type) {
84         return YangConstants.NETCONF_NAMESPACE.equals(type.getNamespace());
85     }
86 }