diff options
| author | Paul Buetow <paul@buetow.org> | 2025-06-06 08:02:52 +0300 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2025-06-06 08:02:52 +0300 |
| commit | 1d99762c7965d351510cfb5e08eac25e48d96038 (patch) | |
| tree | f469493e911878ab9055ccf0494211bf9015922d /src/main/java/core | |
| parent | 4d35597bd92607c4d194686e20b125044506c79a (diff) | |
Modernize project structure, update Maven config, move sources, add logging config, update README and .gitignore
Diffstat (limited to 'src/main/java/core')
| -rw-r--r-- | src/main/java/core/VSAbstractProcess.java | 738 | ||||
| -rw-r--r-- | src/main/java/core/VSInternalProcess.java | 435 | ||||
| -rw-r--r-- | src/main/java/core/VSMessage.java | 182 | ||||
| -rw-r--r-- | src/main/java/core/VSMessageStub.java | 30 | ||||
| -rw-r--r-- | src/main/java/core/VSTask.java | 503 | ||||
| -rw-r--r-- | src/main/java/core/VSTaskManager.java | 562 | ||||
| -rw-r--r-- | src/main/java/core/time/VSLamportTime.java | 50 | ||||
| -rw-r--r-- | src/main/java/core/time/VSTime.java | 22 | ||||
| -rw-r--r-- | src/main/java/core/time/VSVectorTime.java | 96 |
9 files changed, 2618 insertions, 0 deletions
diff --git a/src/main/java/core/VSAbstractProcess.java b/src/main/java/core/VSAbstractProcess.java new file mode 100644 index 0000000..78e7844 --- /dev/null +++ b/src/main/java/core/VSAbstractProcess.java @@ -0,0 +1,738 @@ +package core; + +import java.awt.Color; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.util.ArrayList; + +import core.time.VSLamportTime; +import core.time.VSTime; +import core.time.VSVectorTime; +import prefs.VSPrefs; +import prefs.VSSerializablePrefs; +import protocols.VSAbstractProtocol; +import serialize.VSSerialize; +import simulator.VSLogging; +import simulator.VSSimulatorVisualization; +import utils.VSPriorityQueue; +import utils.VSRandom; +import utils.VSTools; + +/** + * The class VSAbstractProcess, an object of this class represents a process + * of a simulator. + * + * @author Paul C. Buetow + */ +public abstract class VSAbstractProcess extends VSSerializablePrefs { + /** The data serialization id. */ + protected static final long serialVersionUID = 1L; + + /** The protocols to reset if the simulator is over or the reset + * button has been pressed. + */ + protected ArrayList<VSAbstractProtocol> protocolsToReset; + + /** The crash history. represents all crashes of the process using the + * global simulator time. + */ + protected ArrayList<Long> crashHistory; + + /** The lamport time history. */ + protected ArrayList<VSLamportTime> lamportTimeHistory; + + /** The vector time history. */ + protected ArrayList<VSVectorTime> vectorTimeHistory; + + /** The color used if the process has crashed. */ + protected Color crashedColor;; + + /** The process' current color. */ + protected Color currentColor; + + /** A temp. color. For internal usage. */ + protected Color tmpColor; + + /** The loging object. */ + protected VSLogging loging; + + /** The simulator's default prefs. */ + protected VSPrefs prefs; + + /** The random generator of the process. */ + protected VSRandom random; + + /** The simulator canvas. */ + protected VSSimulatorVisualization simulatorVisualization; + + /** The random crash task. May be null if there is no such random task. */ + protected VSTask randomCrashTask; + + /** The vector time. */ + protected VSVectorTime vectorTime; + + /** The tasks of the process. DO ONLY MANIPULATE THIS OBJECT WITHIN THE + * VSTaskManager CLASS! OTHERWISE THE SYNCHRONIZATION IS WRONG! Use the + * VSAbstractProcess.getTasks() method to get a reference to this object + * within the VSTaskManager! */ + protected VSPriorityQueue<VSTask> tasks; + + /** The process has crashed. But may be working again. */ + protected boolean hasCrashed; + + /** The process has started. But may be paused or crashed.. */ + protected boolean hasStarted; + + /** The process is crashed. */ + protected boolean isCrashed; + + /** The process is highlighted. */ + protected boolean isHighlighted; + + /** The process is paused. */ + protected boolean isPaused; + + /** The time has been modified in a task. Needed by the task manager to + * calculate correct offsets. + */ + protected boolean timeModified; + + /** The clock offset. Used by the task manager and also by the process' + * clock variance. + */ + protected double clockOffset; + + /** The clock variance. */ + protected float clockVariance; + + /** The process id. */ + protected int processID; + + /** The process num. It is different to the process id. It represents the + * array index of there the process is stored at. + */ + protected int processNum; + + /** The global time. */ + protected long globalTime; + + /** The lamport time. */ + protected long lamportTime; + + /** The local time. */ + protected long localTime; + + /** The Constant DEFAULT_INTEGER_VALUE_KEYS. + * 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! + */ + protected static final String DEFAULT_INTEGER_VALUE_KEYS[] = { + "process.prob.crash", + "message.prob.outage", + }; + + /** The Constant DEFAULT_LONG_VALUE_KEYS. + * 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! + */ + protected static final String DEFAULT_LONG_VALUE_KEYS[] = { + "message.sendingtime.min", + "message.sendingtime.max", + }; + + /** The Constant DEFAULT_FLOAT_VALUE_KEYS. + * 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! + */ + protected static final String DEFAULT_FLOAT_VALUE_KEYS[] = { + "process.clock.variance", + }; + + /** The Constant DEFAULT_COLOR_VALUE_KEYS. + * 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! + */ + protected static final String DEFAULT_COLOR_VALUE_KEYS[] = { + "col.process.default", + "col.process.running", + "col.process.stopped", + "col.process.highlight", + "col.process.crashed", + }; + + /** The Constant DEFAULT_STRING_VALUE_KEYS. + * 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! + */ + protected static final String DEFAULT_STRING_VALUE_KEYS[] = { + }; + + /** + * Instantiates a new process. + * + * @param prefs the simulator's default prefs + * @param processNum the process num + * @param simulatorVisualization the simulator canvas + * @param loging the loging object + */ + public VSAbstractProcess(VSPrefs prefs, int processNum, + VSSimulatorVisualization simulatorVisualization, + VSLogging loging) { + init(prefs, processNum, simulatorVisualization, loging); + } + + /** + * Inits a the process. + * + * @param prefs the simulator's default prefs + * @param processNum the process num + * @param simulatorVisualization the simulator canvas + * @param loging the loging object + */ + protected void init(VSPrefs prefs, int processNum, + VSSimulatorVisualization simulatorVisualization, + VSLogging loging) { + /* May be not null if called from deserialization */ + if (this.protocolsToReset == null) + this.protocolsToReset = new ArrayList<VSAbstractProtocol>(); + + this.processNum = processNum; + this.prefs = prefs; + this.simulatorVisualization = simulatorVisualization; + this.loging = loging; + + processID = simulatorVisualization.processIDCount(); + random = new VSRandom(processID*processNum+processID+processNum); + tasks = new VSPriorityQueue<VSTask>(); + + initTimeFormats(); + + isPaused = true; + + /* Create the super.VSPrefs with it's default prefs */ + fillWithDefaults(); + + /* Make local copys in order to have more performance */ + clockVariance = getFloat("process.clock.variance"); + currentColor = getColor("col.process.default"); + crashedColor = getColor("col.process.crashed"); + + /* Make additional process settings editable through GUI */ + initLong("process.localtime", localTime, + prefs.getString("lang.process.time.local"), "ms"); + + createRandomCrashTask_(); + } + + /** + * Inits the time formats. E.g. lamport and vector time stamps. + */ + protected void initTimeFormats() { + lamportTime = 0; + lamportTimeHistory = new ArrayList<VSLamportTime>(); + + vectorTime = new VSVectorTime(0); + vectorTimeHistory = new ArrayList<VSVectorTime>(); + crashHistory = new ArrayList<Long>(); + + final int numProcesses = simulatorVisualization.getNumProcesses(); + for (int i = 0; i < numProcesses; ++i) + vectorTime.add(Long.valueOf(0)); + } + + /** + * Reset time formats. E.g. lamport and vector time stamps. + */ + protected void resetTimeFormats() { + lamportTime = 0; + lamportTimeHistory.clear(); + + vectorTime = new VSVectorTime(0); + vectorTimeHistory.clear(); + crashHistory.clear(); + + final int numProcesses = simulatorVisualization.getNumProcesses(); + for (int i = numProcesses; i > 0; --i) + vectorTime.add(Long.valueOf(0)); + } + + /** + * Creates a random percentage 0..100 using the process' own pseudo + * random number generator object of the VSRandom class. + * + * @return A random percentage 0..100. + */ + public synchronized int getRandomPercentage() { + return random.nextInt() % 101; + } + + /** + * Adds the clock offset. This method is used by the task manager. The + * clock offset identifies if the local time of the process has changed and + * how much.. + * + * @param add the clock offset to add. + */ + protected synchronized void addClockOffset(long add) { + this.clockOffset += add; + } + + /** + * Gets the process id. + * + * @return the process id + */ + public synchronized int getProcessID() { + return processID; + } + + /** + * Gets the process num. The num is different to the process id. It + * represents the array index of there the process is stored at. + * + * @return the process num + */ + public synchronized int getProcessNum() { + return processNum; + } + + /** + * Sets the process id. + * + * @param processID the new process id + */ + public synchronized void setProcessID(int processID) { + this.processID = processID; + } + + /** + * Gets the process' local time. + * + * @return the process' local time + */ + public synchronized long getTime() { + return localTime; + } + + /** + * Sets the process' local time. + * + * @param time the new local time of the process. + */ + public synchronized void setTime(final long time) { + if (time >= 0) + this.localTime = time; + else + this.localTime = 0; + + this.timeModified = true; + } + + /** + * Checks if the process is crashed. + * + * @return true, if is crashed + */ + public synchronized boolean isCrashed() { + return isCrashed; + } + + /** + * Sets if the process is crashed. + * + * @param isCrashed true if the process is crashed. + */ + public synchronized void isCrashed(boolean isCrashed) { + this.isCrashed = isCrashed; + crashHistory.add(Long.valueOf(globalTime)); + if (!hasCrashed) + hasCrashed = true; + } + + /** + * Checks if the process has crashed. The difference to isCrashed is, + * that the process may be fully functional again after crashing. This + * method is needed by the simulator canvas in order to see if it should + * paint 'crashed areas' using the crash history of this process. + * + * @return true, if yes + */ + public synchronized boolean hasCrashed() { + return hasCrashed; + } + + /** + * Gets the global time. + * + * @return the global time + */ + public synchronized long getGlobalTime() { + return globalTime; + } + + /** + * Gets the clock variance. + * + * @return the clock variance + */ + public synchronized float getClockVariance() { + return clockVariance; + } + + /** + * Sets the clock variance. + * + * @param clockVariance the new clock variance + */ + 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; + } + + /** + * Gets the a random crash time. + * + * @return the a random crash time. It will be -1 if the process will not + * crash at all randomly! + */ + protected long getARandomCrashTime() { + /* Check if the process will crash or not */ + if (getRandomPercentage() < getInteger("process.prob.crash")) { + /* Calculate the random crash time! */ + final long crashTime = + random.nextLong(simulatorVisualization.getUntilTime()+1) % + simulatorVisualization.getUntilTime(); + return crashTime; + } + + /* No crash */ + return -1; + } + + /** + * Increases the process' lamport time. + */ + public synchronized void increaseLamportTime() { + setLamportTime(getLamportTime()+1); + } + + /** + * Updates the process' lamport time. + * + * @param time the lamport time to use as its update reference. + */ + public synchronized void updateLamportTime(long time) { + final long lamportTime = getLamportTime() + 1; + + if (time > lamportTime) + setLamportTime(time); + else + setLamportTime(lamportTime); + } + + /** + * Gets the lamport time. + * + * @return the lamport time. + */ + public synchronized long getLamportTime() { + return lamportTime; + } + + /** + * Sets the lamport time. + * + * @param lamportTime the new lamport time + */ + public synchronized void setLamportTime(long lamportTime) { + this.lamportTime = lamportTime; + lamportTimeHistory.add(new VSLamportTime(globalTime, lamportTime)); + } + + /** + * Gets the lamport time history as an array. + * + * @return the lamport time history array + */ + public synchronized VSTime[] getLamportTimeArray() { + final int size = lamportTimeHistory.size(); + final VSTime[] arr = new VSLamportTime[size]; + + for (int i = 0; i < size; ++i) + arr[i] = (VSTime) lamportTimeHistory.get(i); + + return arr; + } + + /** + * Increases the vector and the lamport time by 1 each if + * sim.update.vectortime.all/sim.update.lamporttime.all are set + * to true. + */ + public void increaseVectorAndLamportTimeIfAll() { + if (prefs.getBoolean("sim.update.lamporttime.all")) + increaseLamportTime(); + + if (prefs.getBoolean("sim.update.vectortime.all")) + increaseVectorTime(); + } + + /** + * Increases the vector time by 1. + */ + public synchronized void increaseVectorTime() { + vectorTime.set(processNum, + Long.valueOf(vectorTime.get(processNum).longValue()+1)); + vectorTime.setGlobalTime(globalTime); + vectorTimeHistory.add(vectorTime.getCopy()); + } + + /** + * Updates the vector time. + * + * @param vectorTimeUpdate the vector time of the other process to use for + * the update + */ + public synchronized void updateVectorTime(VSVectorTime vectorTimeUpdate) { + final int size = vectorTime.size(); + + for (int i = 0; i < size; ++i) { + if (i == processNum) + vectorTime.set(i, Long.valueOf(vectorTime.get(i).longValue()+1)); + else if (vectorTimeUpdate.get(i) > vectorTime.get(i)) + vectorTime.set(i, vectorTimeUpdate.get(i)); + } + + vectorTime.setGlobalTime(globalTime); + vectorTimeHistory.add(vectorTime.getCopy()); + } + + /** + * Gets the vector time. + * + * @return the vector time + */ + public synchronized VSVectorTime getVectorTime() { + return vectorTime; + } + + /** + * Gets the vector time history as an array. + * + * @return the vector time history array + */ + public synchronized VSTime[] getVectorTimeArray() { + final int size = vectorTimeHistory.size(); + final VSTime[] arr = new VSTime[size]; + + for (int i = 0; i < size; ++i) + arr[i] = (VSTime) vectorTimeHistory.get(i); + + return arr; + } + + /** + * Gets the crash history array. + * + * @return the crash history array + */ + public synchronized Long[] getCrashHistoryArray() { + final int size = crashHistory.size(); + final Long[] arr = new Long[size]; + + for (int i = 0; i < size; ++i) + arr[i] = crashHistory.get(i); + + return arr; + } + + /** + * Logg a message to the loging area. + * + * @param message the message to log + */ + public void log(String message) { + loging.log(toString() + "; " + message, globalTime); + } + + /* (non-Javadoc) + * @see prefs.VSPrefs#fillWithDefaults() + */ + 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); + } + + /* (non-Javadoc) + * @see prefs.VSPrefs#toString() + */ + public synchronized String toString() { + StringBuffer buffer = new StringBuffer(); + buffer.append(prefs.getString("lang.process.id")); + buffer.append(": "); + buffer.append(getProcessID()); + buffer.append("; "); + buffer.append(prefs.getString("lang.process.time.local")); + buffer.append(": "); + buffer.append(VSTools.getTimeString(getTime())); + buffer.append("; "); + buffer.append(prefs.getString("lang.time.lamport")); + buffer.append(": "); + buffer.append(lamportTime); + buffer.append("; "); + buffer.append(prefs.getString("lang.time.vector")); + buffer.append(": "); + buffer.append(vectorTime); + return buffer.toString(); + } + + /** + * The extended string representation of the process object. + * + * @return the extended string representation + */ + public synchronized String toStringFull() { + StringBuffer buffer = new StringBuffer(); + buffer.append(toString()); + buffer.append("; paused: "); + buffer.append(isPaused); + buffer.append("; crashed: "); + buffer.append(isCrashed); + buffer.append("; crashTask: "); + buffer.append(randomCrashTask); + return buffer.toString(); + } + + /** + * Equals. Checks, if both processes have the same process num. + * + * @param process the process to compare to + * + * @return true, if both processes are the same (same processNum). + */ + public boolean equals(VSAbstractProcess process) { + return process.getProcessNum() == processNum; + } + + /** + * Gets the simulator's default prefs. + * + * @return the default prefs + */ + public VSPrefs getPrefs() { + return prefs; + } + + /* (non-Javadoc) + * @see serialize.VSSerializable#serialize(serialize.VSSerialize, + * java.io.ObjectOutputStream) + */ + public synchronized void serialize(VSSerialize serialize, + ObjectOutputStream objectOutputStream) + throws IOException { + super.serialize(serialize, objectOutputStream); + + if (VSSerialize.DEBUG) + System.out.println("Serializing: VSAbstractProcess (num: " + + processNum + + "; id: " + processID + ")"); + + /** For later backwards compatibility, to add more stuff */ + objectOutputStream.writeObject(Boolean.valueOf(false)); + + objectOutputStream.writeObject(Integer.valueOf(processID)); + objectOutputStream.writeObject(Integer.valueOf(protocolsToReset.size())); + for (VSAbstractProtocol protocol : protocolsToReset) { + objectOutputStream.writeObject(protocol.getClassname()); + protocol.serialize(serialize, objectOutputStream); + } + + /** For later backwards compatibility, to add more stuff */ + objectOutputStream.writeObject(Boolean.valueOf(false)); + } + + /* (non-Javadoc) + * @see serialize.VSSerializable#deserialize(serialize.VSSerialize, + * java.io.ObjectInputStream) + */ + public synchronized void deserialize(VSSerialize serialize, + ObjectInputStream objectInputStream) + throws IOException, ClassNotFoundException { + super.deserialize(serialize, objectInputStream); + + /* Bugfix, being compatible with old versions */ + super.deleteLong("process.localTime"); + + updateFromPrefs_(); + + if (VSSerialize.DEBUG) + System.out.println("Deserializing: VSAbstractProcess"); + + /** For later backwards compatibility, to add more stuff */ + objectInputStream.readObject(); + + this.processID = ((Integer) + objectInputStream.readObject()).intValue(); + int numProtocols = ((Integer) + objectInputStream.readObject()).intValue(); + + for (int i = 0; i < numProtocols; ++i) { + String protocolClassname = (String) objectInputStream.readObject(); + VSAbstractProtocol protocol = getProtocolObject_(protocolClassname); + protocol.deserialize(serialize, objectInputStream); + } + + localTime = 0; + setLong("process.localtime", localTime); + + /** For later backwards compatibility, to add more stuff */ + objectInputStream.readObject(); + + serialize.setObject(processNum, "process", this); + } + + /** + * Sets the current color. + * + * @param newColor the new current color + */ + protected void setCurrentColor(Color newColor) { + if (isHighlighted) + tmpColor = newColor; + else + currentColor = newColor; + } + + /* (non-Javadoc) + * @see core.VSInternalMessage#updateFromPrefs() + */ + protected abstract void updateFromPrefs_(); + + /* (non-Javadoc) + * @see core.VSInternalMessage#createRandomCrashTask() + */ + protected abstract void createRandomCrashTask_(); + + /* (non-Javadoc) + * @see core.VSInternalMessage#getProtocolObjekt(java.util.String) + */ + protected abstract VSAbstractProtocol getProtocolObject_( + String protocolClassname); +} diff --git a/src/main/java/core/VSInternalProcess.java b/src/main/java/core/VSInternalProcess.java new file mode 100644 index 0000000..81cc3fd --- /dev/null +++ b/src/main/java/core/VSInternalProcess.java @@ -0,0 +1,435 @@ +package core; + +import java.awt.Color; + +import core.time.VSVectorTime; +import events.VSAbstractEvent; +import events.VSRegisteredEvents; +import events.implementations.VSProcessCrashEvent; +import prefs.VSPrefs; +import protocols.VSAbstractProtocol; +import simulator.VSLogging; +import simulator.VSSimulatorVisualization; +import utils.VSPriorityQueue; + +/** + * The class VSInternalProcess, an object of this class represents a process + * of a simulator. + * + * @author Paul C. Buetow + */ +public class VSInternalProcess extends VSAbstractProcess { + /** + * Instantiates a new process. + * + * @param prefs the simulator's default prefs + * @param processNum the process num + * @param simulatorVisualization the simulator canvas + * @param loging the loging object + */ + public VSInternalProcess(VSPrefs prefs, int processNum, + VSSimulatorVisualization simulatorVisualization, + VSLogging loging) { + super(prefs, processNum, simulatorVisualization, loging); + } + + /** + * Called from the VSProcessEditor, after finishing editing! This makes + * sure that the VSInternalProcess object is using the up to date prefs! + */ + public synchronized void updateFromPrefs() { + setClockVariance(getFloat("process.clock.variance")); + setLocalTime(getLong("process.localtime")); + crashedColor = getColor("col.process.crashed"); + createRandomCrashTask(); + } + + /** + * Called from the VSProcessEditor, before starting editing! This makes + * sure that the editor edits the up to date prefs of the process! + */ + public synchronized void updatePrefs() { + setFloat("process.clock.variance", getClockVariance()); + setLong("process.localtime", getTime()); + } + + /** + * Syncs the process' time. This method is using the clockOffset and + * clockVariance variables. This method is called repeatedly from the + * VSSimulatorVisualization in order to update the process' local and global + * time values. + * + * @param globalTime the global time. + */ + public synchronized void syncTime(final long globalTime) { + final long currentGlobalTimestep = globalTime - this.globalTime; + this.globalTime = globalTime; + + localTime += currentGlobalTimestep; + clockOffset += currentGlobalTimestep * (double) clockVariance; + + while (clockOffset >= 1) { + clockOffset -= 1; + ++localTime; + } + + while (clockOffset <= -1) { + clockOffset += 1; + --localTime; + } + + /* We do not want a negative time */ + if (localTime < 0) + localTime = 0; + } + + /** + * Highlights the process. + */ + public synchronized void highlightOn() { + tmpColor = currentColor; + currentColor = getColor("col.process.highlight"); + isHighlighted = true; + } + + /** + * Unhighlights the process. + */ + public synchronized void highlightOff() { + currentColor = tmpColor; + isHighlighted = false; + } + + /** + * Resets the process. + */ + public synchronized void reset() { + isPaused = true; + isCrashed = false; + hasCrashed = false; + localTime = 0; + globalTime = 0; + clockOffset = 0; + + for (VSAbstractProtocol protocol : protocolsToReset) + protocol.reset(); + + setCurrentColor(getColor("col.process.default")); + resetTimeFormats(); + } + + /** + * Creates the random crash task. The crash task will be created only if + * the process is not crashed atm. and if + * VSInternalProcess.getARandomCrashTime() * returns a non-negative value. + * The random crash task uses the simulaion's global time for its + * scheduling. + */ + public synchronized void createRandomCrashTask() { + if (!isCrashed) { + VSTaskManager taskManager = simulatorVisualization.getTaskManager(); + long crashTime = getARandomCrashTime(); + + if (crashTime < 0) + return; + + if (randomCrashTask != null) + taskManager.removeTask(randomCrashTask); + + if (crashTime >= getGlobalTime()) { + VSAbstractEvent event = new VSProcessCrashEvent(); + randomCrashTask = new VSTask(crashTime, this, event, + VSTask.GLOBAL); + taskManager.addTask(randomCrashTask); + + } else { + randomCrashTask = null; + } + } + } + + /** + * Creates a random percentage 0..100 using the process' own pseudo + * random number generator object of the VSRandom class. + * + * @return A random percentage 0..100. + */ + public synchronized int getRandomPercentage() { + return random.nextInt() % 101; + } + + /** + * Adds the clock offset. This method is used by the task manager. The + * clock offset identifies if the local time of the process has changed and + * how much.. + * + * @param add the clock offset to add. + */ + public synchronized void addClockOffset(long add) { + this.clockOffset += add; + } + + /** + * The process' state is 'play'. Called by the simulator canvas. + */ + public synchronized void play() { + isPaused = false; + setCurrentColor(getColor("col.process.running")); + } + + /** + * The process' state is 'pause'. Called by the simulator canvas. + */ + public synchronized void pause() { + isPaused = true; + setCurrentColor(getColor("col.process.stopped")); + } + + /** + * The process' state is 'Finish'. Called by the simulator canvas. + */ + public synchronized void finish() { + isPaused = true; + setCurrentColor(getColor("col.process.default")); + } + + /** + * Gets the current process' color. + * + * @return the current color of the process. + */ + public synchronized Color getColor() { + return currentColor; + } + + /** + * Gets the color of this process if it's crashed. + * + * @return the crashed color + */ + public synchronized Color getCrashedColor() { + return crashedColor; + } + + /** + * Checks if the time has been modified. by a task. + * This mehod is needed by the task manager in order to add a clock offset + * to the process object. + * + * @return true, if yes + */ + public synchronized boolean timeModified() { + return timeModified; + } + + /** + * Sets if the time has been modified by a task. + * + * @param timeModified true, if it has been modified. + */ + public synchronized void timeModified(boolean timeModified) { + this.timeModified = timeModified; + } + + /** + * Sets the global time. + * + * @param globalTime the new global time + */ + public synchronized void setGlobalTime(final long globalTime) { + this.globalTime = globalTime >= 0 ? globalTime : 0; + } + + /* Gets the duration time of a message to send. + * + * @return the duration time + */ + public synchronized long getDurationTime() { + final long maxDurationTime = getLong("message.sendingtime.max"); + final long minDurationTime = getLong("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); + } + + /** + * Gets the a random message outage time. + * + * @param durationTime the duration time + * + * @return the a random message outage time. It will be -1 if the message + * will not get lost at all. + */ + public synchronized long getARandomMessageOutageTime(long durationTime, + VSInternalProcess receiverProcess) { + int percentage = (int) ((getInteger("message.prob.outage") + + receiverProcess.getInteger( + "message.prob.outage")) / 2); + + /* Check if the message will have an outage or not */ + if (getRandomPercentage() < percentage) { + + /* Calculate the random outage time! */ + long outageTime = globalTime + random.nextLong(durationTime+1) % + simulatorVisualization.getUntilTime(); + + return outageTime; + } + + /* No outage */ + return -1; + } + + /** + * Gets the random crash task. + * + * @return the random crash task + */ + public synchronized VSTask getCrashTask() { + return randomCrashTask; + } + + /** + * Checks if the process is paused. + * + * @return true, if is paused + */ + public synchronized boolean isPaused() { + return isPaused; + } + + /** + * Called by a task if the process sends a message. + * + * @param message the message to send. + */ + public synchronized void sendMessage(VSMessage message) { + StringBuffer buffer = new StringBuffer(); + buffer.append(prefs.getString("lang.message.sent")); + buffer.append("; "); + buffer.append(message.toStringFull()); + log(buffer.toString()); + simulatorVisualization.sendMessage(message); + } + + /** + * Gets the simulator canvas. + * + * @return the simulator canvas + */ + public VSSimulatorVisualization getSimulatorCanvas() { + return simulatorVisualization; + } + + /** + * Removes the process at the specified index. Called by the simulator + * canvas if a process has been removed from the simulator. Needed in + * order to update the vector time and the local processNum. + * + * @param index the index the process has to get removed. + */ + public synchronized void removedAProcessAtIndex(int index) { + if (index < processNum) + --processNum; + + vectorTime.remove(index); + for (VSVectorTime vectorTime : vectorTimeHistory) + vectorTime.remove(index); + } + + /** + * Added a process. Needed in order to update the vector time's size. + * Called by the simulator canvas if a process has been added to the + * simulator. + */ + public synchronized void addedAProcess() { + vectorTime.add(Long.valueOf(0)); + for (VSVectorTime vectorTime : vectorTimeHistory) + vectorTime.add(Long.valueOf(0)); + } + + /** + * Gets the tasks of the process. + * + * @return The tasks + */ + public VSPriorityQueue<VSTask> getTasks() { + return tasks; + } + + /** + * Sets the tasks of the process. + * + * @param tasks The tasks + */ + public void setTasks(VSPriorityQueue<VSTask> tasks) { + this.tasks = tasks; + } + + /** + * Gets the protocol object. + * + * @param protocolClassname the protocol classname + * + * @return the protocol object + */ + public synchronized VSAbstractProtocol getProtocolObject( + String protocolClassname) { + VSAbstractProtocol protocol = null; + + if (!objectExists(protocolClassname)) { + protocol = (VSAbstractProtocol) + VSRegisteredEvents.createEventInstanceByClassname( + protocolClassname, this); + + setObject(protocolClassname, protocol); + protocolsToReset.add(protocol); + + } else { + protocol = (VSAbstractProtocol) getObject(protocolClassname); + } + + return protocol; + } + + /** + * Sets the local time. + * + * @param localTime the new local time. + */ + public synchronized void setLocalTime(final long localTime) { + if (localTime >= 0) + this.localTime = localTime; + else + this.localTime = 0; + } + + /* (non-Javadoc) + * @see core.VSInternalMessage#updateFromPrefs() + */ + protected void updateFromPrefs_() { + updateFromPrefs(); + } + + /* (non-Javadoc) + * @see core.VSInternalMessage#createRandomCrashTask() + */ + protected void createRandomCrashTask_() { + createRandomCrashTask(); + } + + /* (non-Javadoc) + * @see core.VSInternalMessage#getProtocolObjekt(java.util.String) + */ + protected VSAbstractProtocol getProtocolObject_(String protocolClassname) { + return getProtocolObject(protocolClassname); + } +} diff --git a/src/main/java/core/VSMessage.java b/src/main/java/core/VSMessage.java new file mode 100644 index 0000000..a7b48e6 --- /dev/null +++ b/src/main/java/core/VSMessage.java @@ -0,0 +1,182 @@ +package core; + +import core.time.VSVectorTime; +import events.VSRegisteredEvents; +import prefs.VSPrefs; + +/** + * An object of this class represents a message which is sent from one process + * to another process in the simulator. + * + * @author Paul C. Buetow + */ +public class VSMessage extends VSPrefs { + /** The constant IS_SERVER_MESSAGE. */ + public static final boolean IS_SERVER_MESSAGE = true; + + /** The constant IS_CLIENT_MESSAGE. */ + public static final boolean IS_CLIENT_MESSAGE = false; + + /** true, if the message has been sent from a server. false, if the message + * has been sent from a client. + */ + private boolean isServerMessage; + + /** Each message belongs to a specific protocol. This variable defined the + * class name of the protocol being used. + */ + private String protocolClassname; + + /** The default application preferences. */ + private VSPrefs prefs; + + /** A reference to the process who sent this message. */ + private VSInternalProcess sendingProcess; + + /** The vector time of the sending process after sending. The receiver + * process will use this vector time in order to update the local vector + * time. + */ + private VSVectorTime vectorTime; + + /** The lamport time of the sending process after sending. The receiver + * process will use this lamport time in order to update the local vector + * time. + */ + private long lamportTime; + + /** Each message has its own unique ID. The ID will show up in the loging + * window of the simulator + */ + private long messageID; + + /** This counter is used in order to generate unique message ID's. */ + private static long messageCounter; + + /** + * The constructor of the message. Creates a new message object. + */ + public VSMessage() { + this.messageID = ++messageCounter; + } + + /** + * Initializes the message. + * + * @param process The sending process of this message. + * @param protocolClassname The classname of the protocol this message. + * @param isServerMessage Sets if the message has been sent by a server. + */ + void init(VSInternalProcess process, String protocolClassname, + boolean isServerMessage) { + this.sendingProcess = process; + this.protocolClassname = protocolClassname; + this.isServerMessage = isServerMessage; + this.prefs = process.getPrefs(); + + lamportTime = sendingProcess.getLamportTime(); + vectorTime = sendingProcess.getVectorTime().getCopy(); + } + + /** + * Gets the protocol name of the message. + * + * @return The protocol name of the message. + */ + public String getName() { + return VSRegisteredEvents.getNameByClassname(getProtocolClassname()); + } + + /** + * Gets the protocol classname. + * + * @return The protocol classname of the message. + */ + public String getProtocolClassname() { + return protocolClassname; + } + + /** + * Gets the message id. + * + * @return The id of the message. + */ + public long getMessageID() { + return messageID; + } + + /** + * Gets a reference of the sending process. + * + * @return The process which sent this message. + */ + public VSAbstractProcess getSendingProcess() { + return sendingProcess; + } + + /** + * Gets the lamport time. + * + * @return The lamport time of the sending process. + */ + public long getLamportTime() { + return lamportTime; + } + + /** + * Gets the vector time. + * + * @return The vector time of the sending process. + */ + public VSVectorTime getVectorTime() { + return vectorTime; + } + + /** + * Checks if the message has been sent by a server or a client. + * + * @return true, if the message has been sent by a server. false, if the + * message has been sent by a client. + */ + public boolean isServerMessage() { + return isServerMessage; + } + + /* (non-Javadoc) + * @see prefs.VSPrefs#toString() + */ + public String toString() { + StringBuffer buffer = new StringBuffer(); + + buffer.append("ID: "); + buffer.append(messageID); + buffer.append("; "); + buffer.append(prefs.getString("lang.protocol")); + buffer.append(": "); + buffer.append(VSRegisteredEvents.getShortnameByClassname( + getProtocolClassname())); + + return buffer.toString(); + } + + /** + * Extended string representation of the message object. + * + * @return Extended string representation of the message object. + */ + public String toStringFull() { + return toString() + "; " + super.toString(); + } + + /** + * Compares two messages. + * + * @param message The message to compare with. + * + * @return true, if the messages have the same id. Otherwise false. + */ + public boolean equals(VSMessage message) { + return messageID == message.getMessageID(); + } +} + diff --git a/src/main/java/core/VSMessageStub.java b/src/main/java/core/VSMessageStub.java new file mode 100644 index 0000000..95a515b --- /dev/null +++ b/src/main/java/core/VSMessageStub.java @@ -0,0 +1,30 @@ +package core; + +/** + * An object of this class represents a message stub. A message stub allows + * to run the init method on a VSMessage object. The init method should be + * hidden by the protocol programming API. + * + * @author Paul C. Buetow + */ +public class VSMessageStub { + /** The message */ + private VSMessage message; + + /** + * The constructor of the message stub. Creates a new message stub object. + * + * @param message the message + */ + public VSMessageStub(VSMessage message) { + this.message = message; + } + + /* (non-Javadoc) + * @see core.VSMessage#init(VSInternalProcess, java.util.String, boolean) + */ + public void init(VSInternalProcess process, String protocolClassname, + boolean isServerMessage) { + message.init(process, protocolClassname, isServerMessage); + } +} diff --git a/src/main/java/core/VSTask.java b/src/main/java/core/VSTask.java new file mode 100644 index 0000000..54d7ff1 --- /dev/null +++ b/src/main/java/core/VSTask.java @@ -0,0 +1,503 @@ +package core; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; + +import events.VSAbstractEvent; +import events.VSRegisteredEvents; +import events.implementations.VSProcessCrashEvent; +import events.implementations.VSProcessRecoverEvent; +import events.internal.VSAbstractInternalEvent; +import events.internal.VSMessageReceiveEvent; +import events.internal.VSProtocolEvent; +import exceptions.VSEventNotCopyableException; +import prefs.VSPrefs; +import protocols.VSAbstractProtocol; +//import utils.*; +import serialize.VSNotSerializable; +import serialize.VSSerializable; +import serialize.VSSerialize; + +/** + * The class VSTask, an object of this class represents a task to do or done. + * All tasks are managed by the task manager. There are local and global timed + * tasks. Local timed tasks are being fullfilled if the process' local time is + * reached. Global timed tasks are being fullfilled if the simulator's time is + * reached. + * + * @author Paul C. Buetow + */ +public class VSTask implements Comparable<Object>, VSSerializable { + /** The Constant LOCAL. Used for the constructor if it's a local timed + * task. + */ + public final static boolean LOCAL = true; + + /** The Constant GLOBAL. Used for the constructor if it's a global timed + * task. + */ + public final static boolean GLOBAL = false; + + /** The task time. */ + private long taskTime; + + /** The event which takes plase if the task time matches. */ + private VSAbstractEvent event; + + /** The process to run the task at. */ + private VSInternalProcess process; + + /** The simulator's default prefs. */ + private VSPrefs prefs; + + /** The task is programmed. The task will be still in the task manager + * after reset. + */ + private boolean isProgrammed; + + /** The task is global timed. If set to true, its local timed. */ + private boolean isGlobalTimed; + + /** The task counter. Needed for the unique task numbers. */ + private static int taskCounter; + + /** The task number. */ + private int taskNum; + + /** + * Instantiates a new task. + * + * @param taskTime the task time + * @param process the process + * @param event the event + * @param isLocal the taks is local timed + */ + public VSTask(long taskTime, VSInternalProcess process, + VSAbstractEvent event, + boolean isLocal) { + init(taskTime, process, event, isLocal); + } + + /** + * Instantiates a new task, it's a copy constructor. + * + * @param task the task to copy + */ + public VSTask(VSTask task) { + VSAbstractEvent event = task.getEvent(); + + try { + // Use the copy of the event object + event = event.getCopy(); + + } catch (VSEventNotCopyableException e) { + // Use the original event object + } + + init(task.getTaskTime(), + task.getProcess(), + event, + !task.isGlobalTimed()); + } + + /** + * Instantiates a new task during a deserialization. + * + * @param serialize the serialize object + * @param objectInputStream The input stream + */ + public VSTask(VSSerialize serialize, ObjectInputStream objectInputStream) + throws IOException, ClassNotFoundException { + deserialize(serialize, objectInputStream); + } + + /** + * Inits the task + * + * @param taskTime the task time + * @param process the process + * @param event the event + * @param isLocal the taks is local timed + */ + private void init(long taskTime, VSInternalProcess process, + VSAbstractEvent event, boolean isLocal) { + this.process = process; + this.taskTime = taskTime > 0 ? taskTime : 0; + /* May be not null if called from deserialization */ + if (this.event == null) + this.event = event; + this.prefs = process.getPrefs(); + this.isGlobalTimed = !isLocal; + this.taskNum = ++taskCounter; + } + + /** + * Gets the task num. + * + * @return the task num + */ + public int getTaskNum() { + return taskNum; + } + + /** + * Sets if the task is programmed. + * + * @param isProgrammed true, if the task is programmed + */ + public void isProgrammed(boolean isProgrammed) { + this.isProgrammed = isProgrammed; + } + + /** + * Checks if the task is programmed. + * + * @return true, if the task is programmed + */ + public boolean isProgrammed() { + return isProgrammed; + } + + /** + * Checks if the task is using an "internal event". + * + * @return true, if the task is using an internal event + */ + public boolean hasInternalEvent() { + return event instanceof VSAbstractInternalEvent; + } + + /** + * Checks if the task should not get serialized. + * + * @return true, if the task should not get serialized + */ + public boolean hasNotSerializableEvent() { + return event instanceof VSNotSerializable; + } + + /** + * Checks if the task is a message receive event. + * + * @return true, if it is a message receive event + */ + public boolean hasMessageReceiveEvent() { + return event instanceof VSMessageReceiveEvent; + } + + /** + * Checks if the task is a process recover event. + * + * @return true, if it is a process recover event + */ + public boolean hasProcessRecoverEvent() { + return event instanceof VSProcessRecoverEvent; + } + + /** + * Checks if the task belongs to the specified protocol object. + * + * @param protocol the protocol object to check against. + * + * @return true, if it's a task using the protocol object. + */ + public boolean isProtocol(VSAbstractProtocol protocol) { + if (event instanceof VSAbstractProtocol) + return ((VSAbstractProtocol) event).equals(protocol); + + return false; + } + + /** + * Checks if the task's time is over. + * + * @return true, if it's over + */ + public boolean timeOver() { + if (isGlobalTimed) + return taskTime < process.getGlobalTime(); + + return taskTime < process.getTime(); + } + + /** + * Checks if the task equals to another task. + * + * @param task the task to compare to + * + * @return true, if equal (the task nums equal) + */ + public boolean equals(VSTask task) { + return taskNum == task.getTaskNum(); + } + + /** + * Checks if the task belongs to the specified process. + * + * @param process the process to check against + * + * @return true, if the task is using the process + */ + public boolean isProcess(VSInternalProcess process) { + return this.process.equals(process); + } + + /** + * Checks if the task is global timed. + * + * @return true, if the taks is global timed + */ + public boolean isGlobalTimed() { + return isGlobalTimed; + } + + /** + * Gets the process. + * + * @return the process of the event + */ + public VSInternalProcess getProcess() { + return process; + } + + /** + * Runs the task. + */ + public void run() { + if (event.getProcess() == null) + event.init(process); + + if (!(event instanceof VSMessageReceiveEvent) + && !(event instanceof VSAbstractProtocol)) + process.increaseVectorAndLamportTimeIfAll(); + + event.onStart(); + } + + /** + * Gets the task time. + * + * @return the task time + */ + public long getTaskTime() { + return taskTime; + } + + /** + * Sets the task time. + * + * @param taskTime the task time + */ + public void setTaskTime(long taskTime) { + this.taskTime = taskTime; + } + + /** + * Sets the process. + * + * @param process the process + */ + public void setProcess(VSInternalProcess process) { + /* Only do it if the process differs */ + if (!this.process.equals(process)) { + this.process = process; + + try { + // Use the copy of the event object + event = event.getCopy(process); + + } catch (VSEventNotCopyableException e) { + if (event instanceof VSAbstractProtocol) { + String eventShortname = event.getShortname(); + event = process.getProtocolObject(event.getClassname()); + event.setShortname(eventShortname); + } else { + System.out.println(e); + } + } + } + } + + /** + * Gets the event. + * + * @return the event + */ + public VSAbstractEvent getEvent() { + return event; + } + + /* + private void log(String message) { + process.log(message); + } + */ + + /* (non-Javadoc) + * @see java.lang.Object#toString() + */ + public String toString() { + StringBuffer buffer = new StringBuffer(); + + buffer.append(prefs.getString("lang.task")); + buffer.append(" "); + buffer.append(getTaskTime()); + buffer.append(event.toString()); + buffer.append("; PID: "); + buffer.append(process.getProcessID()); + /* + if (isProgrammed()) { + buffer.append("; Programmed"); + } + */ + + return buffer.toString(); + } + + /* (non-Javadoc) + * @see java.lang.Comparable#compareTo(java.lang.Object) + */ + public int compareTo(Object object) { + if (object instanceof VSTask) { + final VSTask task = (VSTask) object; + + if (taskTime < task.getTaskTime()) + return -1; + + else if (taskTime > task.getTaskTime()) + return 1; + + VSAbstractEvent event2 = task.getEvent(); + + /* If it's a recovering, it should get handled very first */ + boolean a = event instanceof VSProcessRecoverEvent; + boolean b = event2 instanceof VSProcessRecoverEvent; + + if (a && b) + return 0; + + if (a) + return -1; + + if (b) + return 1; + + /* If it's a crash, it should get handled second first */ + a = event instanceof VSProcessCrashEvent; + b = event2 instanceof VSProcessCrashEvent; + + if (a && b) + return 0; + + if (a) + return -1; + + if (b) + return 1; + + /* If it's a VSProtocolEvent, it should get handled third */ + a = event instanceof VSProtocolEvent; + b = event2 instanceof VSProtocolEvent; + + if (a && b) + return 0; + + if (a) + return -1; + + if (b) + return 1; + + String shortname = event.getShortname(); + String shortname2 = event2.getShortname(); + + /* One of those may be null if an VSAbstractEvent object has not + been initialized yet */ + if (shortname == null || shortname2 == null) + return 0; + + return shortname.compareTo(shortname2); + } + + return 0; + } + + /* (non-Javadoc) + * @see serialize.VSSerializable#serialize(serialize.VSSerialize, + * java.io.ObjectOutputStream) + */ + public synchronized void serialize(VSSerialize serialize, + ObjectOutputStream objectOutputStream) + throws IOException { + /** For later backwards compatibility, to add more stuff */ + objectOutputStream.writeObject(Boolean.valueOf(false)); + + objectOutputStream.writeObject(Integer.valueOf(process.getProcessNum())); + + if (event.getClassname() == null) + event.init(process); + + if (VSSerialize.DEBUG) + System.out.println("Serializing: " + event.getClassname()); + + objectOutputStream.writeObject(event.getClassname()); + objectOutputStream.writeObject(Integer.valueOf(event.getID())); + event.serialize(serialize, objectOutputStream); + objectOutputStream.writeObject(Integer.valueOf(taskNum)); + objectOutputStream.writeObject(Long.valueOf(taskTime)); + objectOutputStream.writeObject(Boolean.valueOf(isGlobalTimed)); + objectOutputStream.writeObject(Boolean.valueOf(isProgrammed)); + + /** For later backwards compatibility, to add more stuff */ + objectOutputStream.writeObject(Boolean.valueOf(false)); + } + + /* (non-Javadoc) + * @see serialize.VSSerializable#deserialize(serialize.VSSerialize, + * java.io.ObjectInputStream) + */ + public synchronized void deserialize(VSSerialize serialize, + ObjectInputStream objectInputStream) + throws IOException, ClassNotFoundException { + if (VSSerialize.DEBUG) + System.out.println("Deserializing: VSTask"); + + /** For later backwards compatibility, to add more stuff */ + objectInputStream.readObject(); + + int processNum = ((Integer) objectInputStream.readObject()).intValue(); + VSInternalProcess process = (VSInternalProcess) + serialize.getObject(processNum, "process"); + + String eventClassname = (String) objectInputStream.readObject(); + int eventID = ((Integer) objectInputStream.readObject()).intValue(); + + VSAbstractEvent event = null; + + if (serialize.objectExists(eventID, "event")) { + event = (VSAbstractEvent) serialize.getObject(eventID, "event"); + + } else { + event = VSRegisteredEvents. + createEventInstanceByClassname(eventClassname, process); + + serialize.setObject(eventID, "event", event); + } + + event.deserialize(serialize, objectInputStream); + + int taskNum = ((Integer) objectInputStream.readObject()).intValue(); + long taskTime = ((Long) objectInputStream.readObject()).longValue(); + Boolean isGlobalTimed = (Boolean) objectInputStream.readObject(); + Boolean isProgrammed = (Boolean) objectInputStream.readObject(); + + serialize.setObject(taskNum, "task", this); + init(taskTime, process, event, !isGlobalTimed.booleanValue()); + this.isProgrammed = isProgrammed.booleanValue(); + + /** For later backwards compatibility, to add more stuff */ + objectInputStream.readObject(); + } +} + diff --git a/src/main/java/core/VSTaskManager.java b/src/main/java/core/VSTaskManager.java new file mode 100644 index 0000000..6aa10d0 --- /dev/null +++ b/src/main/java/core/VSTaskManager.java @@ -0,0 +1,562 @@ +package core; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.PriorityQueue; + +import prefs.VSPrefs; +import serialize.VSSerializable; +import serialize.VSSerialize; +import simulator.VSSimulatorVisualization; +import utils.VSPriorityQueue; + +/** + * The class VSTaskManager, it is responsible that all tasks will get + * fullfilled in the correct order. Please also read the javadoc of the VSTask + * class. It describes the difference between local and global timed tasks. + * + * @author Paul C. Buetow + */ +public class VSTaskManager implements VSSerializable { + /** The simulator canvas. */ + private VSSimulatorVisualization simulatorVisualization; + + /** The global tasks. */ + private PriorityQueue<VSTask> globalTasks; + + /** The fullfilled programmed tasks. */ + private LinkedList<VSTask> fullfilledProgrammedTasks; + + /** The Constant PROGRAMMED. */ + public final static boolean PROGRAMMED = true; + + /** The Constant ONLY_ONCE. */ + public final static boolean ONLY_ONCE = false; + + /** The simulator's default prefs. */ + private VSPrefs prefs; + + /** + * Instantiates a new task manager object. + * + * @param prefs the simulator's default prefs + * @param simulatorVisualization the simulator canvas + */ + public VSTaskManager(VSPrefs prefs, + VSSimulatorVisualization simulatorVisualization) { + init(prefs, simulatorVisualization); + } + + /** + * Inits the task manager. + * + * @param prefs the simulator's default prefs + * @param simulatorVisualization the simulator canvas + */ + private void init(VSPrefs prefs, + VSSimulatorVisualization simulatorVisualization) { + this.prefs = prefs; + this.simulatorVisualization = simulatorVisualization; + + /* May be not null if called from deserialization */ + if (globalTasks == null) + this.globalTasks = new PriorityQueue<VSTask>(); + + this.fullfilledProgrammedTasks = new LinkedList<VSTask>(); + } + + /** + * Run tasks. This method gets called by the simulator canvas repeatedly. + * Almost all simulator actions take place in this method. + * + * @param step the step + * @param offset the offset + * @param lastGlobalTime the last global time + */ + public synchronized void runTasks(long step, long offset, + long lastGlobalTime) { + VSTask task = null; + long localTime; + long offsetTime; + long taskTime; + long globalTime; + final long globalOffsetTime = lastGlobalTime + step; + boolean redo; + ArrayList<VSInternalProcess> processes = + simulatorVisualization.getProcesses(); + + do { + redo = false; + + /* Run tasks which have for its schedule the global time */ + while (globalTasks.size() != 0) { + task = globalTasks.peek(); + VSInternalProcess process = task.getProcess(); + localTime = process.getTime(); + offsetTime = localTime + step; + taskTime = task.getTaskTime(); + globalTime = process.getGlobalTime(); + + if (globalOffsetTime < taskTime) + break; + + globalTasks.poll(); + redo = true; + + if (process.isCrashed() && !task.hasProcessRecoverEvent()) { + if (task.isProgrammed()) + fullfilledProgrammedTasks.add(task); + continue; + } + + if (globalOffsetTime == taskTime) { + process.setGlobalTime(globalOffsetTime); + process.setLocalTime(offsetTime); + process.timeModified(false); + task.run(); + process.setGlobalTime(globalTime); + if (process.isCrashed()) + process.addClockOffset(step); + if (process.timeModified()) + process.addClockOffset(process.getTime()-offsetTime); + process.setLocalTime(localTime); + + } else { /* if (globalOffsetTime > taskTime) */ + final long diff = globalOffsetTime - taskTime; + if (globalOffsetTime - diff < lastGlobalTime) + process.setGlobalTime(lastGlobalTime); + else + process.setGlobalTime(globalOffsetTime - diff); + process.setLocalTime(offsetTime - diff); + process.timeModified(false); + task.run(); + process.setGlobalTime(globalTime); + if (process.isCrashed()) + process.addClockOffset(step); + if (process.timeModified()) + process.addClockOffset(process.getTime()- + (offsetTime-diff)); + process.setLocalTime(localTime); + } + + if (task.isProgrammed()) + fullfilledProgrammedTasks.add(task); + } + + synchronized (processes) { + for (VSInternalProcess process : processes) { + PriorityQueue<VSTask> tasks = process.getTasks(); + + /* Run tasks which have for its schedule the local + process times */ + while (tasks.size() != 0) { + task = tasks.peek(); + process = task.getProcess(); + localTime = process.getTime(); + offsetTime = localTime + step; + taskTime = task.getTaskTime(); + globalTime = process.getGlobalTime(); + + if (offsetTime < taskTime) + break; + + tasks.poll(); + redo = true; + + if (process.isCrashed() && + !task.hasProcessRecoverEvent()) { + if (task.isProgrammed()) + fullfilledProgrammedTasks.add(task); + continue; + } + + if (offsetTime == taskTime) { + process.setGlobalTime(globalOffsetTime); + process.setLocalTime(offsetTime); + process.timeModified(false); + task.run(); + process.setGlobalTime(globalTime); + if (process.timeModified()) + process.addClockOffset(process.getTime()- + offsetTime); + process.setLocalTime(localTime); + + } else { /* if (offsetTime > taskTime) */ + final long diff = offsetTime - taskTime; + if (globalOffsetTime - diff < lastGlobalTime) + process.setGlobalTime(lastGlobalTime); + else + process.setGlobalTime(globalOffsetTime- + diff); + process.setLocalTime(offsetTime - diff); + process.timeModified(false); + task.run(); + process.setGlobalTime(globalTime); + if (process.timeModified()) + process.addClockOffset(process.getTime()- + (offsetTime-diff)); + process.setLocalTime(localTime); + } + + if (task.isProgrammed()) + fullfilledProgrammedTasks.add(task); + } + } + } + + } while (redo); + } + + /** + * Resets the task manager. + */ + public synchronized void reset() { + ArrayList<VSInternalProcess> processes = + simulatorVisualization.getProcesses(); + PriorityQueue<VSTask> tmp = null; + + synchronized (processes) { + for (VSInternalProcess process : processes) { + tmp = process.getTasks(); + process.setTasks(new VSPriorityQueue<VSTask>()); + + for (VSTask task : tmp) { + if (task.isProgrammed()) + insert(task); + } + } + } + + tmp = globalTasks; + globalTasks = new PriorityQueue<VSTask>(); + + while (fullfilledProgrammedTasks.size() != 0) + insert(fullfilledProgrammedTasks.removeFirst()); + + while (tmp.size() != 0) { + VSTask task = tmp.poll(); + if (task.isProgrammed()) + insert(task); + } + } + + /** + * Inserts a task. Only for internal usage. Use the add methods instead. + * This method checks if the task to insert is a global or a local timed + * task. And it also checks if the task's time is over already. + * + * @param task the task to insert + */ + private synchronized void insert(VSTask task) { + if (task.timeOver()) { + if (task.isProgrammed()) + fullfilledProgrammedTasks.addLast(task); + + } else if (task.isGlobalTimed()) { + globalTasks.add(task); + + } else { + task.getProcess().getTasks().add(task); + } + } + + /** + * Adds a task. + * + * @param task the task to add + */ + public synchronized void addTask(VSTask task) { + addTask(task, VSTaskManager.ONLY_ONCE); + } + + /** + * Adds a task. + * + * @param task the task to add + * @param isProgrammed true, if the task is programmed + */ + public synchronized void addTask(VSTask task, boolean isProgrammed) { + task.isProgrammed(isProgrammed); + insert(task); + } + + /** + * Removes a task. + * + * @param task the task to remove + * + * @return true, if the task has been removed with success + */ + public synchronized boolean removeTask(VSTask task) { + if (fullfilledProgrammedTasks.remove(task)) { + return true; + + } else if (task.isGlobalTimed() && globalTasks.remove(task)) { + return true; + + } else if (!task.isGlobalTimed()) { + if (task.getProcess().getTasks().remove(task)) + return true; + } + + return false; + } + + /** + * Removes several tasks. + * + * @param tasks the tasks to remove + */ + public synchronized void removeAllTasks(ArrayList<VSTask> tasks) { + for (VSTask task : tasks) + removeTask(task); + } + + /** + * Removes the tasks of the specified process. + * + * @param process the process to remove the tasks of + */ + public synchronized void removeTasksOf(VSInternalProcess process) { + ArrayList<VSTask> removeThose = new ArrayList<VSTask>(); + + for (VSTask task : fullfilledProgrammedTasks) + if (task.isProcess(process)) + removeThose.add(task); + + for (VSTask task : removeThose) + fullfilledProgrammedTasks.remove(task); + + removeThose.clear(); + + for (VSTask task : globalTasks) + if (task.isProcess(process)) + removeThose.add(task); + + for (VSTask task : removeThose) + globalTasks.remove(task); + + process.getTasks().clear(); + } + + /** + * Gets the local timed tasks. + * + * @return the local timed tasks + */ + public synchronized ArrayList<VSTask> getLocalTasks() { + ArrayList<VSTask> localTasks = new ArrayList<VSTask>(); + ArrayList<VSInternalProcess> processes = + simulatorVisualization.getProcesses(); + + for (VSTask task : fullfilledProgrammedTasks) + if (!task.isGlobalTimed()) + localTasks.add(task); + + synchronized (processes) { + for (VSInternalProcess process : processes) { + VSPriorityQueue<VSTask> tasks = process.getTasks(); + for (VSTask task : tasks) + localTasks.add(task); + } + } + + return localTasks; + } + + /** + * Gets the global timed tasks. + * + * @return the global timed tasks + */ + public synchronized ArrayList<VSTask> getGlobalTasks() { + ArrayList<VSTask> globalTasks = new ArrayList<VSTask>(); + + for (VSTask task : fullfilledProgrammedTasks) + if (task.isGlobalTimed()) + globalTasks.add(task); + + for (VSTask task : this.globalTasks) + if (task.isProgrammed()) + globalTasks.add(task); + + return globalTasks; + } + + /** + * Gets the local timed tasks of a specific process. + * + * @param process the process to get the local timed tasks of + * + * @return the local tasks of the specified process + */ + public synchronized ArrayList<VSTask> getProcessLocalTasks( + VSInternalProcess process) { + ArrayList<VSTask> processTasks = new ArrayList<VSTask>(); + VSPriorityQueue<VSTask> tasks = process.getTasks(); + + for (VSTask task : fullfilledProgrammedTasks) + if (!task.isGlobalTimed() && task.isProcess(process) && + task.isProgrammed()) + processTasks.add(task); + + for (VSTask task : tasks) + if (task.isProgrammed()) + processTasks.add(task); + + return processTasks; + } + + /** + * Gets the global timed tasks of a specific process. + * + * @param process the process to get the local timed tasks of + * + * @return the global timed tasks of the specified process + */ + public synchronized ArrayList<VSTask> getProcessGlobalTasks( + VSInternalProcess process) { + ArrayList<VSTask> processTasks = new ArrayList<VSTask>(); + + for (VSTask task : fullfilledProgrammedTasks) + if (task.isGlobalTimed() && task.isProcess(process) && + task.isProgrammed()) + processTasks.add(task); + + for (VSTask task : globalTasks) + if (task.isProcess(process) && task.isProgrammed()) + processTasks.add(task); + + return processTasks; + } + + /* (non-Javadoc) + * @see java.lang.Object#toString() + */ + public synchronized String toString() { + StringBuffer buffer = new StringBuffer(); + + buffer.append(prefs.getString("lang.task.manager")); + buffer.append(" ("); + buffer.append(prefs.getString("lang.tasks.fullfilled")); + buffer.append(": "); + + for (VSTask task : fullfilledProgrammedTasks) { + buffer.append(task); + buffer.append("; "); + } + + buffer.append(prefs.getString("lang.tasks.global")); + buffer.append(": "); + + for (VSTask task : globalTasks) { + buffer.append(task); + buffer.append("; "); + } + + buffer.append(prefs.getString("lang.tasks.local")); + buffer.append(": "); + + ArrayList<VSInternalProcess> processes = + simulatorVisualization.getProcesses(); + synchronized (processes) { + for (VSInternalProcess process : processes) { + VSPriorityQueue<VSTask> tasks = process.getTasks(); + for (VSTask task : tasks) { + buffer.append(task); + buffer.append("; "); + } + } + } + + String descr = buffer.toString(); + + if (descr.endsWith("; ")) + return descr.substring(0, descr.length()-2) + ")"; + + return descr + ")"; + } + + /* (non-Javadoc) + * @see serialize.VSSerializable#serialize(serialize.VSSerialize, + * java.io.ObjectOutputStream) + */ + public synchronized void serialize(VSSerialize serialize, + ObjectOutputStream objectOutputStream) + throws IOException { + /** For later backwards compatibility, to add more stuff */ + objectOutputStream.writeObject(Boolean.valueOf(false)); + + ArrayList<VSTask> serializeThoseTasks = new ArrayList<VSTask>(); + + for (VSTask task : fullfilledProgrammedTasks) { + if (!task.hasNotSerializableEvent()) + serializeThoseTasks.add(task); + } + + for (VSTask task : globalTasks) { + if (!task.hasNotSerializableEvent()) + serializeThoseTasks.add(task); + } + + ArrayList<VSInternalProcess> processes = + simulatorVisualization.getProcesses(); + + synchronized (processes) { + for (VSInternalProcess process : processes) { + VSPriorityQueue<VSTask> localTasks = process.getTasks(); + for (VSTask task : localTasks) { + if (!task.hasNotSerializableEvent()) + serializeThoseTasks.add(task); + } + } + } + + objectOutputStream.writeObject( + Integer.valueOf(serializeThoseTasks.size())); + for (VSTask task : serializeThoseTasks) + task.serialize(serialize, objectOutputStream); + + /** For later backwards compatibility, to add more stuff */ + objectOutputStream.writeObject(Boolean.valueOf(false)); + } + + /* (non-Javadoc) + * @see serialize.VSSerializable#deserialize(serialize.VSSerialize, + * java.io.ObjectInputStream) + */ + public synchronized void deserialize(VSSerialize serialize, + ObjectInputStream objectInputStream) + throws IOException, ClassNotFoundException { + if (VSSerialize.DEBUG) + System.out.println("Deserializing: VSTaskManager"); + + /** For later backwards compatibility, to add more stuff */ + objectInputStream.readObject(); + + globalTasks.clear(); + + ArrayList<VSInternalProcess> processes = + simulatorVisualization.getProcesses(); + synchronized (processes) { + for (VSInternalProcess process : processes) + process.getTasks().clear(); + } + + int numTasks = ((Integer) objectInputStream.readObject()).intValue(); + + if (VSSerialize.DEBUG) + System.out.println("Num of tasks: " + numTasks); + + for (int i = 0; i < numTasks; ++i) { + VSTask task = new VSTask(serialize, objectInputStream); + addTask(task, task.isProgrammed()); + } + + /** For later backwards compatibility, to add more stuff */ + objectInputStream.readObject(); + } +} diff --git a/src/main/java/core/time/VSLamportTime.java b/src/main/java/core/time/VSLamportTime.java new file mode 100644 index 0000000..be1226b --- /dev/null +++ b/src/main/java/core/time/VSLamportTime.java @@ -0,0 +1,50 @@ +package core.time; + +/** + * The class VSLamportTime, defines how the lamport timestamps are represented. + * + * @author Paul C. Buetow + */ +public class VSLamportTime implements VSTime { + /** Specified the global time of the lamport timestamp. It's used for + * correct painting position in the simulator canvas paint area. + */ + private long globalTime; + + /** Specified the process' local lamport time. */ + private long lamportTime; + + /** + * A simple constructor. + * + * @param globalTime The global time. + * @param lamportTime The local lamport time. + */ + public VSLamportTime(long globalTime, long lamportTime) { + this.globalTime = globalTime; + this.lamportTime = lamportTime; + } + + /* (non-Javadoc) + * @see core.time.VSTime#getGlobalTime() + */ + public long getGlobalTime() { + return globalTime; + } + + /** + * Gets the lamport time. + * + * @return The process' local lamport time + */ + public long getLamportTime() { + return lamportTime; + } + + /* (non-Javadoc) + * @see core.time.VSTime#toString() + */ + public String toString() { + return "(" + lamportTime + ")"; + } +} diff --git a/src/main/java/core/time/VSTime.java b/src/main/java/core/time/VSTime.java new file mode 100644 index 0000000..d46e0e4 --- /dev/null +++ b/src/main/java/core/time/VSTime.java @@ -0,0 +1,22 @@ +package core.time; + +/** + * This interface is a guidline for general time format classes. + * + * @author Paul C. Buetow + */ +public interface VSTime { + /** + * Gets the global time. + * + * @return The global time + */ + public long getGlobalTime(); + + /** + * Returns a string representation. + * + * @return The representation of the implementing object as a string + */ + public String toString(); +} diff --git a/src/main/java/core/time/VSVectorTime.java b/src/main/java/core/time/VSVectorTime.java new file mode 100644 index 0000000..4e63b3c --- /dev/null +++ b/src/main/java/core/time/VSVectorTime.java @@ -0,0 +1,96 @@ +package core.time; + +import java.util.ArrayList; + +/** + * The class VSVectorTime, defined how the vector timestamps are represented. + * + * @author Paul C. Buetow + */ +public class VSVectorTime extends ArrayList<Long> implements VSTime { + /** The serial version uid */ + private static final long serialVersionUID = 1L; + + /** The global time. */ + private long globalTime; + + /** + * Instantiates a new vector time. + * + * @param globalTime the global time + */ + public VSVectorTime(long globalTime) { + this.globalTime = globalTime; + } + + /** + * To long array. + * + * @return the long[] + */ + public long[] toLongArray() { + final int size = super.size(); + final long[] arr = new long[size]; + + for (int i = 0; i < size; ++i) + arr[i] = super.get(i).longValue(); + + return arr; + } + + /** + * Sets the global time. + * + * @param globalTime the new global time + */ + public void setGlobalTime(long globalTime) { + this.globalTime = globalTime; + } + + /* (non-Javadoc) + * @see core.time.VSTime#getGlobalTime() + */ + public long getGlobalTime() { + return globalTime; + } + + /** + * Gets the copy. + * + * @return the copy + */ + public VSVectorTime getCopy() { + final VSVectorTime vectorTime = new VSVectorTime(globalTime); + final int size = super.size(); + + for (int i = 0; i < size; ++i) + vectorTime.add(super.get(i)); + + return vectorTime; + } + + /* (non-Javadoc) + * @see java.util.AbstractCollection#toString() + */ + public String toString() { + final int size = super.size(); + final StringBuffer buffer = new StringBuffer(); + buffer.append("("); + + for (int i = 0; i < size-1; ++i) + buffer.append(super.get(i)+","); + buffer.append(super.get(size-1)+")"); + + return buffer.toString(); + } + + /* (non-Javadoc) + * @see java.util.ArrayList#get(int) + */ + public Long get(int index) { + if (index >= super.size()) + return Long.valueOf(0); + + return super.get(index); + } +} |
