package ibis.ipl.registry.gossip;
import ibis.ipl.IbisIdentifier;
import ibis.ipl.RegistryEventHandler;
import ibis.util.ThreadPool;
import java.util.LinkedList;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
final class Upcaller implements Runnable {
private static final class Event {
static final int JOIN = 1;
static final int LEAVE = 2;
static final int DIED = 3;
static final int SIGNAL = 4;
static final int ELECT = 5;
int type;
IbisIdentifier ibis;
String string;
Event(int type, IbisIdentifier ibis, String string) {
this.type = type;
this.ibis = ibis;
this.string = string;
}
}
private static final Logger logger = LoggerFactory.getLogger(Upcaller.class);
private RegistryEventHandler handler;
private final List<Event> pendingEvents;
/** Set when registry upcalls are enabled. */
private boolean registryUpcallerEnabled = false;
/** Set when processing a registry upcall. */
private boolean busyUpcaller = false;
Upcaller(RegistryEventHandler handler) {
this.handler = handler;
pendingEvents = new LinkedList<Event>();
ThreadPool.createNew(this, "upcaller");
}
synchronized void enableEvents() {
registryUpcallerEnabled = true;
notifyAll();
}
synchronized void disableEvents() {
registryUpcallerEnabled = false;
while (busyUpcaller) {
try {
wait();
} catch (Exception e) {
// nothing
}
}
}
private synchronized void setBusyUpcaller() {
busyUpcaller = true;
}
private synchronized void clearBusyUpcaller() {
busyUpcaller = false;
notifyAll();
}
private synchronized Event waitForEvent() {
while (!(registryUpcallerEnabled && !pendingEvents.isEmpty())) {
try {
wait();
} catch (Exception e) {
// nothing
}
}
return pendingEvents.remove(0);
}
synchronized void stop() {
pendingEvents.add(null);
notifyAll();
}
public void run() {
while (true) {
Event event = waitForEvent();
if (event == null) {
// registry stopped
return;
}
logger.debug("doing upcall for event: " + event);
setBusyUpcaller();
try {
switch (event.type) {
case Event.JOIN:
handler.joined(event.ibis);
break;
case Event.LEAVE:
handler.left(event.ibis);
break;
case Event.DIED:
handler.died(event.ibis);
break;
case Event.SIGNAL:
handler.gotSignal(event.string, event.ibis);
break;
case Event.ELECT:
handler.electionResult(event.string, event
.ibis);
break;
default:
logger.error("unknown event type: " + event.type);
}
} catch (Throwable t) {
logger.error("error on handling event", t);
}
logger.debug("upcall for event " + event + " done");
clearBusyUpcaller();
}
}
synchronized void ibisJoined(IbisIdentifier ibis) {
pendingEvents.add(new Event(Event.JOIN, ibis, null));
}
synchronized void ibisLeft(IbisIdentifier ibis) {
pendingEvents.add(new Event(Event.LEAVE, ibis, null));
}
synchronized void ibisDied(IbisIdentifier ibis) {
pendingEvents.add(new Event(Event.DIED, ibis, null));
}
synchronized void signal(String signal, IbisIdentifier source) {
pendingEvents.add(new Event(Event.SIGNAL, source, signal));
}
synchronized void electionResult(String name, IbisIdentifier winner) {
pendingEvents.add(new Event(Event.ELECT, winner, name));
}
}