de.uni_hannover.dcsec.siafu.control.Simulation.java Source code

Java tutorial

Introduction

Here is the source code for de.uni_hannover.dcsec.siafu.control.Simulation.java

Source

/*
 * Copyright NEC Europe Ltd. 2006-2007
 *  and 2012 Distributed Computing & Security Group, Leibniz Universitt Hannover
 * 
 * This file is part of the MoSP simulation Siafu context simulator.
 * 
 * Siafu 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.
 * 
 * Siafu 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, see <http://www.gnu.org/licenses/>.
 */

package de.uni_hannover.dcsec.siafu.control;

import java.util.Calendar;

import org.apache.commons.configuration.Configuration;
import org.apache.commons.configuration.XMLConfiguration;

import de.uni_hannover.dcsec.siafu.behaviormodels.BaseAgentModel;
import de.uni_hannover.dcsec.siafu.behaviormodels.BaseContextModel;
import de.uni_hannover.dcsec.siafu.behaviormodels.BaseWorldModel;
import de.nec.nle.siafu.exceptions.GUINotReadyException;
import de.uni_hannover.dcsec.siafu.graphics.markers.Marker;
import de.uni_hannover.dcsec.siafu.model.Agent;
import de.uni_hannover.dcsec.siafu.model.SimulationData;
import de.uni_hannover.dcsec.siafu.model.Trackable;
import de.uni_hannover.dcsec.siafu.model.World;
import de.uni_hannover.dcsec.siafu.output.CSVPrinter;
import de.uni_hannover.dcsec.siafu.output.NullPrinter;
import de.uni_hannover.dcsec.siafu.output.SimulatorOutputPrinter;
import java.util.ArrayList;
import java.util.Stack;

/**
 * The simulation class implements the <code>Runnable</code> that performs the
 * simulation itself.
 * <p>
 * In detail, the simulation thread handles the evolution of agent, context and
 * world according to their respective models, and prints out the agent
 * information using the configured <code>SimulationOutputPrinter</code>.
 * 
 * @author M. Martin
 * @author P. Salomon
 * @author B. Henne
 * @author C. Szongott
 * 
 */
public class Simulation implements Runnable {

    /**
     * The <object>Controller</object> that governs this run of the Context
     * Simulator.
     */
    private final Controller control;

    /** Whether the simulation should end. */
    private boolean ended;

    /**
     * The jar file or folder containing the simulation data.
     */
    private SimulationData simData;

    /**
     * Specifies whether the simulation is currently paused or not. See
     * <code>isPaused()</code> for details.
     */
    private boolean paused;

    /**
     * The simulation's world. This is only a reference to the
     * <code>World</code> in <code>control</code>.
     */
    private World world;

    /**
     * The simulation's time, held in a <code>Calendar</code> object.
     */
    private Calendar time;

    /**
     * The Agent Model, as defined by the configuration file.
     * <p>
     * The agent model determines the behaviour of an agent, deciding what he
     * does next at each iteration, and how it changes over time.
     */
    private BaseAgentModel agentModel;

    /**
     * The World Model, as defined by the configuration file.
     * <p>
     * The world model handles the simulated places, how they evolve, and the
     * events they generate.
     */
    private BaseWorldModel worldModel;

    /**
     * The Context Model, as thefined by the configuration file.
     * <p>
     * The context model handles the evolution of the context variables over
     * time.
     */
    private BaseContextModel contextModel;

    /**
     * The simulation time that ellapses between each iteration.
     */
    private int iterationStep;

    /**
     * The tick count that elapsed since simulation start
     */
    private int ticks = 0;

    /**
     * The output printer for the simulator. The simulation thread calls on this
     * object to print per iteration reports on the agents.
     */
    private SimulatorOutputPrinter outputPrinter;

    /**
     * Whether the simulation is already running.
     */
    private boolean simulationRunning;

    /** The configuration of the running simulation. */
    private Configuration simulationConfig;

    /**
     * The simulator's config (in opposition to the simulation's config).
     */
    private XMLConfiguration siafuConfig;

    /**
     * Liste von Agenten die von Auen in die Simulation eingefgt werden (z.B.
     * ber TCP)
     * 
     * psa
     */
    private Stack<Agent> incommingAgents;

    /**
     * Soll die Simulation automatisch weiterlaufen oder von Auen getaktet
     * werden
     */
    private boolean isAutomaticIteration;

    /**
     * Anzahl der Schritte bis die Simulation wieder stoppt. (Nur wenn von Auen
     * getaktet)
     */
    private int iterationStepsToDo = 0;

