Bump upstreams
[netconf.git] / apps / netconf-topology-singleton / src / main / java / org / opendaylight / netconf / topology / singleton / impl / ProxyDOMActionService.java
1 /*
2  * Copyright (C) 2019 Ericsson Software Technology AB. 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.topology.singleton.impl;
9
10 import static java.util.Objects.requireNonNull;
11
12 import akka.actor.ActorRef;
13 import akka.actor.ActorSystem;
14 import akka.dispatch.OnComplete;
15 import akka.pattern.Patterns;
16 import akka.util.Timeout;
17 import com.google.common.collect.ImmutableList;
18 import com.google.common.util.concurrent.FluentFuture;
19 import com.google.common.util.concurrent.SettableFuture;
20 import java.util.Collection;
21 import org.opendaylight.mdsal.dom.api.DOMActionResult;
22 import org.opendaylight.mdsal.dom.api.DOMActionService;
23 import org.opendaylight.mdsal.dom.api.DOMDataTreeIdentifier;
24 import org.opendaylight.mdsal.dom.spi.SimpleDOMActionResult;
25 import org.opendaylight.netconf.client.mdsal.api.RemoteDeviceId;
26 import org.opendaylight.netconf.client.mdsal.api.RemoteDeviceServices.Actions;
27 import org.opendaylight.netconf.topology.singleton.impl.utils.ClusteringActionException;
28 import org.opendaylight.netconf.topology.singleton.messages.ContainerNodeMessage;
29 import org.opendaylight.netconf.topology.singleton.messages.SchemaPathMessage;
30 import org.opendaylight.netconf.topology.singleton.messages.action.InvokeActionMessage;
31 import org.opendaylight.netconf.topology.singleton.messages.action.InvokeActionMessageReply;
32 import org.opendaylight.netconf.topology.singleton.messages.transactions.EmptyResultResponse;
33 import org.opendaylight.yangtools.yang.common.RpcError;
34 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
35 import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier.Absolute;
36 import org.slf4j.Logger;
37 import org.slf4j.LoggerFactory;
38 import scala.concurrent.Future;
39
40 /**
41  * Implementation of {@link DOMActionService} provided by device in Odl-Cluster environment to invoke action.
42  * Communicates action message {@link InvokeActionMessage} to {@link ActorSystem} using {@link ActorRef} and transforms
43  * replied NETCONF message to action result, using {@link SimpleDOMActionResult}.
44  */
45 public class ProxyDOMActionService implements Actions.Normalized {
46     private static final Logger LOG = LoggerFactory.getLogger(ProxyDOMActionService.class);
47
48     private final RemoteDeviceId id;
49     private final ActorRef masterActorRef;
50     private final ActorSystem actorSystem;
51     private final Timeout actorResponseWaitTime;
52
53     /**
54      * Constructor for {@code ProxyDOMActionService}.
55      *
56      * @param actorSystem ActorSystem
57      * @param masterActorRef ActorRef
58      * @param remoteDeviceId {@link RemoteDeviceId} ref
59      * @param actorResponseWaitTime Timeout
60      */
61     public ProxyDOMActionService(final ActorSystem actorSystem, final ActorRef masterActorRef,
62         final RemoteDeviceId remoteDeviceId, final Timeout actorResponseWaitTime) {
63         id = remoteDeviceId;
64         this.actorSystem = requireNonNull(actorSystem);
65         this.masterActorRef = requireNonNull(masterActorRef);
66         this.actorResponseWaitTime = requireNonNull(actorResponseWaitTime);
67     }
68
69     @Override
70     public FluentFuture<DOMActionResult> invokeAction(final Absolute type,
71             final DOMDataTreeIdentifier domDataTreeIdentifier, final ContainerNode input) {
72         requireNonNull(type);
73         requireNonNull(input);
74         requireNonNull(domDataTreeIdentifier);
75
76         LOG.info("{}: Action Operation invoked with schema type: {} and node: {}.", id, type, input);
77         final ContainerNodeMessage containerNodeMessage = new ContainerNodeMessage(input);
78
79         final Future<Object> scalaFuture = Patterns.ask(masterActorRef, new InvokeActionMessage(
80             new SchemaPathMessage(type), containerNodeMessage, domDataTreeIdentifier), actorResponseWaitTime);
81
82         final SettableFuture<DOMActionResult> settableFuture = SettableFuture.create();
83
84         scalaFuture.onComplete(new OnComplete<>() {
85             @Override
86             public void onComplete(final Throwable failure, final Object response) {
87                 if (failure != null) {
88                     if (failure instanceof ClusteringActionException) {
89                         settableFuture.setException(failure);
90                     } else {
91                         settableFuture.setException(new ClusteringActionException(
92                             id + ": Exception during remote Action invocation.", failure));
93                     }
94                     return;
95                 }
96
97                 if (response instanceof EmptyResultResponse) {
98                     settableFuture.set(null);
99                     return;
100                 }
101                 final Collection<? extends RpcError> errors = ((InvokeActionMessageReply) response).getRpcErrors();
102
103                 final ContainerNodeMessage containerNodeMessage =
104                     ((InvokeActionMessageReply) response).getContainerNodeMessage();
105
106                 final DOMActionResult result;
107
108                 if (containerNodeMessage == null) {
109                     result = new SimpleDOMActionResult(ImmutableList.copyOf(errors));
110                 } else {
111                     result = new SimpleDOMActionResult(containerNodeMessage.getNode(), ImmutableList.copyOf(errors));
112                 }
113                 settableFuture.set(result);
114             }
115         }, actorSystem.dispatcher());
116
117         return FluentFuture.from(settableFuture);
118     }
119 }