BUG 2185 : Introduce the SwitchBehavior message
[controller.git] / opendaylight / md-sal / sal-akka-raft / src / main / java / org / opendaylight / controller / cluster / raft / RaftActor.java
index ebc157bc1729aff08199b5d6fe4a17b04afdc552..7bf76a70f21139e2a8c1087bd66b8463225320ff 100644 (file)
@@ -16,6 +16,7 @@ import akka.persistence.SnapshotSelectionCriteria;
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.Objects;
 import com.google.common.base.Optional;
+import com.google.common.base.Supplier;
 import com.google.common.collect.Lists;
 import java.io.Serializable;
 import java.util.Collection;
@@ -35,6 +36,7 @@ import org.opendaylight.controller.cluster.notifications.RoleChanged;
 import org.opendaylight.controller.cluster.raft.base.messages.ApplyJournalEntries;
 import org.opendaylight.controller.cluster.raft.base.messages.ApplyState;
 import org.opendaylight.controller.cluster.raft.base.messages.Replicate;
+import org.opendaylight.controller.cluster.raft.base.messages.SwitchBehavior;
 import org.opendaylight.controller.cluster.raft.behaviors.AbstractLeader;
 import org.opendaylight.controller.cluster.raft.behaviors.DelegatingRaftActorBehavior;
 import org.opendaylight.controller.cluster.raft.behaviors.Follower;
@@ -114,6 +116,8 @@ public abstract class RaftActor extends AbstractUntypedPersistentActor {
 
     private final BehaviorStateHolder reusableBehaviorStateHolder = new BehaviorStateHolder();
 
+    private final SwitchBehaviorSupplier reusableSwitchBehaviorSupplier = new SwitchBehaviorSupplier();
+
     public RaftActor(String id, Map<String, String> peerAddresses,
          Optional<ConfigParams> configParams, short payloadVersion) {
 
@@ -190,7 +194,7 @@ public abstract class RaftActor extends AbstractUntypedPersistentActor {
     }
 
     @Override
-    public void handleCommand(Object message) {
+    public void handleCommand(final Object message) {
         if (message instanceof ApplyState){
             ApplyState applyState = (ApplyState) message;
 
@@ -234,15 +238,33 @@ public abstract class RaftActor extends AbstractUntypedPersistentActor {
             );
         } else if(message instanceof GetOnDemandRaftState) {
             onGetOnDemandRaftStats();
+        } else if(message instanceof SwitchBehavior){
+            switchBehavior(((SwitchBehavior) message));
         } else if(!snapshotSupport.handleSnapshotMessage(message)) {
-            reusableBehaviorStateHolder.init(getCurrentBehavior());
-
-            setCurrentBehavior(currentBehavior.handleMessage(getSender(), message));
+            switchBehavior(reusableSwitchBehaviorSupplier.handleMessage(getSender(), message));
+        }
+    }
 
-            handleBehaviorChange(reusableBehaviorStateHolder, getCurrentBehavior());
+    private void switchBehavior(SwitchBehavior message) {
+        if(!getRaftActorContext().getRaftPolicy().automaticElectionsEnabled()) {
+            RaftState newState = message.getNewState();
+            if( newState == RaftState.Leader || newState == RaftState.Follower) {
+                switchBehavior(reusableSwitchBehaviorSupplier.handleMessage(getSender(), message));
+                getRaftActorContext().getTermInformation().updateAndPersist(message.getNewTerm(), "");
+            } else {
+                LOG.warn("Switching to behavior : {} - not supported", newState);
+            }
         }
     }
 
+    private void switchBehavior(Supplier<RaftActorBehavior> supplier){
+        reusableBehaviorStateHolder.init(getCurrentBehavior());
+
+        setCurrentBehavior(supplier.get());
+
+        handleBehaviorChange(reusableBehaviorStateHolder, getCurrentBehavior());
+    }
+
     protected RaftActorSnapshotMessageSupport newRaftActorSnapshotMessageSupport() {
         return new RaftActorSnapshotMessageSupport(context, currentBehavior,
                 getRaftActorSnapshotCohort());
@@ -655,4 +677,23 @@ public abstract class RaftActor extends AbstractUntypedPersistentActor {
             return leaderPayloadVersion;
         }
     }
+
+    private class SwitchBehaviorSupplier implements Supplier<RaftActorBehavior> {
+        private Object message;
+        private ActorRef sender;
+
+        public SwitchBehaviorSupplier handleMessage(ActorRef sender, Object message){
+            this.sender = sender;
+            this.message = message;
+            return this;
+        }
+
+        @Override
+        public RaftActorBehavior get() {
+            if(this.message instanceof SwitchBehavior){
+                return ((SwitchBehavior) message).getNewState().createBehavior(getRaftActorContext());
+            }
+            return currentBehavior.handleMessage(sender, message);
+        }
+    }
 }