/**
* SAMOA - PROTOCOL FRAMEWORK
* Copyright (C) 2005 Olivier Rütti (EPFL) (olivier.rutti@a3.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
*/
package seqSamoa;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.logging.ConsoleHandler;
import java.util.logging.FileHandler;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.logging.SimpleFormatter;
import java.util.logging.StreamHandler;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;
import seqSamoa.exceptions.AlreadyBoundServiceException;
import seqSamoa.exceptions.AlreadyExistingProtocolModuleException;
import seqSamoa.exceptions.AlreadyExistingServiceException;
import seqSamoa.exceptions.SamoaClassException;
import seqSamoa.protocols.pt2pt.ProtocolPT2PT;
import seqSamoa.protocols.rpt2pt.ProtocolRPT2PT;
import seqSamoa.protocols.udp.ProtocolUDP;
import seqSamoa.services.monitoring.ProcessSuspicion;
import seqSamoa.services.pt2pt.PT2PT;
import seqSamoa.services.rpt2pt.RPT2PT;
import seqSamoa.services.udp.UDP;
import uka.transport.Transportable;
import framework.PID;
import framework.libraries.BinaryStableStorage;
import framework.libraries.StableStorage;
import framework.libraries.serialization.TList;
/**
* <CODE>ProtocolStack</CODE> is the base class for all protocol stacks.
*/
public class ProtocolStack {
// Is the stack currently in a reconfiguration process
protected boolean isReconfigured;
// Flow Control
protected SamoaFlowControl fc;
// Scheduler
protected SamoaScheduler scheduler;
// Callbacks
private Callback callback;
// Process ID of the stack (unique)
private PID myself;
// Group of processes communicating with the stack
private TList processes;
// Storage
private StableStorage storage;
// Recover Log File Name
private String recoverLogFileName;
// Logger
private Logger logger;
// All protocols, services and final listeners
protected HashMap<String, ProtocolModule> allProtocols = new HashMap<String, ProtocolModule>();
@SuppressWarnings("unchecked")
protected HashMap<String, Service> allServices = new HashMap<String, Service>();
@SuppressWarnings("unchecked")
private HashMap<String, Service.Listener> allFinalListeners = new HashMap<String, Service.Listener>();
// Fake Protocol for Final Listeners
protected ProtocolModule pFake;
// UDP Protocol and Service
protected UDP udp;
protected ProtocolUDP pUDP;
// RPT2PT Protocol and Services
protected RPT2PT rpt2pt;
protected ProcessSuspicion processSuspicion;
protected ProtocolRPT2PT pRPT2PT;
// PT2PT
protected PT2PT pt2pt;
protected ProtocolPT2PT pPT2PT;
// Register a service in the stack
@SuppressWarnings("unchecked")
protected void registerService(Service s)
throws AlreadyExistingServiceException {
if (!this.allServices.containsKey(s.name))
this.allServices.put(s.name, s);
else
throw new AlreadyExistingServiceException(s);
}
// Register a protocol in the stack
protected void registerProtocolModule(ProtocolModule p)
throws AlreadyExistingProtocolModuleException {
if (!this.allProtocols.containsKey(p.name))
this.allProtocols.put(p.name, p);
else
throw new AlreadyExistingProtocolModuleException(p);
}
// Register a final listeners
@SuppressWarnings("unchecked")
protected void registerFinalListener(Service.Listener l) {
this.allFinalListeners.put(l.getService().name, l);
}
/**
* Constructor for stack in a crash-stop model with default values:
* with udp and rpt2pt, new scheduler, new flow control, log on System.out and log producer crash-stop protocols
*
*
* @param myself
* the Process ID of the stack (should be unique)
* @param processes
* the list of processes that run the same stack
* @param callback
* the {@link seqSamoa.Callback callback} that gets the responses of this stack
*/
public ProtocolStack(PID myself, TList processes, Callback callback) {
create_stack(myself, processes, new SamoaScheduler(new SequentialManager()), new SamoaFlowControl(100), callback, null, "groupcomm",
true, true, false);
this.recoverLogFileName = null;
this.storage = null;
}
/**
* Constructor for stack in a crash-stop model.
*
* @param myself
* the Process ID of the stack (should be unique)
* @param processes
* the list of processes that run the same stack
* @param scheduler
* the {@link seqSamoa.SamoaScheduler scheduler} that manages executions in the stack
* @param fc
* the {@link seqSamoa.SamoaFlowControl flowcontrol} dedicated this stack
* @param callback
* the {@link seqSamoa.Callback callback} that gets the responses of this stack
* @param logFile
* name of the file where to log the infos
* @param logName
* name of the log producer
* @param udp
* true, if the stack uses UDP network
* @param rp2p
* true, if the stack uses reliable point to point channels */
public ProtocolStack(PID myself, TList processes, SamoaScheduler scheduler, SamoaFlowControl fc, Callback callback,
String logFile, String logName, boolean udp, boolean rp2p) {
create_stack(myself, processes, scheduler, fc, callback,
logFile, logName, udp, rp2p, false);
this.recoverLogFileName = null;
this.storage = null;
}
/**
* Constructor for stack in a crash-recovery model with default values:
* with udp and pt2pt, new scheduler, new flowcontrol, log on System.out and log producer crash-stop protocols
*
*
* @param myself
* the Process ID of the stack (should be unique)
* @param processes
* the list of processes that run the same stack
* @param callback
* the {@link seqSamoa.Callback callback} that gets the responses of this stack
* @param recoverLogName
* name of the log file that contains info about recovery
* @param recoverFileName
* name of the file that contains info logged by protocols for recovery
*/
public ProtocolStack(PID myself, TList processes, Callback callback,
String recoverLogName, String recoverFileName) {
create_stack(myself, processes, new SamoaScheduler(new SequentialManager()), new SamoaFlowControl(100), callback, null,
"static_recovery", true, false, true);
// Init the storage for recovery
this.recoverLogFileName = recoverLogName;
this.storage = new BinaryStableStorage(recoverFileName);
}
/**
* Constructor for stack in a crash-recovery model.
*
* @param myself
* the Process ID of the stack (should be unique)
* @param processes
* the list of processes that run the same stack
* @param scheduler
* the {@link seqSamoa.SamoaScheduler scheduler} that manages executions in the stack
* @param fc
* the {@link seqSamoa.SamoaFlowControl flowcontrol} dedicated this stack
* @param callback
* the {@link seqSamoa.Callback callback} that gets the responses of this stack
* @param logFile
* name of the file where to log the infos
* @param logName
* name of the log producer
* @param recoverLogName
* name of the log file that contains info about recovery
* @param recoverFileName
* name of the file that contains info logged by protocols for recovery
* @param udp
* true, if the stack uses UDP network
* @param rp2p
* true, if the stack uses reliable point to point channels (assumes a crash-stop model)
*/
public ProtocolStack(PID myself, TList processes, SamoaScheduler scheduler, SamoaFlowControl fc, Callback callback,
String logFile, String logName, String recoverLogName,
String recoverFileName, boolean udp, boolean rp2p) {
create_stack(myself, processes, scheduler, fc, callback,
logFile, logName, udp, false, rp2p);
// Init the storage for recovery
this.recoverLogFileName = recoverLogName;
this.storage = new BinaryStableStorage(recoverFileName);
}
/**
* Constructor for stack according to an XMLfile with default values:
* with udp and pt2pt, new scheduler, new flowcontrol, log on System.out and log producer crash-stop protocols
*
* @param myself
* the Process ID of the stack (should be unique)
* @param processes
* the list of processes that run the same stack
* @param callback
* the {@link seqSamoa.Callback callback} that gets the responses of this stack
* @param recoverLogName
* name of the log file that contains info about recovery
* @param recoverFileName
* name of the file that contains info logged by protocols for recovery
* @param XMLfile
* name of the file that contains the description of the stack
*/
public ProtocolStack(PID myself, TList processes, Callback callback,
String recoverLogName, String recoverFileName, String XMLfile)
throws IOException, JDOMException, SamoaClassException,
AlreadyExistingServiceException,
AlreadyExistingProtocolModuleException {
create_stack_from_xml(myself, processes, new SamoaScheduler(new SequentialManager()), new SamoaFlowControl(100), callback, null,
null, recoverLogName, recoverFileName, XMLfile);
}
/**
* Constructor for stack according to an XMLfile.
*
* @param myself
* the Process ID of the stack (should be unique)
* @param processes
* the list of processes that run the same stack
* @param scheduler
* the {@link seqSamoa.SamoaScheduler scheduler} that manages executions in the stack
* @param fc
* the {@link seqSamoa.SamoaFlowControl flowcontrol} dedicated this stack
* @param callback
* the {@link seqSamoa.Callback callback} that gets the responses of this stack
* @param logFile
* name of the file where to log the infos
* @param logName
* name of the log producer
* @param recoverLogName
* name of the log file that contains info about recovery
* @param recoverFileName
* name of the file that contains info logged by protocols for recovery
* @param XMLfile
* name of the file that contains the description of the stack
*/
public ProtocolStack(PID myself, TList processes, SamoaScheduler scheduler, SamoaFlowControl fc, Callback callback,
String logFile, String logName, String recoverLogName,
String recoverFileName, String XMLfile) throws IOException,
JDOMException, SamoaClassException,
AlreadyExistingServiceException,
AlreadyExistingProtocolModuleException {
create_stack_from_xml(myself, processes, scheduler, fc,
callback, logFile, logName, recoverLogName, recoverFileName,
XMLfile);
}
@SuppressWarnings("unchecked")
private void create_stack_from_xml(PID myself, TList processes,
SamoaScheduler scheduler, SamoaFlowControl fc,
Callback callback, String logFile, String logName,
String recoverLogName, String recoverFileName, String XMLfile)
throws IOException, JDOMException, SamoaClassException,
AlreadyExistingServiceException,
AlreadyExistingProtocolModuleException {
// Check if there is a stack file in the tmp folder
File xmlfile = new File(XMLfile);
if (!xmlfile.exists())
throw new SamoaClassException("The stack description does not exist: "+XMLfile);
// Start analyse of the files
SAXBuilder sxb = new SAXBuilder();
Document document = sxb.build(xmlfile);
List protocols = document.getRootElement().getChild("Protocols")
.getChildren("Protocol");
List services = document.getRootElement().getChild("Services")
.getChildren("Service");
// Check if the stack is Recovery and also for communication protocols
for (int i = 0; i < protocols.size(); i++) {
Element prot = (Element) protocols.get(i);
String model = prot.getChildText("Model");
// By default the protocol is for the crash stop model
if ((model!=null) && (model.equals("Crash recovery"))) {
// Create the recovery file
this.recoverLogFileName = recoverLogName;
this.storage = new BinaryStableStorage(recoverFileName);
}
}
// Set the basic fields of the stack
this.myself = myself;
this.processes = processes;
this.scheduler = scheduler;
this.fc = fc;
this.callback = callback;
this.isReconfigured = false;
// Init the logging
if (logName != null) {
try {
Handler logHandler = null;
logger = Logger.getLogger(logName);
// Logging handler
if (logFile == null) {
// System.err
logHandler = new ConsoleHandler();
} else if (logFile.equals("out")) {
// System.out
logHandler = new StreamHandler(System.out,
new SimpleFormatter());
} else {
// File
logHandler = new FileHandler(logFile);
logHandler.setFormatter(new SimpleFormatter());
}
logHandler.setLevel(Level.ALL);
logger.setLevel(Level.OFF);
logger.addHandler(logHandler);
} catch (IOException ioe) {
throw new RuntimeException("Wrong log file name: "
+ ioe.getMessage());
}
}
// Check that "myself" is in "processes"
if (!processes.isEmpty() && !processes.contains(myself))
throw new RuntimeException("Bad arguments: the local PID "
+ "is not contained in the group!!");
// Create the fake protocol
// Create network services and protocols
try {
this.pFake = new ProtocolModule("fake", this);
this.allProtocols.remove("fake");
} catch (AlreadyExistingProtocolModuleException aem) {
throw new RuntimeException(
"Should not be possible! Bug in conception.");
}
// Construct all the services
Iterator itServices = services.iterator();
while (itServices.hasNext()) {
Element service = (Element) itServices.next();
newService(service);
}
// Construct all the protocols
Iterator itProtocols = protocols.iterator();
while (itProtocols.hasNext()) {
Element module = (Element) itProtocols.next();
newProtocolModule(module);
}
}
private void create_stack(PID myself, TList processes,
SamoaScheduler scheduler, SamoaFlowControl fc,
Callback callback, String logFile, String logName, boolean udp,
boolean rp2p, boolean p2p) {
this.myself = myself;
this.processes = processes;
this.scheduler = scheduler;
this.fc = fc;
this.callback = callback;
this.isReconfigured = false;
// Init the logging
if (logName != null) {
try {
Handler logHandler = null;
logger = Logger.getLogger(logName);
// Logging handler
if (logFile == null) {
// System.err
logHandler = new ConsoleHandler();
} else if (logFile.equals("out")) {
// System.out
logHandler = new StreamHandler(System.out,
new SimpleFormatter());
} else {
// File
logHandler = new FileHandler(logFile);
logHandler.setFormatter(new SimpleFormatter());
}
logHandler.setLevel(Level.ALL);
logger.setLevel(Level.OFF);
logger.addHandler(logHandler);
} catch (IOException ioe) {
throw new RuntimeException("Wrong log file name: "
+ ioe.getMessage());
}
}
// Check that "myself" is in "processes"
if (!processes.isEmpty() && !processes.contains(myself))
throw new RuntimeException("Bad arguments: the local PID \""
+ myself
+ "\" is not contained in the group!!");
// Create the fake protocol
// Create network services and protocols
try {
this.pFake = new ProtocolModule("fake", this);
this.allProtocols.remove("fake");
if (udp || p2p) {
this.udp = new UDP("udp", this);
this.pUDP = new ProtocolUDP(new String("udp"), this, this.udp);
}
if (rp2p) {
this.rpt2pt = new RPT2PT("rpt2pt", this);
this.processSuspicion = new ProcessSuspicion(
"processSuspicion", this);
this.pRPT2PT = new ProtocolRPT2PT(new String("rpt2pt"), this,
3000, 30000, 5000, rpt2pt, processSuspicion);
}
if (p2p) {
this.pt2pt = new PT2PT("pt2pt", this);
this.pPT2PT = new ProtocolPT2PT(new String("pt2pt"), this, 100,
pt2pt, this.udp);
}
} catch (AlreadyExistingServiceException aes) {
throw new RuntimeException(
"Should not be possible! Bug in conception.");
} catch (AlreadyExistingProtocolModuleException aem) {
throw new RuntimeException(
"Should not be possible! Bug in conception.");
}
}
/**
* Call a {@link seqSamoa.Service service}
*
* @param serviceName
* the name identifying the {@link seqSamoa.Service service} to call
* @param params
* the parameters of the {@link seqSamoa.Service service} call
* @param toSend
* the message of the {@link seqSamoa.Service service} call
*/
@SuppressWarnings("unchecked")
synchronized public void serviceCall(final String serviceName,
final Object params, final Transportable toSend) {
Service service = allServices.get(serviceName);
Message dmessage = null;
if (toSend != null)
dmessage = new Message(toSend, allFinalListeners.get(serviceName));
fc.enter();
long cid = service.externalCall(params, dmessage);
this.scheduler.waitEnd(cid);
}
/**
* Return the {@link seqSamoa.SamoaFlowControl flowcontrol} dedicated to this stack
*
* @return
* the {@link seqSamoa.SamoaFlowControl flowcontrol}
*/
public SamoaFlowControl getFlowControl() {
return this.fc;
}
/**
* Return the {@link seqSamoa.SamoaScheduler scheduler} dedicated to this stack
*
* @return
* the {@link seqSamoa.SamoaScheduler scheduler}
*/
public SamoaScheduler getScheduler() {
return this.scheduler;
}
/**
* Return the process ID attached to this stack
*
* @return
* the process ID attached to this stack
*/
public PID getPID() {
return this.myself;
}
/**
* Return the group of processes that run the same stack
*
* @return
* the group of processes that run the same stack
*/
public TList getGroup() {
return this.processes;
}
/**
* Set the group of processes that run the same stack
*/
public void setGroup(TList processes) {
this.processes = processes;
}
/**
* Return the reconfiguration status of the stack. Note that
* when the stack will be reconfigured (status = true),
* there is no concurrency in the stack.
*
* @return
* the reconfiguration status of the stack
*/
public boolean getReconfigurationStatus() {
return this.isReconfigured;
}
/**
* Set the reconfiguration status of the stack. Note that
* when the stack will be reconfigured, there is no concurrency
* in the stack.
*
* @param isReconfigured
* true, if the stack has to be reconfigured. False otherwise
*/
public void setReconfigurationStatus(boolean isReconfigured) {
this.isReconfigured = isReconfigured;
if (!this.isReconfigured)
this.scheduler.stackReconfigured(this);
}
/**
* Return the storage for committing information
*
* @return
* the storage for committing information
*/
public StableStorage getStorage() {
return this.storage;
}
/**
* Return the {@link seqSamoa.Callback callback} attached to the stack
*
* @return
* the {@link seqSamoa.Callback callback} attached to the stack
*/
public Callback getCallback() {
return this.callback;
}
/**
* Return the {@link seqSamoa.Service service} that corresponds to the given name.
* @param name
* the name of the {@link seqSamoa.Service service}
* @return
* the {@link seqSamoa.Service service}
*/
@SuppressWarnings("unchecked")
public Service getService(String name) {
return this.allServices.get(name);
}
/**
* Return the {@link seqSamoa.ProtocolModule protocol} that corresponds to the given name.
* @param name
* the name of the {@link seqSamoa.ProtocolModule protocol}
* @return
* the {@link seqSamoa.ProtocolModule protocol}
*/
public ProtocolModule getProtocol(String name) {
return this.allProtocols.get(name);
}
/**
* Create a new Service and add it to the stack
*
* @param service
* The XML element that describes the service to be created
*
* @return
* the {@link seqSamoa.Service service} that is created
*
* @throws SamoaClassException, AlreadyBoundServiceException
*/
@SuppressWarnings("unchecked")
public Service newService(Element service) throws SamoaClassException,
AlreadyExistingServiceException {
String className = service.getChild("Class").getChildText("Name");
String packageName = service.getChild("Class").getChildText("Package");
String name = service.getChildText("Name");
Service result = null;
if (allServices.containsKey(name))
throw new AlreadyExistingServiceException(name);
try {
Class classService = Class.forName(packageName+"."+className);
Object[] paramsService = new Object[] {name, this};
Constructor constructorObject = classService.getConstructors()[0];
result = (Service) constructorObject.newInstance(paramsService);
} catch (ClassNotFoundException ex) {
throw new SamoaClassException(service.toString()
+ " class can not be found");
} catch (InstantiationException ex) {
throw new SamoaClassException(service.toString()
+ " class can't be instantiated");
} catch (IllegalAccessException ex) {
throw new SamoaClassException(service.toString()
+ " could not access the constructor of the class");
} catch (InvocationTargetException ex) {
// the construct threw an exception
throw new SamoaClassException(service.toString()
+ "results in InvocationTargetException(" + ex.getMessage()
+ ") caused by " + ex.getCause());
}
if (Boolean.parseBoolean(service.getChildText("ServiceFinal"))) {
result.new Listener(this, new LinkedList<ServiceCallOrResponse>()) {
synchronized public void evaluate(Object infos,
Transportable message) {
callback.serviceCallback(infos, message);
}
};
}
if (!Boolean.parseBoolean(service.getChildText("ServiceProvided"))) {
Service.Executer executer = result.new Executer(this, new LinkedList<ServiceCallOrResponse>()) {
synchronized public void evaluate(Object params,
Message dmessage) {
callback.serviceCallback(params, dmessage);
}
};
try {
executer.link();
} catch (AlreadyBoundServiceException aes) {
throw new RuntimeException(
"Should not be possible! Error in the conception.");
}
}
return result;
}
/**
* Create a new ProtocolModule and add it to the stack
*
* @param module
* The XML element that describes the protocol module to be
* created
*
* @return
* the {@link seqSamoa.ProtocolModule protocol} that is created
*
* @throws SamoaClassException,
* AlreadyBoundServiceException
*/
@SuppressWarnings("unchecked")
public ProtocolModule newProtocolModule(Element module)
throws SamoaClassException, AlreadyExistingProtocolModuleException {
String className = module.getChild("Class").getChildText("Name");
String packageName = module.getChild("Class").getChildText("Package");
String name = module.getChildText("Name");
if (allProtocols.containsKey(module.getChildText("Name")))
throw new AlreadyExistingProtocolModuleException(module
.getChildText("Name"));
// construct the params list
LinkedList<Object> protParams = new LinkedList<Object>();
protParams.add(name);
protParams.add(this);
List params = module.getChild("Parameters").getChildren("Parameter");
for (int i = 0; i< params.size(); i++) {
Element param = (Element) params.get(i);
String paramType = param.getChildText("Type");
String paramValue = param.getChildText("Value");
if (paramType.equals("java.lang.Integer")) {
protParams.addLast(new Integer(paramValue));
} else if (paramType.equals("java.lang.Boolean")) {
protParams.addLast(new Boolean(paramValue));
} else if (paramType.equals("java.lang.Long")) {
protParams.addLast(new Long(param.getChildText("Value")));
} else if (paramType.equals("java.lang.String")) {
protParams.addLast(paramValue);
}
}
// add the services provided
List providedServices = module.getChild("ProvidedServices")
.getChildren("ProvidedService");
for (int i = 0; i < providedServices.size(); i++) {
String serviceName = ((Element) providedServices.get(i))
.getChildText("Name");
protParams.addLast(this.getService(serviceName));
}
// add the services required
List requiredServices = module.getChild("RequiredServices")
.getChildren("RequiredService");
for (int i = 0; i < requiredServices.size(); i++) {
String serviceName = ((Element) requiredServices.get(i))
.getChildText("Name");
protParams.addLast(this.getService(serviceName));
}
try {
Class classModule = Class.forName(packageName + "." + className);
Constructor constructorObject = classModule.getConstructors()[0];
return (ProtocolModule) constructorObject.newInstance(protParams
.toArray());
} catch (ClassNotFoundException ex) {
throw new SamoaClassException(module.toString() + " class can not be found");
} catch (InstantiationException ex) {
throw new SamoaClassException(module.toString() +
" class can't be instantiated");
} catch (IllegalAccessException ex) {
throw new SamoaClassException(module.toString() +
" could not access the constructor of the class");
} catch (InvocationTargetException ex) {
// the construct threw an exception
throw new SamoaClassException(module.toString()
+ "results in InvocationTargetException(" + ex.getMessage()
+ ") caused by " + ex.getCause());
}
}
@SuppressWarnings("unchecked")
public String toString() {
StringBuffer result = new StringBuffer();
Iterator<String> it = allServices.keySet().iterator();
while(it.hasNext()) {
String nameService = it.next();
Service service = allServices.get(nameService);
String classService = service.getClass().toString();
ProtocolModule prot = service.getProvider();
if (prot !=null)
result.append(classService+" "+nameService+" provided by "+prot.getClass().toString()+" "+prot.name+" \n");
else
result.append(classService+" "+nameService+" has no provider \n");
}
return result.toString();
}
/**
* Remove a protocol module from the stack
*
* @param m
* the {@link seqSamoa.ProtocolModule protocol} to be removed
*/
public void removeProtocolModule(ProtocolModule m) {
this.allProtocols.remove(m.name);
}
/**
* Initialize the stack: initialize the {@link seqSamoa.SamoaScheduler scheduler}
* and all the {@link seqSamoa.ProtocolModule protocols} in the stack
*
* @throws AlreadyBoundServiceException
*/
public void init() throws AlreadyBoundServiceException {
// Link all protocols to the service they provide
Iterator<ProtocolModule> it = allProtocols.values().iterator();
while (it.hasNext())
it.next().linkToService();
// Bind all interceptors
it = allProtocols.values().iterator();
while (it.hasNext())
it.next().bindInterceptors();
// Start the timer and the scheduler
this.scheduler.stackReconfigured(this);
this.scheduler.start();
// Init all protocols
AtomicTask initTask = new AtomicTask() {
public void execute() {
Iterator<ProtocolModule> it = allProtocols.values().iterator();
while (it.hasNext())
it.next().init();
// Recover all protocols if needed
// TODO: recover the architecture of the stack
if (recoverLogFileName != null) {
File recoveryLogFile = new File(recoverLogFileName);
if (recoveryLogFile.exists()) {
System.out
.println("We have recovered, processing the recovery...");
it = allProtocols.values().iterator();
while (it.hasNext())
it.next().recovery(true);
} else {
try {
recoveryLogFile.createNewFile();
} catch (IOException ioe) {
throw new RuntimeException(
"ApiSamoaAbcastStack: IOException: "
+ " Impossible to create the recovery file !");
}
it = allProtocols.values().iterator();
while (it.hasNext())
it.next().recovery(false);
}
}
// Initialize the protocol with final listeners at the end
pFake.init();
}
};
long cID = this.scheduler.schedule(initTask);
this.scheduler.waitEnd(cID);
// Start the listener of all UDP protocols
it = allProtocols.values().iterator();
while (it.hasNext()) {
ProtocolModule prot = it.next();
if (prot instanceof ProtocolUDP)
((ProtocolUDP) prot).startListener();
}
}
/**
* Print the state of all {@link seqSamoa.ProtocolModule protocols} in the stack
*
* @param stream
* the stream where the state is printed
*/
public void sendDump(OutputStream stream) {
// Send dump to all protocol modules
Iterator<ProtocolModule> it = allProtocols.values().iterator();
while (it.hasNext())
it.next().dump(stream);
}
/**
* Set the mode for the log.
*
* @param mode
* If true, print all messages in the log. Otherwise, print nothing in the log.
*/
public void sendDebug(boolean mode) {
if (mode)
logger.setLevel(Level.ALL);
else
logger.setLevel(Level.OFF);
}
/**
* Commit the stack, i.e. all the {@link seqSamoa.ProtocolModule protocols} in the stack.
* This method also commit the state of the application by runnning a specified method
* dedicated to this task.
*
* @param r
* the method that executes the commit of the application
*/
synchronized public void commit(final Runnable r) {
// TODO: commit the architecture of the stack!!!
AtomicTask task = new AtomicTask() {
public void execute() {
if (r != null)
r.run();
// Send dump to all protocol modules
Iterator<ProtocolModule> it = allProtocols.values().iterator();
while (it.hasNext()) {
it.next().commit();
it.remove();
}
}
};
long cID = this.scheduler.schedule(task);
this.scheduler.waitEnd(cID);
}
/**
* Close the stack, i.e. close all the {@link seqSamoa.ProtocolModule protocols}
* of the stack and stop the {@link seqSamoa.SamoaScheduler scheduler}
*/
public void close() {
this.finalize();
}
/**
* Finalize the satck. This method has the same effect as method close.
*/
public void finalize() {
// Close the timer and the scheduler
this.scheduler.close();
// Close all protocol modules
Iterator<ProtocolModule> it = allProtocols.values().iterator();
while (it.hasNext())
it.next().close();
this.pFake.close();
}
}