package core; import java.awt.*; import java.util.*; import prefs.*; import protocols.*; import simulator.*; import utils.*; import events.*; public final class VSProcess extends VSPrefs { private VSTask randomCrashTask; private Color currentColor; private Color tmpColor; private Color crashedColor;; private VSLogging logging; private VSPrefs prefs; private VSRandom random; private VSSimulationPanel simulationPanel; private boolean hasStarted; private boolean isHighlighted; private boolean isPaused; private boolean timeModified; private double clockOffset; private float clockVariance; private int num; private int processID; private long globalTime; private long localTime; private static int processCounter; private boolean isCrashed; private long lamportTime; private ArrayList lamportTimestamps; private ArrayList vectorTimestamps; /* This array contains all Integer prefs of the process which should show * up in the prefs menu! All keys which dont start with "sim." only show * up in the extended prefs menu! */ private static final String DEFAULT_INTEGER_VALUE_KEYS[] = { "sim.process.prob.crash", "sim.message.prob.outage", }; /* This array contains all Long prefs of the process which should show * up in the prefs menu! All keys which dont start with "sim." only show * up in the extended prefs menu! */ private static final String DEFAULT_LONG_VALUE_KEYS[] = { "sim.message.sendingtime.min", "sim.message.sendingtime.max", }; /* This array contains all Float prefs of the process which should show * up in the prefs menu! All keys which dont start with "sim." only show * up in the extended prefs menu! */ private static final String DEFAULT_FLOAT_VALUE_KEYS[] = { "sim.process.clock.variance", }; /* This array contains all Color prefs of the process which should show * up in the prefs menu! All keys which dont start with "sim." only show * up in the extended prefs menu! */ private static final String DEFAULT_COLOR_VALUE_KEYS[] = { "process.default", "process.running", "process.stopped", "process.highlight", "process.crashed", }; /* This array contains all String prefs of the process which should show * up in the prefs menu! All keys which dont start with "sim." only show * up in the extended prefs menu! */ private static final String DEFAULT_STRING_VALUE_KEYS[] = { }; public VSProcess(VSPrefs prefs, VSSimulationPanel simulationPanel, VSLogging logging, int num) { this.prefs = prefs; this.simulationPanel = simulationPanel; this.logging = logging; this.num = num; this.random = new VSRandom(processID+processCounter); this.lamportTimestamps = new ArrayList(); this.vectorTimestamps = new ArrayList(); setLamportTime(0); setObject("protocols", new ArrayList()); isPaused = true; processID = ++processCounter; /* Create the super.VSPrefs with it's default prefs */ fillWithDefaults(); /* Make local copys in order to have more performance */ clockVariance = getFloat("sim.process.clock.variance"); currentColor = getColor("process.default"); /* Make additional process settings editable through GUI */ initInteger("sim.process.id", processID, prefs.getString("lang.process.id"), 1, processID + 10); setLongIfUnset("sim.process.localtime", localTime, prefs.getString("lang.process.time.local")); crashedColor = getColor("process.crashed"); createRandomCrashTask(); } /** * Called from the VSProcessEditor, after finishing editing! */ public synchronized void updateFromVSPrefs() { setClockVariance(getFloat("sim.process.clock.variance")); setProcessID(getInteger("sim.process.id")); setLocalTime(getLong("sim.process.localtime")); crashedColor = getColor("process.crashed"); simulationPanel.repaint(); createRandomCrashTask(); } /** * Called from the VSProcessEditor, before starting editing! */ public synchronized void updatePrefs() { setFloat("sim.process.clock.variance", getClockVariance()); setInteger("sim.process.id", getProcessID()); setLong("sim.process.localtime", getTime()); } public synchronized void syncTime(final long globalTime) { final long currentGlobalTimestep = globalTime - this.globalTime; this.globalTime = globalTime; if (!isCrashed) { localTime += currentGlobalTimestep; clockOffset += currentGlobalTimestep * (double) clockVariance; } while (clockOffset >= 1) { clockOffset -= 1; ++localTime; } while (clockOffset <= -1) { clockOffset += 1; --localTime; } if (localTime < 0) localTime = 0; } private void setCurrentColor(Color newColor) { if (isHighlighted) tmpColor = newColor; else currentColor = newColor; } public synchronized void highlightOn() { tmpColor = currentColor; currentColor = getColor("process.highlight"); isHighlighted = true; } public synchronized void highlightOff() { currentColor = tmpColor; isHighlighted = false; } public synchronized void reset() { isPaused = true; isCrashed = false; localTime = 0; globalTime = 0; clockOffset = 0; lamportTime = 0; lamportTimestamps.clear(); vectorTimestamps.clear(); if (objectExists("protocols.registered")) { Object protocolsObj = getObject("protocols.registered"); if (protocolsObj instanceof Vector) { Vector protocols = (Vector) protocolsObj; for (VSProtocol protocol : protocols) protocol.reset(); } } setCurrentColor(getColor("process.default")); createRandomCrashTask(); } private void createRandomCrashTask() { if (!isCrashed) { VSTaskManager taskManager = simulationPanel.getTaskManager(); long crashTime = getARandomCrashTime(); if (randomCrashTask != null) taskManager.removeTask(randomCrashTask); if (crashTime >= 0 && crashTime >= getGlobalTime()) { randomCrashTask = new VSTask(crashTime, this, new ProcessCrashEvent()); taskManager.addTask(randomCrashTask); //System.out.println("DEBUG " + processID + " crashes at " + crashTime); } else { randomCrashTask = null; } } } public synchronized void addClockOffset(long add) { this.clockOffset += add; } public synchronized void play() { isPaused = false; setCurrentColor(getColor("process.running")); } public synchronized void pause() { isPaused = true; setCurrentColor(getColor("process.stopped")); } public synchronized void finish() { isPaused = true; setCurrentColor(getColor("process.default")); } public synchronized int getProcessID() { return processID; } public synchronized void setProcessID(int processID) { this.processID = processID; } public synchronized Color getColor() { return currentColor; } public synchronized void setLocalTime(final long localTime) { if (localTime >= 0) this.localTime = localTime; else this.localTime = 0; } public synchronized long getTime() { return localTime; } public synchronized void setTime(final long time) { if (time >= 0) this.localTime = time; else this.localTime = 0; this.timeModified = true; } public synchronized boolean isCrashed() { return isCrashed; } public synchronized void isCrashed(boolean isCrashed) { this.isCrashed = isCrashed; } public synchronized Color getCrashedColor() { return crashedColor; } public int getNum() { return num; } public synchronized boolean timeModified() { return timeModified; } public synchronized void timeModified(boolean timeModified) { this.timeModified = timeModified; } public synchronized long getGlobalTime() { return globalTime; } public synchronized void setGlobalTime(final long globalTime) { this.globalTime = globalTime >= 0 ? globalTime : 0; } public synchronized float getClockVariance() { return clockVariance; } public synchronized void setClockVariance(float clockVariance) { /* If negative, only allow < 1 prefs */ if (clockVariance < 0) { int part = (int) -clockVariance; if (part > 0) { this.clockVariance = 0; return; } } this.clockVariance = clockVariance; } public synchronized long getDurationTime() { final long maxDurationTime = getLong("sim.message.sendingtime.max"); final long minDurationTime = getLong("sim.message.sendingtime.min"); if (maxDurationTime <= minDurationTime) return minDurationTime; final int diff = (int) (maxDurationTime - minDurationTime); /* Integer overflow */ if (diff <= 0) return minDurationTime; return minDurationTime + random.nextInt(diff+1); } public synchronized long getARandomMessageOutageTime(final long durationTime) { /* Check if the message will have an outage or not */ if (random.nextInt(100) <= getInteger("sim.message.prob.outage")) { /* Calculate the random outage time! */ final long outageTime = globalTime + random.nextLong(durationTime+1) % simulationPanel.getUntilTime(); return outageTime; } /* No outage */ return -1; } private long getARandomCrashTime() { /* Check if the process will crash or not */ if (random.nextInt(100) <= getInteger("sim.process.prob.crash")) { /* Calculate the random crash time! */ final long crashTime = random.nextLong(simulationPanel.getUntilTime()+1) % simulationPanel.getUntilTime(); return crashTime; } /* No crash */ return -1; } public synchronized VSTask getCrashTask() { return randomCrashTask; } public synchronized boolean isPaused() { return isPaused; } public synchronized long getLamportTime() { return lamportTime; } public synchronized void setLamportTime(long lamportTime) { this.lamportTime = lamportTime; lamportTimestamps.add(new VSLamport(globalTime, lamportTime)); } public synchronized VSLamport[] getLamportArray() { final int size = lamportTimestamps.size(); final VSLamport[] arr = new VSLamport[size]; for (int i = 0; i < size; ++i) arr[i] = lamportTimestamps.get(i); return arr; } public synchronized int[] getVectorTime() { final int size = vectorTimestamps.size(); final int[] arr = new int[size]; for (int i = 0; i < size; ++i) arr[i] = vectorTimestamps.get(i); return arr; } public void sendMessage(VSMessage message) { logg(prefs.getString("lang.message.sent") + "; " + prefs.getString("lang.protocol") + ": " + message.getProtocolName() + "; " + prefs.getString("lang.message") + " " + message.toStringFull()); simulationPanel.sendMessage(message); } public void logg(String message) { logging.logg(toString() + "; " + message, globalTime); } public void fillWithDefaults() { prefs.copyIntegers(this, DEFAULT_INTEGER_VALUE_KEYS); prefs.copyLongs(this, DEFAULT_LONG_VALUE_KEYS); prefs.copyFloats(this, DEFAULT_FLOAT_VALUE_KEYS); prefs.copyColors(this, DEFAULT_COLOR_VALUE_KEYS); prefs.copyStrings(this, DEFAULT_STRING_VALUE_KEYS); } public String toString() { return prefs.getString("lang.process.id") + ": " + getProcessID() + "; " + prefs.getString("lang.process.time.local") + ": " + VSTools.getTimeString(getTime()) + "; Lamport: " + lamportTime; } public String toStringFull() { return toString() + "; paused: " + isPaused + "; crashed: " + isCrashed + "; crashTask: " + randomCrashTask; } public boolean equals(VSProcess process) { return process.getNum() == getNum(); } public VSSimulationPanel getSimulationPanel() { return simulationPanel; } public VSPrefs getPrefs() { return prefs; } public static void resetProcessCounter() { processCounter = 0; } }