/**
* 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.protocols.pt2pt;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
import seqSamoa.Message;
import seqSamoa.ProtocolModule;
import seqSamoa.ProtocolStack;
import seqSamoa.Service;
import seqSamoa.ServiceCallOrResponse;
import seqSamoa.AtomicTask;
import seqSamoa.exceptions.AlreadyExistingProtocolModuleException;
import seqSamoa.exceptions.NotScheduledTaskException;
import seqSamoa.services.pt2pt.PT2PT;
import seqSamoa.services.pt2pt.PT2PTCallParameters;
import seqSamoa.services.pt2pt.PT2PTResponseParameters;
import seqSamoa.services.udp.UDP;
import seqSamoa.services.udp.UDPCallParameters;
import static_recovery.common.pt2pt.Pt2ptHandler;
import uka.transport.Transportable;
import framework.Constants;
import framework.GroupCommEventArgs;
import framework.GroupCommException;
import framework.GroupCommMessage;
import framework.PID;
import framework.libraries.Timer;
import framework.libraries.Trigger;
import framework.libraries.serialization.TBoolean;
/**
* This class implement a Protocol that allows Point to Point communication
*
* The service implemented is pt2pt (described in util/Services.java)
*/
public class ProtocolPT2PT extends ProtocolModule implements Trigger, Timer {
// Service provided
private PT2PT pt2pt;
// Service required
private UDP udp;
protected Pt2ptHandler handlers = null;
// Is the Protocol Closed
boolean closed;
/** Timers scheduled */
Map<Transportable, AtomicTask> timers = null;
// The Executer
// It start to monitor the processes in parameters
protected PT2PT.Executer pt2ptExecuter;
// The Listener
// It wait for UDP message
protected UDP.Listener udpListener;
// The COR for the call to pt2pt
private ServiceCallOrResponse pt2ptCallCOR;
/**
* Constructor
*
* @param name
* String identifier of the protocol
* @param stack
* The stack in which the module will be
* @param sendTimeout
* The time we wait before sending again a message
*/
public ProtocolPT2PT(String name, ProtocolStack stack, int sendTimeout, PT2PT pt2pt,
UDP udp) throws AlreadyExistingProtocolModuleException {
super(name, stack);
this.timers = new HashMap<Transportable, AtomicTask>();
this.closed = false;
handlers = new Pt2ptHandler(this, this, sendTimeout, stack.getPID());
this.udp = udp;
this.pt2pt = pt2pt;
this.pt2ptCallCOR = ServiceCallOrResponse.createServiceCallOrResponse(this.pt2pt, true);
LinkedList<ServiceCallOrResponse> initiatedPt2Pt = new LinkedList<ServiceCallOrResponse>();
initiatedPt2Pt.add(ServiceCallOrResponse.createServiceCallOrResponse(udp, true));
pt2ptExecuter = pt2pt.new Executer(this, initiatedPt2Pt) {
public void evaluate(PT2PTCallParameters params, Message dmessage) {
synchronized (this.parent) {
GroupCommEventArgs ga = new GroupCommEventArgs();
if (dmessage != null) {
ga.addLast(dmessage.toGroupCommMessage());
ga.addLast(params.pid);
ga.addLast(params.key);
handlers.handlePt2ptSend(ga);
} else {
ga.addLast(params.key);
try {
handlers.handleKillMessage(ga);
} catch (Exception e) {
throw new RuntimeException("ProtocolPT2PT: "
+ "PT2PTExecuter: " + e);
}
}
}
}
};
LinkedList<ServiceCallOrResponse> initiatedUdp = new LinkedList<ServiceCallOrResponse>();
initiatedUdp.add(ServiceCallOrResponse.createServiceCallOrResponse(pt2pt, false));
udpListener = udp.new Listener(this, initiatedUdp) {
public void evaluate(Object infos, Transportable response) {
synchronized (this.parent) {
GroupCommEventArgs ga = new GroupCommEventArgs();
ga.addLast(response);
handlers.handleUDPReceive(ga);
}
}
};
}
private synchronized void timeout(Object o) {
final Transportable fKey = (Transportable) o;
if (!timers.containsKey(fKey))
// Timer was canceled
return;
handlers.handleTimeout(fKey);
}
synchronized public void recovery(boolean recovery) {
GroupCommEventArgs e = new GroupCommEventArgs();
e.add(new TBoolean(recovery));
try {
handlers.handleRecovery(e);
} catch (GroupCommException ex) {
throw new RuntimeException("ProtocolPT2PT: Recovery: "
+ ex.getMessage());
}
}
synchronized public void close() {
closed = true;
super.close();
}
synchronized public void dump(OutputStream os) {
handlers.dump(os);
}
/**
* Manage the triggering of the events
*/
@SuppressWarnings("unchecked")
public void trigger(int type, GroupCommEventArgs l) {
switch (type) {
case Constants.PT2PTDELIVER:
Message message = new Message((GroupCommMessage) l.get(0));
PT2PTResponseParameters infos = new PT2PTResponseParameters(
(PID) l.get(1));
pt2pt.externalResponse(infos, message);
break;
case Constants.UDPSEND:
Transportable umessage = l.get(0);
UDPCallParameters uparams = new UDPCallParameters((PID) l.get(1));
udp.call(uparams,
new Message(umessage, (Service.Listener) udpListener));
break;
default:
throw new RuntimeException("Error : ProtocolPT2PT : trigger"
+ "Trying to send an unknown event type: " + type);
}
}
/**
* <i>Requiered by interface Timer </i>
*/
synchronized public void schedule(final Transportable key, boolean periodic, int time) {
if (!periodic)
throw new RuntimeException("ProtocolPT2PT: schedule: "
+ "Non-periodic timers not supported!!!");
if (timers.containsKey(key))
throw new RuntimeException("ProtocolPT2PT: schedule: "
+ "Task already scheduled!");
// There is no entry in the map
// Create the entry and start the timer
AtomicTask trigger = new AtomicTask() {
public void execute() {
timeout(key);
}
public ServiceCallOrResponse getCOR(){
return pt2ptCallCOR;
}
};
timers.put(key, trigger);
stack.getScheduler().schedule(trigger, periodic, time);
}
/**
* <i>Requiered by interface Timer</i>
*/
synchronized public void cancel(Transportable key) {
try {
stack.getScheduler().cancel(timers.remove(key));
} catch (NotScheduledTaskException ex) {
throw new RuntimeException("ProtocolPing: cancel: The task is not"
+ " currently scheduled");
}
}
/**
* <i>Requiered by interface Timer</i>
*/
public void reset(Transportable key) {
throw new RuntimeException("ProtocolPT2PT: reset: not supported!!!");
}
}