/*
* Copyright (c) 2005-2011 KOM - Multimedia Communications Lab
*
* This file is part of PeerfactSim.KOM.
*
* PeerfactSim.KOM 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 3 of the License, or
* any later version.
*
* PeerfactSim.KOM 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 PeerfactSim.KOM. If not, see .
*
*/
package de.tud.kom.p2psim.impl.churn;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import de.tud.kom.p2psim.api.churn.ChurnGenerator;
import de.tud.kom.p2psim.api.churn.ChurnModel;
import de.tud.kom.p2psim.api.common.SimHost;
import de.tud.kom.p2psim.api.network.SimNetInterface;
import de.tud.kom.p2psim.api.network.SimNetworkComponent;
import de.tud.kom.p2psim.api.scenario.Configurator;
import de.tud.kom.p2psim.api.scenario.HostBuilder;
import de.tud.kom.p2psim.impl.util.toolkits.CollectionHelpers;
import de.tud.kom.p2psim.impl.util.toolkits.Predicates;
import de.tudarmstadt.maki.simonstrator.api.Event;
import de.tudarmstadt.maki.simonstrator.api.EventHandler;
import de.tudarmstadt.maki.simonstrator.api.Monitor;
import de.tudarmstadt.maki.simonstrator.api.Monitor.Level;
import de.tudarmstadt.maki.simonstrator.api.Time;
/**
* Provides a random number generator for times. do sth
*
* @author Sebastian Kaune
*/
public class DefaultChurnGenerator implements EventHandler, ChurnGenerator {
HostBuilder hostBuilder;
ChurnModel churnModel;
List hosts = null;
long endTime = Long.MAX_VALUE;
boolean testMode = false;
public final static int CHURN_START = 1;
public final static int CHURN_STOP = 2;
public final static int CHURN_EVENT = 3;
public final static int CHURN_NOCHURN_HOSTS = 4;
public void setChurnModel(ChurnModel model) {
this.churnModel = model;
}
public void setStart(long time) {
Event.scheduleWithDelay(time - Time.getCurrentTime(), this, null,
CHURN_START);
}
public void setStop(long time) {
this.endTime = time;
Event.scheduleWithDelay(time - Time.getCurrentTime(), this, null,
CHURN_STOP);
}
public void compose(Configurator config) {
hostBuilder = (HostBuilder) config
.getConfigurable(Configurator.HOST_BUILDER);
}
@Override
public void eventOccurred(Object content, int type) {
if (type == CHURN_EVENT) {
ChurnEvent churnEvent = (ChurnEvent) content;
SimNetworkComponent net = churnEvent.host.getNetworkComponent();
if (churnEvent.goOnline) {
for (SimNetInterface netI : net.getSimNetworkInterfaces()) {
if (netI.isOffline()) {
netI.goOnline();
}
}
} else {
for (SimNetInterface netI : net.getSimNetworkInterfaces()) {
if (netI.isOnline()) {
netI.goOffline();
}
}
}
scheduleChurnEvent(churnEvent.host);
} else if (type == CHURN_START) {
this.hosts = new ArrayList(this.filterHosts());
this.churnModel.prepare(this.hosts);
this.activate();
} else if (type == CHURN_STOP) {
if (hosts == null)
throw new RuntimeException(
"Tried to stop churn at "
+ Time.getCurrentTime()
+ ", but it never started. Maybe you should correct your churn start and stop.");
for (SimHost host : this.hosts) {
for (SimNetInterface netI : host.getNetworkComponent()
.getSimNetworkInterfaces()) {
if (netI.isOffline()) {
netI.goOnline();
}
}
}
} else if (type == CHURN_NOCHURN_HOSTS) {
// Send no-churn-hosts online immediately
List nochurnhosts = (List) content;
for (SimHost host : nochurnhosts) {
for (SimNetInterface netI : host.getNetworkComponent()
.getSimNetworkInterfaces()) {
if (netI.isOffline()) {
netI.goOnline();
}
}
}
}
}
void activate() {
for (SimHost host : hosts) {
scheduleChurnEvent(host);
}
Monitor.log(DefaultChurnGenerator.class, Level.INFO,
"Scheduled %s churn events", hosts.size());
}
private List filterHosts() {
List tmp = hostBuilder.getAllHosts();
List filteredHosts = new LinkedList();
CollectionHelpers.filter(tmp, filteredHosts,
Predicates.IS_CHURN_AFFECTED);
List noChurn = new LinkedList();
noChurn.addAll(tmp);
noChurn.removeAll(filteredHosts);
Event.scheduleImmediately(this, noChurn, CHURN_NOCHURN_HOSTS);
return filteredHosts;
}
private void scheduleChurnEvent(SimHost host) {
SimNetworkComponent net = host.getNetworkComponent();
long offset;
boolean goOnline;
long currentTime = Time.getCurrentTime();
/*
* Sanity check: currently, we assume within this churn generator, that
* all NetInterfaces of a host behave identical, i.e., they are all
* either online or offline.
*/
boolean oneOffline = false;
boolean oneOnline = false;
for (SimNetInterface netI : net.getSimNetworkInterfaces()) {
if (netI.isOffline()) {
oneOffline = true;
} else {
oneOnline = true;
}
}
if (oneOffline && oneOnline) {
throw new AssertionError(
"Unexpectedly, one NetInterface of the host is offline, while another one is online...");
}
if (oneOnline) {
offset = this.churnModel.getNextDowntime(host);
goOnline = false;
// if (testMode)
// this.testStub.onlineEvent(host, currentTime);
} else {
offset = this.churnModel.getNextUptime(host);
goOnline = true;
// if (testMode)
// this.testStub.offlineEvent(host, currentTime);
}
long timepoint = currentTime + offset;
if (currentTime < endTime && timepoint < endTime) {
Event.scheduleWithDelay(offset, this,
new ChurnEvent(host, goOnline), CHURN_EVENT);
}
}
private class ChurnEvent {
public final SimHost host;
public final boolean goOnline;
ChurnEvent(SimHost host, boolean goOnline) {
this.host = host;
this.goOnline = goOnline;
}
}
// void setTestStub(ChurnTestStub testStub) {
// this.testStub = testStub;
// this.testMode = true;
// }
}