fdda197c3bf02f6dedf64859cf042438d483bf41
[controller.git] / opendaylight / md-sal / sal-remoterpc-connector / src / main / java / org / opendaylight / controller / remote / rpc / OpsRegistrar.java
1 /*
2  * Copyright (c) 2017 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.controller.remote.rpc;
9
10 import static java.util.Objects.requireNonNull;
11
12 import akka.actor.Address;
13 import akka.actor.Props;
14 import java.util.HashMap;
15 import java.util.Map;
16 import java.util.Map.Entry;
17 import java.util.Optional;
18 import org.opendaylight.controller.cluster.common.actor.AbstractUntypedActor;
19 import org.opendaylight.controller.remote.rpc.registry.ActionRegistry;
20 import org.opendaylight.controller.remote.rpc.registry.ActionRegistry.Messages.UpdateRemoteActionEndpoints;
21 import org.opendaylight.controller.remote.rpc.registry.ActionRegistry.RemoteActionEndpoint;
22 import org.opendaylight.controller.remote.rpc.registry.RpcRegistry.Messages.UpdateRemoteEndpoints;
23 import org.opendaylight.controller.remote.rpc.registry.RpcRegistry.RemoteRpcEndpoint;
24 import org.opendaylight.mdsal.dom.api.DOMActionImplementation;
25 import org.opendaylight.mdsal.dom.api.DOMActionProviderService;
26 import org.opendaylight.mdsal.dom.api.DOMRpcImplementation;
27 import org.opendaylight.mdsal.dom.api.DOMRpcProviderService;
28 import org.opendaylight.yangtools.concepts.ObjectRegistration;
29
30 /**
31  * Actor handling registration of RPCs and Actions available on remote nodes with the local
32  * {@link DOMRpcProviderService} and {@link DOMActionProviderService}.
33  */
34 final class OpsRegistrar extends AbstractUntypedActor {
35     private final Map<Address, ObjectRegistration<DOMRpcImplementation>> rpcRegs = new HashMap<>();
36     private final Map<Address, ObjectRegistration<DOMActionImplementation>> actionRegs = new HashMap<>();
37     private final DOMRpcProviderService rpcProviderService;
38     private final RemoteOpsProviderConfig config;
39     private final DOMActionProviderService actionProviderService;
40
41     OpsRegistrar(final RemoteOpsProviderConfig config, final DOMRpcProviderService rpcProviderService,
42                  final DOMActionProviderService actionProviderService) {
43         this.config = requireNonNull(config);
44         this.rpcProviderService = requireNonNull(rpcProviderService);
45         this.actionProviderService = requireNonNull(actionProviderService);
46     }
47
48     public static Props props(final RemoteOpsProviderConfig config, final DOMRpcProviderService rpcProviderService,
49                               final DOMActionProviderService actionProviderService) {
50         return Props.create(OpsRegistrar.class, requireNonNull(config),
51             requireNonNull(rpcProviderService, "DOMRpcProviderService cannot be null"),
52             requireNonNull(actionProviderService, "DOMActionProviderService cannot be null"));
53     }
54
55     @Override
56     public void postStop() throws Exception {
57         rpcRegs.clear();
58         actionRegs.clear();
59
60         super.postStop();
61     }
62
63     @Override
64     protected void handleReceive(final Object message) {
65         if (message instanceof UpdateRemoteEndpoints) {
66             LOG.debug("Handling updateRemoteEndpoints message");
67             updateRemoteRpcEndpoints(((UpdateRemoteEndpoints) message).getRpcEndpoints());
68         } else if (message instanceof UpdateRemoteActionEndpoints) {
69             LOG.debug("Handling updateRemoteActionEndpoints message");
70             updateRemoteActionEndpoints(((UpdateRemoteActionEndpoints) message).getActionEndpoints());
71         } else {
72             unknownMessage(message);
73         }
74     }
75
76     private void updateRemoteRpcEndpoints(final Map<Address, Optional<RemoteRpcEndpoint>> rpcEndpoints) {
77         /*
78          * Updating RPC providers is a two-step process. We first add the newly-discovered RPCs and then close
79          * the old registration. This minimizes churn observed by listeners, as they will not observe RPC
80          * unavailability which would occur if we were to do it the other way around.
81          *
82          * Note that when an RPC moves from one remote node to another, we also do not want to expose the gap,
83          * hence we register all new implementations before closing all registrations.
84          */
85         for (Entry<Address, Optional<RemoteRpcEndpoint>> e : rpcEndpoints.entrySet()) {
86             LOG.debug("Updating RPC registrations for {}", e.getKey());
87
88             final Optional<RemoteRpcEndpoint> maybeEndpoint = e.getValue();
89             if (maybeEndpoint.isPresent()) {
90                 final RemoteRpcEndpoint endpoint = maybeEndpoint.get();
91                 final RemoteRpcImplementation impl = new RemoteRpcImplementation(endpoint.getRouter(), config);
92                 rpcRegs.put(e.getKey(), rpcProviderService.registerRpcImplementation(impl,
93                         endpoint.getRpcs()));
94             } else {
95                 rpcRegs.remove(e.getKey());
96             }
97         }
98     }
99
100     /**
101      * Updates the action endpoints, Adding new registrations first before removing previous registrations.
102      */
103     private void updateRemoteActionEndpoints(final Map<Address,
104             Optional<ActionRegistry.RemoteActionEndpoint>> actionEndpoints) {
105         /*
106          * Updating Action providers is a two-step process. We first add the newly-discovered RPCs and then close
107          * the old registration. This minimizes churn observed by listeners, as they will not observe RPC
108          * unavailability which would occur if we were to do it the other way around.
109          *
110          * Note that when an Action moves from one remote node to another, we also do not want to expose the gap,
111          * hence we register all new implementations before closing all registrations.
112          */
113         for (Entry<Address, Optional<RemoteActionEndpoint>> e : actionEndpoints.entrySet()) {
114             LOG.debug("Updating Action registrations for {}", e.getKey());
115
116             final Optional<RemoteActionEndpoint> maybeEndpoint = e.getValue();
117             if (maybeEndpoint.isPresent()) {
118                 final RemoteActionEndpoint endpoint = maybeEndpoint.get();
119                 final RemoteActionImplementation impl = new RemoteActionImplementation(endpoint.getRouter(), config);
120                 actionRegs.put(e.getKey(),
121                         actionProviderService.registerActionImplementation(impl, endpoint.getActions()));
122             } else {
123                 actionRegs.remove(e.getKey());
124             }
125         }
126     }
127 }