/*
 * Copyright (c) 2015 Huawei Technologies Co., Ltd. and others.  All rights reserved.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
 * and is available at http://www.eclipse.org/legal/epl-v10.html
 */

package org.opendaylight.controller.cluster.common.actor;

import akka.actor.Props;
import akka.actor.UntypedActor;
import akka.japi.Effect;
import akka.remote.AssociationErrorEvent;
import akka.remote.InvalidAssociation;
import akka.remote.RemotingLifecycleEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * This class listens to Akka RemotingLifecycleEvent events to detect when this node has been
 * quarantined by another. Once this node gets quarantined, restart the ActorSystem to allow this
 * node to rejoin the cluster.
 *
 * @author Gary Wu gary.wu1@huawei.com
 *
 */
public class QuarantinedMonitorActor extends UntypedActor {

    private static final Logger LOG = LoggerFactory.getLogger(QuarantinedMonitorActor.class);

    public static final String ADDRESS = "quarantined-monitor";

    private final Effect callback;
    private boolean quarantined;

    protected QuarantinedMonitorActor(Effect callback) {
        this.callback = callback;

        LOG.debug("Created QuarantinedMonitorActor");

        getContext().system().eventStream().subscribe(getSelf(), RemotingLifecycleEvent.class);
    }

    @Override
    public void postStop() {
        LOG.debug("Stopping QuarantinedMonitorActor");
    }

    @Override
    public void onReceive(Object message) throws Exception {
        final String messageType = message.getClass().getSimpleName();
        LOG.trace("onReceive {} {}", messageType, message);

        // check to see if we got quarantined by another node

        if (quarantined) {
            return;
        }

        // TODO: follow https://github.com/akka/akka/issues/18758 to see if Akka adds a named
        // exception for quarantine detection
        if (message instanceof AssociationErrorEvent) {
            AssociationErrorEvent event = (AssociationErrorEvent) message;
            Throwable cause = event.getCause();
            if (cause instanceof InvalidAssociation) {
                Throwable cause2 = ((InvalidAssociation) cause).getCause();
                if (cause2.getMessage().contains("quarantined this system")) {
                    quarantined = true;

                    LOG.warn("Got quarantined by {}", event.getRemoteAddress());

                    // execute the callback
                    callback.apply();
                } else {
                    LOG.debug("received AssociationErrorEvent, cause: InvalidAssociation", cause2);
                }
            } else {
                LOG.debug("received AssociationErrorEvent", cause);
            }
        }
    }

    public static Props props(final Effect callback) {
        return Props.create(QuarantinedMonitorActor.class, callback);
    }
}

@@ -476,106 +476,34 @@
 ote.
-AssociationErrorEvent;%0Aimport akka.remote.InvalidAssociation;%0Aimport akka.remote.RemotingLifecycle
+ThisActorSystemQuarantined
 Even
@@ -1167,16 +1167,22 @@
 orActor(
+final 
 Effect c
@@ -1347,33 +1347,42 @@
 Self(), 
-RemotingLifecycle
+ThisActorSystemQuarantined
 Event.cl
@@ -1539,16 +1539,22 @@
 Receive(
+final 
 Object m
@@ -1774,17 +1774,16 @@
 er node%0A
-%0A
         
@@ -1844,578 +1844,167 @@
     
-// TODO: follow https://github.com/akka/akka/issues/18758 to see if Akka adds a named%0A        // exception for quarantine detection%0A        if (message instanceof AssociationErrorEvent) %7B%0A            AssociationErrorEvent event = (AssociationErrorEvent) message;%0A            Throwable cause = event.getCause();%0A            if (cause instanceof InvalidAssociation) %7B%0A                Throwable cause2 = ((InvalidAssociation) cause).getCause();%0A                if (cause2.getMessage().contains(%22quarantined this system%22)) %7B%0A                    quarantined = true;%0A%0A        
+if (message instanceof ThisActorSystemQuarantinedEvent) %7B%0A            final ThisActorSystemQuarantinedEvent event = (ThisActorSystemQuarantinedEvent) message;%0A
     
@@ -2055,12 +2055,9 @@
 ent.
-getR
+r
 emot
@@ -2069,25 +2069,24 @@
 ess());%0A
-%0A
         
         
@@ -2069,32 +2069,57 @@
 ess());%0A        
+    quarantined = true;%0A%0A
             // e
@@ -2150,24 +2150,16 @@
         
-   
-     
 callback
@@ -2172,254 +2172,8 @@
 ();%0A
-                %7D else %7B%0A                    LOG.debug(%22received AssociationErrorEvent, cause: InvalidAssociation%22, cause2);%0A                %7D%0A            %7D else %7B%0A                LOG.debug(%22received AssociationErrorEvent%22, cause);%0A            %7D%0A
     

Simplify QuarantinedMonitorActor