de.tud.kom.p2psim.impl.simengine.Simulator.java Source code

Java tutorial

Introduction

Here is the source code for de.tud.kom.p2psim.impl.simengine.Simulator.java

Source

/*
 * 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 <http://www.gnu.org/licenses/>.
 *
 */

package de.tud.kom.p2psim.impl.simengine;

import java.util.Collection;
import java.util.Map;

import org.apache.commons.math.random.JDKRandomGenerator;
import org.apache.commons.math.random.RandomGenerator;
import org.apache.log4j.Logger;

import de.tud.kom.p2psim.api.common.Monitor;
import de.tud.kom.p2psim.api.scenario.Configurable;
import de.tud.kom.p2psim.api.scenario.ConfigurationException;
import de.tud.kom.p2psim.api.scenario.Configurator;
import de.tud.kom.p2psim.api.scenario.Scenario;
import de.tud.kom.p2psim.api.scenario.ScenarioFactory;
import de.tud.kom.p2psim.api.simengine.SimulationEventHandler;
import de.tud.kom.p2psim.impl.common.DefaultMonitor;
import de.tud.kom.p2psim.impl.scenario.DefaultConfigurator;
import de.tud.kom.p2psim.impl.skynet.SkyNetBatchSimulator;
import de.tud.kom.p2psim.impl.skynet.analyzing.writers.AttributeWriter;
import de.tud.kom.p2psim.impl.skynet.analyzing.writers.MetricsWriter;
import de.tud.kom.p2psim.impl.util.logging.SimLogger;

/**
 * Concrete implementation of a simulator which can be used to run a simulation
 * by calling the main method in the SimulatorRunner class.
 * 
 * @author Sebastian Kaune <peerfact@kom.tu-darmstadt.de>
 * @author Konstantin Pussep
 * @version 3.0, 11/29/2007
 * 
 */
public class Simulator implements Configurable {

    private final static Logger log = SimLogger.getLogger(Simulator.class);

    /**
     * These constant should be ALWAYS used for virtual time calculations.
     */
    public final static long MICROSECOND_UNIT = 1l;

    /**
     * These constant should be ALWAYS used for virtual time calculations.
     */
    public final static long MILLISECOND_UNIT = 1000l * MICROSECOND_UNIT;

    /**
     * These constant should be ALWAYS used for virtual time calculations.
     */
    public final static long SECOND_UNIT = 1000l * MILLISECOND_UNIT;

    /**
     * These constant should be ALWAYS used for virtual time calculations.
     */
    public final static long MINUTE_UNIT = 60l * SECOND_UNIT;

    /**
     * These constant should be ALWAYS used for virtual time calculations.
     */
    public final static long HOUR_UNIT = 60l * MINUTE_UNIT;

    /**
     * Scenario holding all the information about the current simulation run.
     */
    private Scenario scenario;

    /**
     * Singleton instance of default simulator.
     */
    private static Simulator singleton;

    /**
     * Configurator instance is used to initialize the scenario.
     */
    private DefaultConfigurator defaultConfigurator;

    private boolean running;

    private static long seed;

    private static Scheduler scheduler;

    private static RandomGenerator randomGen = new JDKRandomGenerator();

    private static Monitor monitor;

    private static boolean finishedWithoutError = false;

    /**
     * This class is singleton, so use getInstance() method to obtain a
     * reference to it.
     * 
     */
    private Simulator() {
        singleton = this;
        scheduler = new Scheduler(true);
        monitor = new DefaultMonitor();
    }

    /**
     * Returns the single instance of the SimulationFramework
     * 
     * @return the SimulationFramework
     */
    public static Simulator getInstance() {
        if (singleton == null)
            singleton = new Simulator();
        return singleton;
    }

    /**
     * Set the scenario (protocol stack, network topology etc.) which will be
     * used to run the simulation.
     * 
     * @param scenario
     *            simulation scenario to be used
     */
    public void setScenario(Scenario scenario) {
        checkRunning();
        this.scenario = scenario;
    }

    /**
     * Returns the scenario used to run the simulation.
     * 
     * @return
     */
    public Scenario getScenario() {
        return scenario;
    }

    /**
     * This method will run the simulation using the previously set scenario
     * data.
     * 
     */
    public void start(boolean throwExceptions) {
        checkRunning();
        log.info("Prepare Scenario ...");
        this.scenario.prepare();

        log.info("Running Scenario with seed=" + getSeed());
        long startTime = System.currentTimeMillis();

        log.info("Simulation started...");
        this.running = true;
        Exception reason = null;
        try {

            scheduler.start();
            finishedWithoutError = true;

        } catch (RuntimeException e) {
            finishedWithoutError = false;
            if (throwExceptions) {
                throw e;
            } else {
                log.error("Simulator run stopped because of error", e);
                reason = e;
            }
        } finally {
            this.running = false;
            // After a simulation start the mechanisms, which
            // finalize a simulation
            shutdownSimulation(reason, startTime);
        }
    }

    private void shutdownSimulation(Exception reason, long startTime) {
        this.running = false;
        if (finishedWithoutError) {
            log.info("Simulation successfully finished.");
        } else {
            log.error("Simulation finished with the error = " + reason);
        }
        long runTime = System.currentTimeMillis() - startTime;
        long minutes = (long) Math.floor((runTime) / 60000);
        long secs = (runTime % 60000) / 1000;
        log.info("Realtime Duration of experiment (m:s) " + minutes + ":" + secs);
        log.info("Simulated time is " + getSimulatedRealtime());
        if (AttributeWriter.hasInstance()) {
            AttributeWriter.getInstance().closeWriter();
        }
        if (MetricsWriter.hasInstance()) {
            MetricsWriter.getInstance().closeWriter();
        }
        if (SkyNetBatchSimulator.hasInstance()) {
            SkyNetBatchSimulator.getInstance().finish(finishedWithoutError);
        }
    }

