Bump to odlparent-4.0.13/yangtools-2.1.13/mdsal-3.0.7
[controller.git] / opendaylight / md-sal / sal-akka-raft-example / src / main / java / org / opendaylight / controller / cluster / example / ExampleRoleChangeListener.java
1 /*
2  * Copyright (c) 2014, 2015 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
9 package org.opendaylight.controller.cluster.example;
10
11 import akka.actor.ActorRef;
12 import akka.actor.Cancellable;
13 import akka.actor.Props;
14 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
15 import java.util.HashMap;
16 import java.util.Map;
17 import java.util.concurrent.TimeUnit;
18 import org.opendaylight.controller.cluster.common.actor.AbstractUntypedActor;
19 import org.opendaylight.controller.cluster.example.messages.RegisterListener;
20 import org.opendaylight.controller.cluster.notifications.RegisterRoleChangeListener;
21 import org.opendaylight.controller.cluster.notifications.RegisterRoleChangeListenerReply;
22 import org.opendaylight.controller.cluster.notifications.RoleChangeNotification;
23 import scala.concurrent.Await;
24 import scala.concurrent.duration.FiniteDuration;
25
26 /**
27  * This is a sample implementation of a Role Change Listener which is an actor, which registers itself
28  * to the ClusterRoleChangeNotifier.
29  *
30  * <p>
31  * The Role Change listener receives a SetNotifiers message with the notifiers to register itself with.
32  *
33  * <p>
34  * It kicks of a scheduler which sends registration messages to the notifiers, till it gets a
35  *  RegisterRoleChangeListenerReply.
36  *
37  * <p>
38  * If all the notifiers have been regsitered with, then it cancels the scheduler.
39  * It starts the scheduler again when it receives a new registration
40  */
41 public class ExampleRoleChangeListener extends AbstractUntypedActor implements AutoCloseable {
42     // the akka url should be set to the notifiers actor-system and domain.
43     private static final String NOTIFIER_AKKA_URL = "akka://raft-test@127.0.0.1:2550/user/";
44
45     private final Map<String, Boolean> notifierRegistrationStatus = new HashMap<>();
46     private Cancellable registrationSchedule = null;
47     private static final FiniteDuration DURATION = new FiniteDuration(100, TimeUnit.MILLISECONDS);
48     private static final FiniteDuration SCHEDULER_DURATION = new FiniteDuration(1, TimeUnit.SECONDS);
49     private static final String[] SHARDS_TO_MONITOR = new String[] {"example"};
50
51     public ExampleRoleChangeListener(String memberName) {
52         scheduleRegistrationListener(SCHEDULER_DURATION);
53         populateRegistry(memberName);
54     }
55
56     public static Props getProps(final String memberName) {
57         return Props.create(ExampleRoleChangeListener.class, memberName);
58     }
59
60     @Override
61     protected void handleReceive(Object message) {
62         if (message instanceof RegisterListener) {
63             // called by the scheduler at intervals to register any unregistered notifiers
64             sendRegistrationRequests();
65
66         } else if (message instanceof RegisterRoleChangeListenerReply) {
67             // called by the Notifier
68             handleRegisterRoleChangeListenerReply(getSender().path().toString());
69
70         } else if (message instanceof RoleChangeNotification) {
71             // called by the Notifier
72             RoleChangeNotification notification = (RoleChangeNotification) message;
73
74             LOG.info("Role Change Notification received for member:{}, old role:{}, new role:{}",
75                 notification.getMemberId(), notification.getOldRole(), notification.getNewRole());
76
77             // the apps dependent on such notifications can be called here
78             //TODO: add implementation here
79
80         }
81     }
82
83     private void scheduleRegistrationListener(FiniteDuration interval) {
84         LOG.debug("--->scheduleRegistrationListener called.");
85         registrationSchedule = getContext().system().scheduler().schedule(
86             interval, interval, getSelf(), new RegisterListener(),
87             getContext().system().dispatcher(), getSelf());
88
89     }
90
91     private void populateRegistry(String memberName) {
92         String notifier = new StringBuilder().append(NOTIFIER_AKKA_URL).append(memberName)
93                 .append("/").append(memberName).append("-notifier").toString();
94
95         if (!notifierRegistrationStatus.containsKey(notifier)) {
96             notifierRegistrationStatus.put(notifier, false);
97         }
98
99         if (!registrationSchedule.isCancelled()) {
100             scheduleRegistrationListener(SCHEDULER_DURATION);
101         }
102     }
103
104     @SuppressWarnings("checkstyle:IllegalCatch")
105     @SuppressFBWarnings("REC_CATCH_EXCEPTION")
106     private void sendRegistrationRequests() {
107         for (Map.Entry<String, Boolean> entry : notifierRegistrationStatus.entrySet()) {
108             if (!entry.getValue()) {
109                 try {
110                     LOG.debug("{} registering with {}", getSelf().path().toString(), entry.getKey());
111                     ActorRef notifier = Await.result(
112                         getContext().actorSelection(entry.getKey()).resolveOne(DURATION), DURATION);
113
114                     notifier.tell(new RegisterRoleChangeListener(), getSelf());
115
116                 } catch (Exception e) {
117                     LOG.error("ERROR!! Unable to send registration request to notifier {}", entry.getKey());
118                 }
119             }
120         }
121     }
122
123     private void handleRegisterRoleChangeListenerReply(String senderId) {
124         if (notifierRegistrationStatus.containsKey(senderId)) {
125             notifierRegistrationStatus.put(senderId, true);
126
127             //cancel the schedule when listener is registered with all notifiers
128             if (!registrationSchedule.isCancelled()) {
129                 boolean cancelScheduler = true;
130                 for (Boolean value : notifierRegistrationStatus.values()) {
131                     cancelScheduler = cancelScheduler & value;
132                 }
133                 if (cancelScheduler) {
134                     registrationSchedule.cancel();
135                 }
136             }
137         } else {
138             LOG.info(
139                 "Unexpected, RegisterRoleChangeListenerReply received from notifier which is not known to Listener:{}",
140                 senderId);
141         }
142     }
143
144
145     @Override
146     public void close() {
147         registrationSchedule.cancel();
148     }
149 }