Split up MessageTransformer
[netconf.git] / netconf / sal-netconf-connector / src / main / java / org / opendaylight / netconf / sal / connect / netconf / sal / 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.sal.connect.netconf.sal;
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.mdsal.dom.spi.DefaultDOMRpcResult;
19 import org.opendaylight.netconf.api.NetconfMessage;
20 import org.opendaylight.netconf.sal.connect.api.RemoteDeviceCommunicator;
21 import org.opendaylight.netconf.sal.connect.api.RemoteDeviceServices.Rpcs;
22 import org.opendaylight.netconf.sal.connect.api.RpcTransformer;
23 import org.opendaylight.netconf.sal.connect.netconf.schema.mapping.BaseRpcSchemalessTransformer;
24 import org.opendaylight.netconf.sal.connect.netconf.schema.mapping.SchemalessMessageTransformer;
25 import org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil;
26 import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId;
27 import org.opendaylight.yangtools.yang.common.QName;
28 import org.opendaylight.yangtools.yang.common.RpcResult;
29 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
30 import org.opendaylight.yangtools.yang.data.api.schema.DOMSourceAnyxmlNode;
31 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
32
33 /**
34  * Invokes RPC by sending netconf message via listener. Also transforms result from NetconfMessage to CompositeNode.
35  */
36 public final class SchemalessNetconfDeviceRpc implements Rpcs.Schemaless {
37     private final RemoteDeviceCommunicator listener;
38     private final BaseRpcSchemalessTransformer baseRpcTransformer;
39     private final SchemalessMessageTransformer schemalessTransformer;
40     private final RemoteDeviceId deviceId;
41
42     public SchemalessNetconfDeviceRpc(final RemoteDeviceId deviceId, final RemoteDeviceCommunicator listener,
43             final BaseRpcSchemalessTransformer baseRpcTransformer,
44             final SchemalessMessageTransformer messageTransformer) {
45         this.deviceId = deviceId;
46         this.listener = listener;
47         this.baseRpcTransformer = baseRpcTransformer;
48         schemalessTransformer = messageTransformer;
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 ListenableFuture<? extends DOMRpcResult> invokeRpc(final QName type, final NormalizedNode input) {
61         final RpcTransformer transformer;
62         if (input instanceof DOMSourceAnyxmlNode) {
63             transformer = schemalessTransformer;
64         } else if (isBaseRpc(type)) {
65             transformer = baseRpcTransformer;
66         } else {
67             return Futures.immediateFailedFuture(new DOMRpcImplementationNotAvailableException(
68                 "Unable to invoke rpc %s", type));
69         }
70         return handleRpc(type, input, transformer);
71     }
72
73     private @NonNull ListenableFuture<DOMRpcResult> handleRpc(final @NonNull QName type,
74             final @NonNull NormalizedNode input, final RpcTransformer transformer) {
75         final var delegateFuture = listener.sendRequest(transformer.toRpcRequest(type, input), type);
76         final var ret = SettableFuture.<DOMRpcResult>create();
77         Futures.addCallback(delegateFuture, new FutureCallback<>() {
78             @Override
79             public void onSuccess(final RpcResult<NetconfMessage> result) {
80                 ret.set(result.isSuccessful() ? transformer.toRpcResult(result.getResult(), type)
81                         : new DefaultDOMRpcResult(result.getErrors()));
82             }
83
84             @Override
85             public void onFailure(final Throwable cause) {
86                 ret.setException(new DOMRpcImplementationNotAvailableException(cause,
87                     "Unable to invoke rpc %s on device %s", type, deviceId));
88             }
89
90         }, MoreExecutors.directExecutor());
91         return ret;
92     }
93
94     private static boolean isBaseRpc(final QName type) {
95         return NetconfMessageTransformUtil.NETCONF_URI.equals(type.getNamespace());
96     }
97 }