    /**
     * Configure simulation from an XML file.
     * 
     * @param configFile
     *            XML file with the configuration data.
     * @param variables
     *            the variables which are specified in the XML file with the
     *            configuarion data.
     */
    public void configure(String configFile, Map<String, String> variables) {
        // TODO create a class, that contains general informations of the
        // simulation, which can be accessed from every component during a
        // simulation. This can be seen as an alternative to implementing the
        // Composable interface
        this.defaultConfigurator = new DefaultConfigurator(configFile);
        defaultConfigurator.setVariables(variables);
        this.defaultConfigurator.register(Configurator.CORE, this);
        Collection<Configurable> components = this.defaultConfigurator.configureAll();
        log.debug("components " + components);
        ScenarioFactory scenarioBuilder = (ScenarioFactory) this.defaultConfigurator
                .getConfigurable(Configurator.SCENARIO_TAG);
        if (scenarioBuilder == null)
            throw new ConfigurationException(
                    "No scenario builder specified in the configuration file. Nothing to do.");
        Scenario scenario = scenarioBuilder.createScenario();
        setScenario(scenario);

    }

    /**
     * Returns the seed used within a simulation run.
     * 
     * @return the predefined seed
     * 
     */
    public static long getSeed() {
        return seed;
    }

    /**
     * This method sets the seed of the global random generator which can be
     * obtained using the static getRandom()-method.
     * 
     * @param seed
     *            the seed to configure the global random generator
     */
    public void setSeed(long seed) {
        checkRunning();
        this.seed = seed;
        randomGen.setSeed(seed);
    }

    /**
     * Returns the global monitor which can be used to delegate
     * information/occured events to a specific analyzer/s.
     * 
     * @return the global monitor
     */
    public static Monitor getMonitor() {
        if (monitor == null)
            monitor = new DefaultMonitor();
        return monitor;
    }

    /**
     * Assure that the set methods are not called after the simulation has
     * started.
     */
    private void checkRunning() {
        if (this.running)
            throw new IllegalStateException("Simulator is already running.");
    }

    /**
     * This method provides the global random generator which has to be used
     * within the simulation framework to generate reproducable results
     * depending on a predefined seed.
     * 
     * @return the global random generator with a predefined seed.
     */
    public static RandomGenerator getRandom() {
        return randomGen;
    }

    /**
     * Sets the monitor which has to be configured by using the XML file with
     * the configuration data.
     * 
     * @param monitor
     *            monitor predefined in the XML file with the configuration
     *            data.
     */
    public void setMonitor(Monitor monitor) {
        checkRunning();
        this.monitor = monitor;
    }

    /**
     * Returns the current simulation unit value.
     * 
     * @return the current simulation unit value
     */
    public static long getCurrentTime() {
        return scheduler.getCurrentTime();
    }

    /**
     * Returns the end time of the simulation.
     * 
     * @return
     */
    public static long getEndTime() {
        return scheduler.getEndTime();
    }

    /**
     * Returns the simulated realtime in the format (Hours:Minutes:Seconds).
     * 
     * @return the simulated realtime
     */
    public static String getSimulatedRealtime() {
        return scheduler.getSimulatedRealtime();
    }

    /**
     * Inserts new event in queue
     * 
     * @param content
     *            the content of the event
     * @param simulationTime
     *            time to schedule the event
     * @param handler
     *            handler which will receive this event
     * @param eventType
     *            specific simulation event
     */
    public static void scheduleEvent(Object content, long simulationTime, SimulationEventHandler handler,
            SimulationEvent.Type eventType) {
        scheduler.scheduleEvent(content, simulationTime, handler, eventType);
    }

    /**
     * Reset the simulator, so that it can be configured again for another
     * simulation run without to restart the Java Virtual Machine. This is
     * especially usefull for JUnit tests.
     * 
     */
    void reset() {
        checkRunning();
        monitor = new DefaultMonitor();
        scenario = null;
        scheduler = new Scheduler(true);
        seed = 0;
    }

    public static Scheduler getScheduler() {
        return scheduler;
    }

    /**
     * Sets the end time at which the simulation framework will finish at the
     * latest the simulation , irrespective if there are still unprocessed
     * events in the event queue.
     * 
     * @param endTime
     *            point in time at which the simular will finish at the latest
     */
    public void setFinishAt(long endTime) {
        checkRunning();
        this.scheduler.setFinishAt(endTime);
    }

    static boolean isFinishedWithoutError() {
        return finishedWithoutError;
    }

    /**
     * Can be used to format the absolute simulation time (current, past or
     * future) into human-readable format: (h:m:s:ms).
     * 
     * @param time
     *            - absolute simulation time like the one obtained via
     *            getCurrentTime();
     * @return human-readable representation of the given simulation time
     */
    public static String getFormattedTime(long time) {
        return scheduler.getFormattedTime(time);
    }

    /**
     * Specifies how often the scheduler will printout the current simulation
     * time.
     * 
     * @param time
     */
    public void setStatusInterval(long time) {
        scheduler.setStatusInterval(time);
    }

    public void setRealTime(boolean realTime) {
        scheduler.setRealTime(realTime);
    }

    public void setTimeSkew(double timeSkew) {
        scheduler.setTimeSkew(timeSkew);
    }

    public DefaultConfigurator getConfigurator() {
        return defaultConfigurator;
    }

}