    /**
     * Find out if the simulation is already running.
     * 
     * @return true if the simulation is running
     */
    public boolean isSimulationRunning() {
        return simulationRunning;
    }

    public Controller getControl() {
        return this.control;
    }

    /**
     * Build a <code>Simulation</code> object and start a thread that governs
     * it.
     * 
     * @param simulationPath
     *            the path to the simulation data, which includes maps, sprites,
     *            behavior models, etc...
     * @param control
     *            the simulation <code>Controller</code>
     */
    public Simulation(final String simulationPath, final Controller control) {
        this.simData = SimulationData.getInstance(simulationPath);
        this.siafuConfig = control.getSiafuConfig();
        this.simulationConfig = simData.getConfigFile();
        this.control = control;
        this.incommingAgents = new Stack<Agent>();

        World.setShouldPrefillCache(control.getSiafuConfig().getBoolean("ui.gradientcache.prefill"));

        World.setCacheSize(control.getSiafuConfig().getInt("ui.gradientcache.size"));

        if (this.simulationConfig.containsKey("automaticiteration")) {
            if (this.simulationConfig.getBoolean("automaticiteration"))
                this.isAutomaticIteration = true;
            else
                this.isAutomaticIteration = false;
        } else
            this.isAutomaticIteration = true;

        System.out.println("Auto Int:" + this.isAutomaticIteration);

        new Thread(this, "Simulation thread").start();
    }

    /**
     * Get the simulation's world.
     * 
     * @return the simulation's world
     */
    public World getWorld() {
        return world;
    }

    /**
     * Get the simulation's ticks.
     */
    public int getTicks() {
        return ticks;
    }

    /**
     * Sets the output type of the simulator. This is done by assigning an
     * implementation of <code>SimulatorOutputPrinter</code> to simPrinter of
     * the type provided in the parameter.
     * 
     * @param type
     *            the output printer type. Currently, only "null" and "cvs" are
     *            supported.
     * @return an instance of the SimulatorOutputPrinter of the given type
     * 
     * @see de.nec.nle.siafu.output.SimulatorOutputPrinter
     */
    private SimulatorOutputPrinter createOutputPrinter(final String type) {

        if (type.equalsIgnoreCase("csv")) {
            System.out.println("CSV output selected");
            return new CSVPrinter(world, siafuConfig);
        } else if (type.equalsIgnoreCase("null")) {
            return new NullPrinter();
        } else {
            throw new RuntimeException("Unknown ouput type in the configuration");
        }
    }

    /**
     * Starts the simulation.
     */
    public void run() {
        this.world = new World(this, simData);
        this.time = world.getTime();
        this.iterationStep = simulationConfig.getInt("iterationstep");
        this.agentModel = world.getAgentModel();
        this.worldModel = world.getWorldModel();
        this.contextModel = world.getContextModel();
        this.outputPrinter = createOutputPrinter(siafuConfig.getString("output.type"));

        Controller.getProgress().reportSimulationStarted();
        simulationRunning = true;
        // int h = time.get(Calendar.HOUR_OF_DAY);
        int m = time.get(Calendar.MINUTE);
        if (!isAutomaticIteration)
            this.control.setPaused(true);

        while (!isEnded()) {
            /*
             * if(time.after(world.getEndTime())) {
             * System.out.println("End simulation, no time left!"); break; }
             */

            if (!isAutomaticIteration) {
                if (iterationStepsToDo == 0) {
                    if (!isPaused()) {
                        this.control.getOutput().iterationFinish(); // step done
                        this.control.setPaused(true);
                    }
                } else
                    iterationStepsToDo--;
            }

            // if (h != time.get(Calendar.HOUR_OF_DAY)) {
            // h = time.get(Calendar.HOUR_OF_DAY);
            // System.out.println("Time: " + h);
            // System.out.println("#people:"+world.getPeople().size());
            // }
            if (m != time.get(Calendar.MINUTE)) {
                m = time.get(Calendar.MINUTE);
                System.out.print(".");
            }

            if (!isPaused()) {
                tickTime();
                ticks++;
                System.out.println(ticks + " (" + this.getWorld().getWorldName() + ")");
                worldModel.doIteration(world.getPlaces());
                agentModel.doIteration(world.getPeople());
                contextModel.doIteration(world.getOverlays());
            }
            addOrRemoveAgents();
            moveAgents();
            control.scheduleDrawing();
            outputPrinter.notifyIterationConcluded();
        }
        simulationRunning = false;

        outputPrinter.cleanup();
        Controller.getProgress().reportSimulationEnded();
    }

