Register action MXBean only during start
[controller.git] / opendaylight / md-sal / sal-remoterpc-connector / src / main / java / org / opendaylight / controller / remote / rpc / registry / ActionRegistry.java
1 /*
2  * Copyright (c) 2019 Nordix Foundation.  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.registry;
9
10 import static java.util.Objects.requireNonNull;
11
12 import akka.actor.ActorRef;
13 import akka.actor.Address;
14 import akka.actor.Props;
15 import com.google.common.annotations.VisibleForTesting;
16 import com.google.common.collect.ImmutableList;
17 import com.google.common.collect.ImmutableMap;
18 import com.google.common.collect.ImmutableSet;
19 import java.util.Collection;
20 import java.util.HashMap;
21 import java.util.Map;
22 import java.util.Optional;
23 import java.util.Set;
24 import org.opendaylight.controller.remote.rpc.RemoteOpsProviderConfig;
25 import org.opendaylight.controller.remote.rpc.registry.gossip.Bucket;
26 import org.opendaylight.controller.remote.rpc.registry.gossip.BucketStoreAccess;
27 import org.opendaylight.controller.remote.rpc.registry.gossip.BucketStoreActor;
28 import org.opendaylight.controller.remote.rpc.registry.mbeans.RemoteActionRegistryMXBeanImpl;
29 import org.opendaylight.mdsal.dom.api.DOMActionInstance;
30
31 /**
32  * Registry to look up cluster nodes that have registered for a given Action.
33  *
34  * <p>
35  * It uses {@link org.opendaylight.controller.remote.rpc.registry.gossip.BucketStoreActor} to maintain this
36  * cluster wide information.
37  */
38 public class ActionRegistry extends BucketStoreActor<ActionRoutingTable> {
39     private final ActorRef rpcRegistrar;
40
41     private RemoteActionRegistryMXBeanImpl mxBean;
42
43     public ActionRegistry(final RemoteOpsProviderConfig config, final ActorRef rpcInvoker,
44                           final ActorRef rpcRegistrar) {
45         super(config, config.getRpcRegistryPersistenceId(), new ActionRoutingTable(rpcInvoker, ImmutableSet.of()));
46         this.rpcRegistrar = requireNonNull(rpcRegistrar);
47     }
48
49     /**
50      * Create a new props instance for instantiating an ActionRegistry actor.
51      *
52      * @param config Provider configuration
53      * @param opsRegistrar Local RPC provider interface, used to register routers to remote nodes
54      * @param opsInvoker Actor handling RPC invocation requests from remote nodes
55      * @return A new {@link Props} instance
56      */
57     public static Props props(final RemoteOpsProviderConfig config, final ActorRef opsInvoker,
58                               final ActorRef opsRegistrar) {
59         return Props.create(ActionRegistry.class, config, opsInvoker, opsRegistrar);
60     }
61
62     @Override
63     public void preStart() {
64         super.preStart();
65         mxBean = new RemoteActionRegistryMXBeanImpl(new BucketStoreAccess(self(), getContext().dispatcher(),
66             getConfig().getAskDuration()), getConfig().getAskDuration());
67     }
68
69     @Override
70     public void postStop() throws Exception {
71         if (mxBean != null) {
72             mxBean.unregister();
73             mxBean = null;
74         }
75         super.postStop();
76     }
77
78     @Override
79     protected void handleCommand(final Object message) throws Exception {
80         if (message instanceof ActionRegistry.Messages.UpdateActions) {
81             LOG.debug("handling updatesActionRoutes message");
82             updatesActionRoutes((Messages.UpdateActions) message);
83         } else {
84             super.handleCommand(message);
85         }
86     }
87
88     private void updatesActionRoutes(final Messages.UpdateActions msg) {
89         LOG.debug("addedActions: {}", msg.getAddedActions());
90         LOG.debug("removedActions: {}", msg.getRemovedActions());
91         updateLocalBucket(getLocalData().updateActions(msg.getAddedActions(), msg.getRemovedActions()));
92     }
93
94     @Override
95     protected void onBucketRemoved(final Address address, final Bucket<ActionRoutingTable> bucket) {
96         rpcRegistrar.tell(new Messages.UpdateRemoteActionEndpoints(ImmutableMap.of(address, Optional.empty())),
97             ActorRef.noSender());
98     }
99
100     @Override
101     protected void onBucketsUpdated(final Map<Address, Bucket<ActionRoutingTable>> buckets) {
102         LOG.debug("Updating buckets for action registry");
103         final Map<Address, Optional<RemoteActionEndpoint>> endpoints = new HashMap<>(buckets.size());
104
105         for (Map.Entry<Address, Bucket<ActionRoutingTable>> e : buckets.entrySet()) {
106             final ActionRoutingTable table = e.getValue().getData();
107
108             final Collection<DOMActionInstance> actions = table.getItems();
109             endpoints.put(e.getKey(), actions.isEmpty() ? Optional.empty()
110                 : Optional.of(new RemoteActionEndpoint(table.getInvoker(), actions)));
111         }
112
113         if (!endpoints.isEmpty()) {
114             rpcRegistrar.tell(new Messages.UpdateRemoteActionEndpoints(endpoints), ActorRef.noSender());
115         }
116     }
117
118     public static final class RemoteActionEndpoint {
119         private final Set<DOMActionInstance> actions;
120         private final ActorRef router;
121
122         @VisibleForTesting
123         public RemoteActionEndpoint(final ActorRef router, final Collection<DOMActionInstance> actions) {
124             this.router = requireNonNull(router);
125             this.actions = ImmutableSet.copyOf(actions);
126         }
127
128         public ActorRef getRouter() {
129             return router;
130         }
131
132         public Set<DOMActionInstance> getActions() {
133             return actions;
134         }
135     }
136
137         /**
138          * All messages used by the ActionRegistry.
139          */
140     public static class Messages {
141         abstract static class AbstractActionRouteMessage {
142             final Collection<DOMActionInstance> addedActions;
143             final Collection<DOMActionInstance> removedActions;
144
145             AbstractActionRouteMessage(final Collection<DOMActionInstance> addedActions,
146                                        final Collection<DOMActionInstance> removedActions) {
147                 this.addedActions = ImmutableList.copyOf(addedActions);
148                 this.removedActions = ImmutableList.copyOf(removedActions);
149             }
150
151             Collection<DOMActionInstance> getAddedActions() {
152                 return this.addedActions;
153             }
154
155             Collection<DOMActionInstance> getRemovedActions() {
156                 return this.removedActions;
157             }
158
159
160             @Override
161             public String toString() {
162                 return "ContainsRoute{" + "addedActions=" + addedActions + " removedActions=" + removedActions + '}';
163             }
164         }
165
166
167         public static final class UpdateActions extends AbstractActionRouteMessage {
168             public UpdateActions(final Collection<DOMActionInstance> addedActions,
169                                  final Collection<DOMActionInstance> removedActions) {
170                 super(addedActions, removedActions);
171             }
172
173         }
174
175         public static final class UpdateRemoteActionEndpoints {
176             private final Map<Address, Optional<RemoteActionEndpoint>> actionEndpoints;
177
178             @VisibleForTesting
179             public UpdateRemoteActionEndpoints(final Map<Address, Optional<RemoteActionEndpoint>>
180                                                                    actionEndpoints) {
181                 this.actionEndpoints = ImmutableMap.copyOf(actionEndpoints);
182             }
183
184             public Map<Address, Optional<RemoteActionEndpoint>> getActionEndpoints() {
185                 return actionEndpoints;
186             }
187         }
188     }
189 }