/**
* Fortika - Robust Group Communication
* Copyright (C) 2002-2006 Sergio Mena de la Cruz (EPFL) (sergio.mena@epfl.ch)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
// ###############################
// Projet de semestre I&C - LSR
// He Hui-Yang Informatique
// F�vrier 2005
// ###############################
package groupcomm.common.fd;
import java.io.OutputStream;
import java.io.PrintStream;
import java.util.logging.Level;
import java.util.logging.Logger;
import framework.Constants;
import framework.GroupCommEventArgs;
import framework.GroupCommException;
import framework.GroupCommMessage;
import framework.PID;
import framework.libraries.Timer;
import framework.libraries.Trigger;
public class FDRHandler{
private PID myself;
//defaut value for suspicion and heartbeat
private static final int TIME_SUSPECT=5000;
private static final int TIME_HEARTBEAT=2000;
//precedent and succcessor
private PID pre;
private PID suc;
//define time for suspicion
private int timeS= TIME_SUSPECT;
//define time for heartbeat
private int timeH=TIME_HEARTBEAT;
//Initialize a timer for suspicion and heartbeat
private Timer timer;
//initialize a trigger
private Trigger trigger;
//variable for detecting if precedent is suspected
public boolean suspected=false;
//initialize a logger
private static final Logger logger=Logger.getLogger(FDRHandler.class.getName());
//constructor of Fault Detector R
public FDRHandler( Trigger trigger, Timer timer,
PID myself,PID pre, PID suc,
int timeS,int timeH) throws GroupCommException{
logger.entering("FDRHandler","<constr> 7 parameters");
this.trigger=trigger;
this.timer=timer;
this.myself=myself;
this.pre=pre;
this.suc=suc;
//precedent and successor should not be the same
if (pre.equals(suc)){
throw new GroupCommException("pre and suc can not be the same");}
//time for suspicion must be positive
if (timeS>0)
this.timeS=timeS;
logger.log(Level.FINE,"Scheduling timer for: {0} not periodic with time:{1}",
new Object[] {pre,new Integer(timeS)});
//schedule timer for precedent
timer.schedule(pre,false,this.timeS);
//time for heartbeat must be positive
if (timeH>0)
this.timeH=timeH;
logger.log(Level.FINE,"Scheduling timer for: {0} periodic with time:{1}",
new Object[] {suc,new Integer(timeH)});
//schedule timer for successor
timer.schedule(suc,true,this.timeH);
logger.exiting("FDRHandler","<constr> 7 parameters");
}
//change the precedent
public void changePre(PID newPre) throws GroupCommException{
//cancel the timer for the old precedent only if it is not suspected
if (!suspected)
timer.cancel(pre);
//validate the new precedent
pre = newPre;
//precedent and successor cannot be the same
if (pre.equals(suc)){
throw new GroupCommException("pre and suc can not be the same");
}
//reinitialize boolean suspected
suspected=false;
logger.log(Level.FINE,"Scheduling timer for: {0} not periodic with time:{1}",
new Object[] {pre,new Integer(timeS)});
//schedule timer for the new precedent
timer.schedule(pre,false,timeS);
}
//change the successor
public void changeSuc(PID newSuc) throws GroupCommException{
//cancel timer of the lod successor
timer.cancel(suc);
//validate the new successor
suc= newSuc;
//precedent and successor cannot be the same
if (suc.equals(pre)){
throw new GroupCommException("pre and suc can not be the same");
}
logger.log(Level.FINE,"Scheduling timer for: {0} periodic with time:{1}",
new Object[] {suc,new Integer(timeH)});
//schedule timer for the new successor
timer.schedule(suc,true,timeH);
}
//deal with the suspicion of the precedent
public void handleUdpDeliver(GroupCommEventArgs arg){
logger.entering("FDRHandler","handleSuspicion");
//obtain the precessor to suspect by unpacking from the message
PID pid=(PID)(((GroupCommMessage)arg.get(0)).tunpack());
//if the precessor is really his precedent
if (pid.equals(pre)){
if (suspected){//if it has been suspected,we have to reactive it
triggerSuspect(null);
suspected=false;
logger.log(Level.FINE,"Scheduling timer for: {0} not periodic with time:{1}",
new Object[] {pre,new Integer(timeS)});
//schedule timer for the precedent
timer.schedule(pre,false,timeS);
}
else
{
logger.log(Level.FINE,"Resetting timer for: {0} ", pre);
//reset timer for the precedent
timer.reset(pre);
}
}
logger.exiting("FDRHandler","handleSuspicion");
}
//deal with timeout of timer
public void handleTimeout(GroupCommEventArgs arg){
//obtain the processor from event received
PID p=(PID)(arg.get(0));
//if it is the precedent, decide to suspect
if (p.equals(pre)){
//if not suspected yet
if (!suspected){
suspected=true;
logger.log(Level.FINE,"Suspecting : {0} ", pre);
//suspect precedent
triggerSuspect(pre);
}
}
//if it is successor, send a heartbeat
else if (p.equals(suc)){
logger.log(Level.FINE,"Sending heartbeat to : {0} ", suc);
//send heartbeat to successor
triggerSend(suc);
}
}
//handler of suspicion
private void triggerSuspect(PID pid){
logger.entering("FDRHandler","triggerSuspect");
GroupCommEventArgs e=new GroupCommEventArgs();
//add processor to event
e.addLast(pid);
//trigger event
logger.log(Level.FINE,"triggering event Suspect: {0} ", e);
trigger.trigger(Constants.SUSPECT,e);
logger.exiting("FDRHandler","triggerSuspect");
}
//handler of send heartbeat
private void triggerSend(PID dest){
logger.entering("FDRHandler","triggerSend");
GroupCommMessage m=new GroupCommMessage();
//pack myself in message m
m.tpack(myself);
GroupCommEventArgs e=new GroupCommEventArgs();
//add message and precessor destinated to event to be sent
e.addLast(m);
e.addLast(dest);
//trigger event
logger.log(Level.FINE,"triggering event UdpSend: {0} ", e);
trigger.trigger(Constants.UDPSEND,e);
logger.exiting("FDRHandler","triggerSend");
}
/**
* Used for debugging. </br>
* Undocumented.
*/
public void dump(OutputStream out) {
PrintStream err = new PrintStream(out);
err.println("========= FDRHandler: dump =========");
err.println(" Previous Process: " + pre);
err.println(" Successive Process:" +suc);
err.println(" Precedent Suspected or not: " + suspected);
err.println(" Timeout set for suspicion: " + timeS);
err.println(" Timeout set for heartbeat: " + timeH);
err.println("===================================");
}
}