    /**
     * Stop looping the simulatio and, well, kill the thread.
     */
    public void die() {
        ended = true;
    }

    /**
     * Pauses the simulation. See <code>isPaused()</code> for details. If the
     * gui is not used, this method has no effect.
     * 
     * @param state
     *            a boolean with the value true will pause the simulation, while
     *            false will resume it.
     */
    public synchronized void setPaused(final boolean state) {
        // if (control.isGuiUsed()) {
        paused = state;
        // }
    }

    /**
     * Reports on the pause state of the simulation.
     * <p>
     * When paused, time stops, and all automatic behaviour is interrupted.
     * However, using the GUI, the user can still manipulate agents in his
     * control, or update variables through the external command interface.
     * 
     * @return true if the simulation is paused, false otherwise
     */
    public synchronized boolean isPaused() {
        return paused;
    }

    /**
     * Find out if the simulation is ended or ending.
     * 
     * @return true if the simulation is ending or has already ended
     */
    private synchronized boolean isEnded() {
        return ended;
    }

    /**
     * Handles all of the movements of the agents. Note that an agent is allowed
     * to move only if the simulation is not paused or if he is being controlled
     * by the user.
     * 
     */
    private void moveAgents() {
        for (Agent a : world.getPeople()) {

            if (!isPaused() || !a.isOnAuto()) {
                a.moveTowardsDestination();
            }
        }
    }

    private void addOrRemoveAgents() {
        ArrayList<Agent> removeList = new ArrayList<Agent>();

        for (Agent a : world.getPeople()) {
            if (a.isDeleted())
                removeList.add(a);
        }

        for (Agent a : removeList) {
            control.getOutput().agentLeave(a);
            world.deleteAgent(a);
        }

        while (!incommingAgents.empty()) {
            world.addAgent(incommingAgents.pop());
        }

    }

    /**
     * Increases the simulation time by <code>iterationStep</code>, defined in
     * the configuration file.
     */
    private void tickTime() {
        time.add(Calendar.SECOND, iterationStep);
    }

    /**
     * Add a Marker to the simulation GUI. If the GUI is not ready, this method
     * performs no action a GUINotReadyException is thrown. If the GUI is not
     * being used this method returns silently and does nothing.
     * 
     * @param m
     *            the marker to add
     * @throws GUINotReadyException
     *             if the GUI can not draw the mark at the moment.
     */
    public void addMarker(final Marker m) throws GUINotReadyException {
        control.addMarker(m);
    }

    /**
     * Remove all Markers from the simulation GUI. If the GUI is not ready, this
     * method performs no action a GUINotReadyException is thrown. If the GUI is
     * not being used this method returns silently and does nothing.
     * 
     * @throws GUINotReadyException
     *             if the GUI can not draw the mark at the moment.
     */
    public void unMarkAll() throws GUINotReadyException {
        control.unMarkAll();
    }

    /**
     * Remove the Marker for this Trackable from the simulation GUI F. If the
     * GUI is not ready, this method performs no action a GUINotReadyException
     * is thrown. If the GUI is not being used this method returns silently and
     * does nothing.
     * 
     * @param t
     *            the Trackable to unmark
     * @throws GUINotReadyException
     *             if the GUI can not draw the mark at the moment.
     */
    public void unMark(final Trackable t) throws GUINotReadyException {
        control.unMark(t);
    }

    /**
     * Find out if the given Trackable is marked in the GUI. If the GUI is not
     * ready, this method throws a GUINotReadyException. If the GUI is not being
     * used this method returns false.
     * 
     * @param t
     *            the Trackable about which we are asking
     * @return true if the trackable has been marked, false otherwise
     * @throws GUINotReadyException
     *             if the GUI can not draw the mark at the moment.
     */
    public boolean isMarked(final Trackable t) throws GUINotReadyException {
        return control.isMarked(t);
    }

    public String addAgent(String type, String parameter) {
        Agent.unlockInfoFields();
        ;
        Agent agent = getWorld().getAgentModel().addAgent(type, parameter);
        Agent.lockInfoFields();
        if (agent != null) {
            incommingAgents.push(agent);

            return agent.getName();
        } else
            return "no agent added!";
    }

    /**
     * Get the Simulation's Data object.
     * 
     * @return the SimulationData for the running simulation
     */
    public SimulationData getSimulationData() {
        return simData;
    }

    public boolean isAutomaticIteration() {
        return this.isAutomaticIteration;
    }

    public int addSteps(int steps) {
        iterationStepsToDo += steps;
        return iterationStepsToDo;
    }
}