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 | |
| parent | 4d35597bd92607c4d194686e20b125044506c79a (diff) | |
Modernize project structure, update Maven config, move sources, add logging config, update README and .gitignore
Diffstat (limited to 'src/main')
63 files changed, 14416 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); + } +} diff --git a/src/main/java/events/VSAbstractEvent.java b/src/main/java/events/VSAbstractEvent.java new file mode 100644 index 0000000..52c2423 --- /dev/null +++ b/src/main/java/events/VSAbstractEvent.java @@ -0,0 +1,243 @@ +package events; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; + +import core.VSAbstractProcess; +import core.VSInternalProcess; +import exceptions.VSEventNotCopyableException; +import prefs.VSPrefs; +import prefs.VSSerializablePrefs; +import serialize.VSSerialize; + +/** + * The class VSAbstractEvent. This abstract class defines the basic framework + * of each event. an event is used to fullfill a specific task. An event object + * will get stored in a VSTask object. + * + * @author Paul C. Buetow + */ +abstract public class VSAbstractEvent extends VSSerializablePrefs { + /** The prefs. */ + public VSPrefs prefs; + + /** The process. */ + public VSAbstractProcess process; + + /** The event shortname. */ + private String eventShortname; + + /** The event classname. */ + private String eventClassname; + + /** + * Creates a copy of the event and using a new process. + * + * @param theProcess The new process + * @return The copy + */ + final public VSAbstractEvent getCopy(VSInternalProcess theProcess) + throws VSEventNotCopyableException { + + if (theProcess == null) + theProcess = (VSInternalProcess) process; + + if (!(this instanceof VSCopyableEvent)) + throw new VSEventNotCopyableException( + eventShortname + " (" + eventClassname + ")"); + + VSAbstractEvent copy = + VSRegisteredEvents.createEventInstanceByClassname( + eventClassname, theProcess); + + ((VSCopyableEvent) this).initCopy(copy); + copy.setShortname(eventShortname); + + return copy; + } + + /** + * Creates a copy of the event. + * + * @return The copy + */ + final public VSAbstractEvent getCopy() throws VSEventNotCopyableException { + return getCopy(null); + } + + /** + * Inits the event. + * + * @param process the process + */ + public void init(VSInternalProcess process) { + if (this.process == null) { + this.process = process; + this.prefs = process.getPrefs(); + init(); + } + } + + /** + * Inits the event without setting the processes and prefs variables + * of the object. + */ + public void init() { + onInit(); + } + + /** + * Sets the classname. + * + * @param eventClassname the new classname + */ + public final void setClassname(String eventClassname) { + if (eventClassname.startsWith("class ")) + eventClassname = eventClassname.substring(6); + + this.eventClassname = eventClassname; + } + + /** + * Gets the classname. + * + * @return the classname + */ + public String getClassname() { + return eventClassname; + } + + /** + * Gets the name. + * + * @return the name + */ + public String getName() { + return VSRegisteredEvents.getNameByClassname(eventClassname); + } + + /** + * Sets the shortname. + * + * @param eventShortname the new shortname + */ + public void setShortname(String eventShortname) { + this.eventShortname = eventShortname; + } + + /** + * Gets the shortname. + * + * @return the shortname + */ + public String getShortname() { + if (eventShortname == null) + return VSRegisteredEvents.getShortnameByClassname(eventClassname); + + return eventShortname; + } + + /** + * Gets the process. + * + * @return the process + */ + public VSAbstractProcess getProcess() { + return process; + } + + /** + * Logg a specific message. + * + * @param message the loging message + */ + public void log(String message) { + process.log(/*toString() + "; " + */message); + } + + /** + * Checks if the event equals to another event.. + * + * @param event the event to compare against. + * + * @return true, if the events are the same (have the same event id) + */ + public boolean equals(VSAbstractEvent event) { + return super.getID() == event.getID(); + } + + /** + * Every event has its own initialize method. + */ + abstract public void onInit(); + + /** + * Every event can get started. This method get's executed if the event + * takes place. + */ + abstract public void onStart(); + + /** + * Every event has to be able to set its own shortname + * + * @param shortName The saved short name. May be overwritten due wrong lang + * + * @return The event's shortname + */ + abstract protected String createShortname(String savedShortname); + + /* (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: VSAbstractEvent; id="+getID()); + + /** For later backwards compatibility, to add more stuff */ + objectOutputStream.writeObject(Boolean.valueOf(false)); + + objectOutputStream.writeObject(Integer.valueOf(super.getID())); + objectOutputStream.writeObject(eventShortname); + objectOutputStream.writeObject(eventClassname); + + /** 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); + + if (VSSerialize.DEBUG) + System.out.print("Deserializing: VSAbstractEvent "); + + /** For later backwards compatibility, to add more stuff */ + objectInputStream.readObject(); + + int id = ((Integer) objectInputStream.readObject()).intValue(); + String savedEventShortname = (String) objectInputStream.readObject(); + this.eventClassname = (String) objectInputStream.readObject(); + this.eventShortname = createShortname(savedEventShortname); + + if (VSSerialize.DEBUG) { + System.out.println("eventClassname: " + eventClassname); + System.out.println("eventShortname: " + eventShortname); + } + + serialize.setObject(id, "event", this); + + /** For later backwards compatibility, to add more stuff */ + objectInputStream.readObject(); + } +} diff --git a/src/main/java/events/VSCopyableEvent.java b/src/main/java/events/VSCopyableEvent.java new file mode 100644 index 0000000..23125ce --- /dev/null +++ b/src/main/java/events/VSCopyableEvent.java @@ -0,0 +1,16 @@ +package events; + +/** + * The interface VSCopyableEvent, all events which implement this class + * are copyable. + * + * @author Paul C. Buetow + */ +public interface VSCopyableEvent { + /** + * Fills a copy of this event with its values + * + * @param copy The copy + */ + public void initCopy(VSAbstractEvent copy); +} diff --git a/src/main/java/events/VSRegisteredEvents.java b/src/main/java/events/VSRegisteredEvents.java new file mode 100644 index 0000000..6d50ae5 --- /dev/null +++ b/src/main/java/events/VSRegisteredEvents.java @@ -0,0 +1,346 @@ +package events; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.Set; +import java.util.Vector; + +import core.VSInternalProcess; +import prefs.VSPrefs; +import utils.VSClassLoader; + +/** + * The class VSRegisteredEvents. This class is responsible to manage all + * events. It manages the event classnames, the event shortnames and the event + * names. It also checks if a protocol (which is an event as well) has + * variables which are editable through the GUI of the simulator. + * + * @author Paul C. Buetow + */ +public final class VSRegisteredEvents { + /** The event classnames by eventnames. */ + private static HashMap<String,String> eventClassnamesByNames = + new HashMap<String,String>(); + + /** The event shortnames by classnames. */ + private static HashMap<String,String> eventShortnamesByClassnames = + new HashMap<String,String>(); + + /** The event names by classnames. */ + private static HashMap<String,String> eventNamesByClassnames = + new HashMap<String,String>(); + + /** The event classnames by shortnames. */ + private static HashMap<String,String> eventClassnamesByShortnames = + new HashMap<String,String>(); + + /** The editable protocols classnames. */ + private static ArrayList<String> editableProtocolsClassnames = + new ArrayList<String>(); + + private static HashMap<String,ArrayList<String>> clientVariables = + new HashMap<String,ArrayList<String>>(); + + private static HashMap<String,ArrayList<String>> serverVariables = + new HashMap<String,ArrayList<String>>(); + + private static HashMap<String,Boolean> isOnServerStartProtocol = + new HashMap<String,Boolean>(); + + /** The prefs. */ + private static VSPrefs prefs; + + /** + * Registers available events. + * + * @param prefs_ the prefs_ + */ + public static void init(VSPrefs prefs_) { + prefs = prefs_; + registerEvent("events.implementations.VSProcessCrashEvent"); + registerEvent("events.implementations.VSProcessRecoverEvent"); + registerEvent("protocols.implementations.VSBasicMulticastProtocol"); + registerEvent("protocols.implementations.VSBerkelyTimeProtocol"); + registerEvent("protocols.implementations.VSBroadcastProtocol"); + registerEvent("protocols.implementations.VSDummyProtocol"); + registerEvent("protocols.implementations.VSExternalTimeSyncProtocol"); + registerEvent("protocols.implementations.VSInternalTimeSyncProtocol"); + registerEvent("protocols.implementations.VSOnePhaseCommitProtocol"); + registerEvent("protocols.implementations.VSPingPongProtocol"); + registerEvent("protocols.implementations.VSReliableMulticastProtocol"); + registerEvent("protocols.implementations.VSTwoPhaseCommitProtocol"); + + /* Make dummy objects of each protocol, to see if they contain VSPrefs + values to edit */ + Vector<String> protocolClassnames = getProtocolClassnames(); + VSClassLoader classLoader = new VSClassLoader(); + + for (String protocolClassname : protocolClassnames) { + Object serverObject = classLoader.newInstance(protocolClassname); + Object clientObject = classLoader.newInstance(protocolClassname); + + if (clientObject instanceof protocols.VSAbstractProtocol && + serverObject instanceof protocols.VSAbstractProtocol) { + + protocols.VSAbstractProtocol serverProtocol = + (protocols.VSAbstractProtocol) serverObject; + protocols.VSAbstractProtocol clientProtocol = + (protocols.VSAbstractProtocol) clientObject; + + serverProtocol.onServerInit(); + clientProtocol.onClientInit(); + + if (!serverProtocol.isEmpty() || !clientProtocol.isEmpty()) + editableProtocolsClassnames.add(protocolClassname); + + if (!serverProtocol.isEmpty()) { + ArrayList<String> variables = new ArrayList<String>(); + variables.addAll(serverProtocol.getAllFullKeys()); + serverVariables.put(protocolClassname, variables); + } + + if (!clientProtocol.isEmpty()) { + ArrayList<String> variables = new ArrayList<String>(); + variables.addAll(clientProtocol.getAllFullKeys()); + clientVariables.put(protocolClassname, variables); + } + + if (serverProtocol.hasOnServerStart()) + isOnServerStartProtocol.put(protocolClassname, + Boolean.valueOf(true)); + } + } + } + + /** + * Gets the editable protocols classnames. + * + * @return the editable protocols classnames + */ + public static ArrayList<String> getEditableProtocolsClassnames() { + return editableProtocolsClassnames; + } + + /** + * Gets the protocols server variable names. + * + * @return The variable names + */ + public static ArrayList<String> getProtocolServerVariables( + String protocolClassname) { + return serverVariables.get(protocolClassname); + } + + /** + * Gets the protocols server variable names. + * + * @return The variable names + */ + public static ArrayList<String> getProtocolClientVariables( + String protocolClassname) { + return clientVariables.get(protocolClassname); + } + + /** + * Gets the protocol names. + * + * @return the protocol names + */ + public static Vector<String> getProtocolNames() { + Set<String> set = eventClassnamesByNames.keySet(); + Vector<String> vector = new Vector<String>(); + + for (String eventName : set) + if (getClassnameByEventname(eventName).startsWith( + "protocols.implementations")) + vector.add(eventName); + + Collections.sort(vector); + + return vector; + } + + /** + * Gets the protocol classnames. + * + * @return the protocol classnames + */ + public static Vector<String> getProtocolClassnames() { + ArrayList<String> shortnames = new ArrayList<String>(); + shortnames.addAll(eventClassnamesByShortnames.keySet()); + Collections.sort(shortnames); + Vector<String> vector = new Vector<String>(); + + for (String eventShortname : shortnames) { + String eventClassname = getClassnameByShortname(eventShortname); + if (eventClassname.startsWith("protocols.implementations")) + vector.add(eventClassname); + } + + return vector; + } + + /** + * Gets the non protocol names. + * + * @return the non protocol names + */ + public static Vector<String> getNonProtocolNames() { + Set<String> set = eventClassnamesByNames.keySet(); + Vector<String> vector = new Vector<String>(); + + for (String eventName : set) + if (getClassnameByEventname(eventName).startsWith( + "events.implementations")) + vector.add(eventName); + + Collections.sort(vector); + + return vector; + } + + /** + * Gets the non protocol classnames. + * + * @return the non protocol classnames + */ + public static Vector<String> getNonProtocolClassnames() { + Set<String> set = eventNamesByClassnames.keySet(); + Vector<String> vector = new Vector<String>(); + + for (String eventClassname : set) + if (eventClassname.startsWith("events.implementations")) + vector.add(eventClassname); + + Collections.sort(vector); + + return vector; + } + + /** + * Gets the classname. + * + * @param eventName the event name + * + * @return the classname + */ + public static String getClassnameByEventname(String eventName) { + return eventClassnamesByNames.get(eventName); + } + + /** + * Gets the name. + * + * @param eventClassname the event classname + * + * @return the name + */ + public static String getNameByClassname(String eventClassname) { + return eventNamesByClassnames.get(eventClassname); + } + + /** + * Gets the shortname. + * + * @param eventClassname the event classname + * + * @return the shortname + */ + public static String getShortnameByClassname(String eventClassname) { + return eventShortnamesByClassnames.get(eventClassname); + } + + /** + * Gets the classname. + * + * @param eventShortname the event shortname + * + * @return the shortname + */ + public static String getClassnameByShortname(String eventShortname) { + return eventClassnamesByShortnames.get(eventShortname); + } + + /** + * Checks if the protocol uses onServerStart or onClientStart + * + * @param protocolClassname the protocol's classname + * + * @return true if onServerStart, false if onClientStart + */ + public static boolean isOnServerStartProtocol(String protocolClassname) { + if (isOnServerStartProtocol.containsKey(protocolClassname)) { + Boolean bool = isOnServerStartProtocol.get(protocolClassname); + return bool.booleanValue(); + } + + return false; + } + + /** + * Creates the event instance by classname. + * + * @param eventClassname the event classname + * @param process the process + * + * @return An instance of the event classname, if exists. Else null. + */ + public static VSAbstractEvent createEventInstanceByClassname( + String eventClassname, VSInternalProcess process) { + Object protocolObj = new VSClassLoader().newInstance(eventClassname); + + if (protocolObj instanceof VSAbstractEvent) { + VSAbstractEvent event = (VSAbstractEvent) protocolObj; + event.init(process); + return event; + } + + return null; + } + + /** + * Creates the event instance by name. + * + * @param eventName the event name + * @param process the process + * + * @return An instance of the event, if exists. Else null. + */ + public static VSAbstractEvent createEventInstanceByName(String eventName, + VSInternalProcess process) { + return createEventInstanceByClassname( + eventClassnamesByNames.get(eventName), process); + } + + /** + * Registers an event. Use the language settings of VSPrefs. + * + * @param eventClassname the event classname + */ + private static void registerEvent(String eventClassname) { + String eventName = + prefs.getString("lang." + eventClassname); + String eventShortname = + prefs.getString("lang." + eventClassname + ".short"); + registerEvent(eventClassname, eventName, eventShortname); + } + + /** + * Registers an event. + * + * @param eventClassname the event classname + * @param eventName the event name + * @param eventShortname the event shortname + */ + private static void registerEvent(String eventClassname, String eventName, + String eventShortname) { + if (eventShortname == null) + eventShortname = eventName; + + eventNamesByClassnames.put(eventClassname, eventName); + eventShortnamesByClassnames.put(eventClassname, eventShortname); + eventClassnamesByNames.put(eventName, eventClassname); + eventClassnamesByShortnames.put(eventShortname, eventClassname); + } +} diff --git a/src/main/java/events/implementations/VSProcessCrashEvent.java b/src/main/java/events/implementations/VSProcessCrashEvent.java new file mode 100644 index 0000000..a68e8a1 --- /dev/null +++ b/src/main/java/events/implementations/VSProcessCrashEvent.java @@ -0,0 +1,43 @@ +package events.implementations; + +import events.VSAbstractEvent; +import events.VSCopyableEvent; +import simulator.VSMain; + +/** + * The class VSProcessCrashEvent. This event makes a process to crash. + * + * @author Paul C. Buetow + */ +public class VSProcessCrashEvent extends VSAbstractEvent + implements VSCopyableEvent { + /* (non-Javadoc) + * @see events.VSCopyableEvent#initCopy(events.VSAbstractEvent) + */ + public void initCopy(VSAbstractEvent copy) { + } + + /* (non-Javadoc) + * @see events.VSAbstractEvent#onInit() + */ + public void onInit() { + setClassname(getClass().toString()); + } + + /* (non-Javadoc) + * @see events.VSAbstractEvent#createShortname()() + */ + protected String createShortname(String savedShortname) { + return VSMain.prefs.getString("lang.process.crash"); + } + + /* (non-Javadoc) + * @see events.VSAbstractEvent#onStart() + */ + public void onStart() { + if (!process.isCrashed()) { + process.isCrashed(true); + log(prefs.getString("lang.crashed")); + } + } +} diff --git a/src/main/java/events/implementations/VSProcessRecoverEvent.java b/src/main/java/events/implementations/VSProcessRecoverEvent.java new file mode 100644 index 0000000..2aa5758 --- /dev/null +++ b/src/main/java/events/implementations/VSProcessRecoverEvent.java @@ -0,0 +1,44 @@ +package events.implementations; + +import events.VSAbstractEvent; +import events.VSCopyableEvent; +import simulator.VSMain; + +/** + * The class VSProcessRecoverEvent. This event makes a process to recover if + * it is crashed. + * + * @author Paul C. Buetow + */ +public class VSProcessRecoverEvent extends VSAbstractEvent + implements VSCopyableEvent { + /* (non-Javadoc) + * @see events.VSCopyableEvent#initCopy(events.VSAbstractEvent) + */ + public void initCopy(VSAbstractEvent copy) { + } + + /* (non-Javadoc) + * @see events.VSAbstractEvent#onInit() + */ + public void onInit() { + setClassname(getClass().toString()); + } + + /* (non-Javadoc) + * @see events.VSAbstractEvent#createShortname()() + */ + protected String createShortname(String savedShortname) { + return VSMain.prefs.getString("lang.process.recover"); + } + + /* (non-Javadoc) + * @see events.VSAbstractEvent#onStart() + */ + public void onStart() { + if (process.isCrashed()) { + process.isCrashed(false); + log(prefs.getString("lang.recovered")); + } + } +} diff --git a/src/main/java/events/internal/VSAbstractInternalEvent.java b/src/main/java/events/internal/VSAbstractInternalEvent.java new file mode 100644 index 0000000..33e3763 --- /dev/null +++ b/src/main/java/events/internal/VSAbstractInternalEvent.java @@ -0,0 +1,58 @@ +package events.internal; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; + +import events.VSAbstractEvent; +import serialize.VSSerialize; + +/** + * The class VSAbstractInternalEvent, this class if for destinguishing between + * internal and non-internal events. Internal usage only. + * + * @author Paul C. Buetow + */ +abstract public class VSAbstractInternalEvent extends VSAbstractEvent { + /* (non-Javadoc) + * @see events.VSAbstractEvent#createShortname()() + */ + protected String createShortname(String savedShortname) { + return savedShortname; + } + + /* (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); + + /** For later backwards compatibility, to add more stuff */ + objectOutputStream.writeObject(Boolean.valueOf(false)); + + /** 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); + + if (VSSerialize.DEBUG) + System.out.println("Deserializing: VSAbstractInternalEvent"); + + /** For later backwards compatibility, to add more stuff */ + objectInputStream.readObject(); + + /** For later backwards compatibility, to add more stuff */ + objectInputStream.readObject(); + } +} diff --git a/src/main/java/events/internal/VSMessageReceiveEvent.java b/src/main/java/events/internal/VSMessageReceiveEvent.java new file mode 100644 index 0000000..51ae926 --- /dev/null +++ b/src/main/java/events/internal/VSMessageReceiveEvent.java @@ -0,0 +1,84 @@ +package events.internal; + +import core.VSMessage; +import protocols.VSAbstractProtocol; +import serialize.VSNotSerializable; + +/** + * The class VSMessageReceiveEvent, this event is used if a process receives + * a message. + * + * @author Paul C. Buetow + */ +public class VSMessageReceiveEvent extends VSAbstractInternalEvent + implements VSNotSerializable { + + /** The message. */ + private VSMessage message; + + /** + * Instantiates a new message receive event. + * + * @param message the message + */ + public VSMessageReceiveEvent(VSMessage message) { + this.message = message; + } + + /* (non-Javadoc) + * @see events.VSAbstractEvent#onInit() + */ + public void onInit() { + setClassname(getClass().toString()); + } + + /* (non-Javadoc) + * @see events.VSAbstractEvent#onStart() + */ + public void onStart() { + boolean onlyRelevantMessages = process.getPrefs().getBoolean("sim.messages.relevant"); + + //String eventName = message.getName(); + String protocolClassname = message.getProtocolClassname(); + + if (onlyRelevantMessages && !isRelevantMessage()) + return; + + Object protocolObj = null; + + if (process.objectExists(protocolClassname)) + protocolObj = process.getObject(protocolClassname); + + process.updateLamportTime(message.getLamportTime()+1); + process.updateVectorTime(message.getVectorTime()); + + StringBuffer buffer = new StringBuffer(); + buffer.append(prefs.getString("lang.message.recv")); + buffer.append("; "); + buffer.append(message);; + log(buffer.toString()); + + if (protocolObj != null) + ((VSAbstractProtocol) protocolObj).onMessageRecvStart(message); + } + + /** + * Checks if the message delivering is relevant. + * + * @return true, if relevant + */ + public boolean isRelevantMessage() { + String protocolClassname = message.getProtocolClassname(); + Object protocolObj = null; + + if (process.objectExists(protocolClassname)) + protocolObj = process.getObject(protocolClassname); + else + return false; + + if (!((VSAbstractProtocol) protocolObj).isRelevantMessage(message)) + return false; + + return true; + } +} diff --git a/src/main/java/events/internal/VSProtocolEvent.java b/src/main/java/events/internal/VSProtocolEvent.java new file mode 100644 index 0000000..de630e3 --- /dev/null +++ b/src/main/java/events/internal/VSProtocolEvent.java @@ -0,0 +1,175 @@ +package events.internal; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; + +import core.VSInternalProcess; +import events.VSAbstractEvent; +import events.VSCopyableEvent; +import events.VSRegisteredEvents; +import protocols.VSAbstractProtocol; +import serialize.VSSerialize; + +/** + * The class VSProtocolEvent, this event is used if a protocol (server or + * client part) of a process gets enabled or disabled, an object of this class + * can be for 4 different purporses! Activation of the client protocol, + * deactivation of the client protocol, activation of the server protocol, + * deactivation of the server protocol. + * + * @author Paul C. Buetow + */ +public class VSProtocolEvent extends VSAbstractInternalEvent + implements VSCopyableEvent { + /** The protocol classname. */ + private String protocolClassname; + + /** The event is a client protocol if true. Else it is a server protocol */ + private boolean isClientProtocol; + + /** The event is a protocol activation if true. Else it is a deactivation */ + private boolean isProtocolActivation; + + /* (non-Javadoc) + * @see events.VSCopyableEvent#initCopy(events.VSAbstractEvent) + */ + public void initCopy(VSAbstractEvent copy) { + VSProtocolEvent protocolEventCopy = (VSProtocolEvent) copy; + protocolEventCopy.isClientProtocol(isClientProtocol); + protocolEventCopy.isProtocolActivation(isProtocolActivation); + protocolEventCopy.setProtocolClassname(protocolClassname); + } + + /* (non-Javadoc) + * @see events.VSAbstractEvent#onInit() + */ + public void onInit() { + setClassname(getClass().toString()); + } + + /** + * Sets if it is a client protocol activation/deactivation. + * + * @param isClientProtocol the event is client protocol if true. the event + * is a server protocol if false. + */ + public void isClientProtocol(boolean isClientProtocol) { + this.isClientProtocol = isClientProtocol; + } + + /** + * Checks if it is a client protocol activation/deactivation. + * + * @return the event is client protocol if true. the event + * is a server protocol if false. + */ + public boolean isClientProtocol() { + return isClientProtocol; + } + + /** + * Sets if it is protocol activation. + * + * @param isProtocolActivation true, if it is a protocol activation. false, + * if it is a protocol deactivation. + */ + public void isProtocolActivation(boolean isProtocolActivation) { + this.isProtocolActivation = isProtocolActivation; + } + + /** + * Checks if it is protocol activation. + * + * @return true, if it is a protocol activation. false, if it is a protocol + * deactivation. + */ + public boolean isProtocolActivation() { + return isProtocolActivation; + } + + /** + * Sets the protocol classname. + * + * @param protocolClassname the new protocol classname + */ + public void setProtocolClassname(String protocolClassname) { + this.protocolClassname = protocolClassname; + } + + /* (non-Javadoc) + * @see events.VSAbstractEvent#onStart() + */ + public void onStart() { + VSInternalProcess internalProcess = (VSInternalProcess) process; + VSAbstractProtocol protocol = + internalProcess.getProtocolObject(protocolClassname); + + if (isClientProtocol) + protocol.isClient(isProtocolActivation); + else + protocol.isServer(isProtocolActivation); + + StringBuffer buffer = new StringBuffer(); + buffer.append(VSRegisteredEvents.getShortnameByClassname( + protocolClassname)); + + buffer.append(" "); + buffer.append(isClientProtocol + ? prefs.getString("lang.client") + : prefs.getString("lang.server")); + + buffer.append(" "); + buffer.append(isProtocolActivation + ? prefs.getString("lang.activated") + : prefs.getString("langactivated")); + + log(buffer.toString()); + } + + /* (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); + + /** For later backwards compatibility, to add more stuff */ + objectOutputStream.writeObject(Boolean.valueOf(false)); + + objectOutputStream.writeObject(protocolClassname); + objectOutputStream.writeObject(Boolean.valueOf(isClientProtocol)); + objectOutputStream.writeObject(Boolean.valueOf(isProtocolActivation)); + + /** 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); + + if (VSSerialize.DEBUG) + System.out.println("Deserializing: VSProtocolEvent"); + + /** For later backwards compatibility, to add more stuff */ + objectInputStream.readObject(); + + protocolClassname = (String) objectInputStream.readObject(); + + isClientProtocol = ((Boolean) + objectInputStream.readObject()).booleanValue();; + isProtocolActivation = ((Boolean) + objectInputStream.readObject()).booleanValue();; + + /** For later backwards compatibility, to add more stuff */ + objectInputStream.readObject(); + } +} diff --git a/src/main/java/events/internal/VSProtocolScheduleEvent.java b/src/main/java/events/internal/VSProtocolScheduleEvent.java new file mode 100644 index 0000000..c940212 --- /dev/null +++ b/src/main/java/events/internal/VSProtocolScheduleEvent.java @@ -0,0 +1,126 @@ +package events.internal; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; + +import protocols.VSAbstractProtocol; +import serialize.VSNotSerializable; +import serialize.VSSerialize; + +/** + * The class VSProtocolScheduleEvent, this event is used if a protocol (which + * is a subclass of VSAbstractProtocol) reschedules itself to run again on a + * specific time. + * + * @author Paul C. Buetow + */ +public class VSProtocolScheduleEvent extends VSAbstractInternalEvent + implements VSNotSerializable { + /** The event is a server protocol schedule. */ + private boolean isServerSchedule; /* true = server, false = client */ + + /** The reference to the protocol object to schedule. */ + private VSAbstractProtocol protocol; + + /** + * Create a VSProtocolScheduleEvent object + * + * @param protocol the protocol + * @param isServerSchedule the event is a client protocol schedule if + * false, else server schedule + */ + public VSProtocolScheduleEvent(VSAbstractProtocol protocol, + boolean isServerSchedule) { + this.protocol = protocol; + this.isServerSchedule = isServerSchedule; + } + + /* (non-Javadoc) + * @see events.VSAbstractEvent#onInit() + */ + public void onInit() { + setClassname(getClass().toString()); + } + + /** + * Sets if it is client protocol schedule. + * + * @param isServerSchedule false, if the event is a client protocol + * schedule. true, if server. + */ + public void isServerSchedule(boolean isServerSchedule) { + this.isServerSchedule = isServerSchedule; + } + + /** + * Sets if it is client protocol schedule. + * + * @return false, if the event is a client protocol schedule. true, if + * server. + */ + public boolean isServerSchedule() { + return isServerSchedule; + } + + /** + * Sets the protocol. + * + * @param protocol the protocol + */ + public void setProtocol(VSAbstractProtocol protocol) { + this.protocol = protocol; + } + + /** + * Gets the protocol. + * + * @return the protocol + */ + public VSAbstractProtocol getProtocol() { + return protocol; + } + + /* (non-Javadoc) + * @see events.VSAbstractEvent#onStart() + */ + public void onStart() { + if (isServerSchedule) + protocol.onServerScheduleStart(); + else + protocol.onClientScheduleStart(); + } + + /* (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); + + /** For later backwards compatibility, to add more stuff */ + objectOutputStream.writeObject(Boolean.valueOf(false)); + + /** 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); + + if (VSSerialize.DEBUG) + System.out.println("Deserializing: VSProtocolEvent"); + + /** For later backwards compatibility, to add more stuff */ + objectInputStream.readObject(); + + } +} diff --git a/src/main/java/exceptions/VSEventNotCopyableException.java b/src/main/java/exceptions/VSEventNotCopyableException.java new file mode 100644 index 0000000..f542db8 --- /dev/null +++ b/src/main/java/exceptions/VSEventNotCopyableException.java @@ -0,0 +1,16 @@ +package exceptions; + +/** + * The Interface VSEventNotCopyableException, this exception is thrown if + * the someone tried to copy a not copyable event! + * + * @author Paul C. Buetow + */ +public class VSEventNotCopyableException extends Exception { + /** The serial version uid */ + private static final long serialVersionUID = 1L; + + public VSEventNotCopyableException(String descr) { + super(descr); + } +} diff --git a/src/main/java/exceptions/VSNegativeNumberException.java b/src/main/java/exceptions/VSNegativeNumberException.java new file mode 100644 index 0000000..edf2049 --- /dev/null +++ b/src/main/java/exceptions/VSNegativeNumberException.java @@ -0,0 +1,12 @@ +package exceptions; + +/** + * The Interface VSNegativeNumberException, this exception is thrown if + * a negative number has returned if a positive number has been expected. + * + * @author Paul C. Buetow + */ +public class VSNegativeNumberException extends Exception { + /** The serial version uid */ + private static final long serialVersionUID = 1L; +} diff --git a/src/main/java/exceptions/VSParseIntegerVectorException.java b/src/main/java/exceptions/VSParseIntegerVectorException.java new file mode 100644 index 0000000..19c2b82 --- /dev/null +++ b/src/main/java/exceptions/VSParseIntegerVectorException.java @@ -0,0 +1,13 @@ +package exceptions; + +/** + * The Interface VSParseIntegerVectorException, this exception is thrown if + * the VSAbstractEditor is not able to parse the vector fields input of the + * user. + * + * @author Paul C. Buetow + */ +public class VSParseIntegerVectorException extends Exception { + /** The serial version uid */ + private static final long serialVersionUID = 1L; +} diff --git a/src/main/java/prefs/VSDefaultPrefs.java b/src/main/java/prefs/VSDefaultPrefs.java new file mode 100644 index 0000000..f980734 --- /dev/null +++ b/src/main/java/prefs/VSDefaultPrefs.java @@ -0,0 +1,275 @@ +package prefs; + +import java.awt.Color; +import java.awt.event.KeyEvent; + +/** + * The class VSDefaultPrefs, makes sure that the simulator has its default + * configuration values. + * + * @author Paul C. Buetow + */ +public class VSDefaultPrefs extends VSSerializablePrefs { + /** + * Inits a prefs object with default values. + * + * @return the lang.process.removeprefs + */ + public static VSPrefs init() { + VSDefaultPrefs prefs = new VSDefaultPrefs(); + prefs.fillWithDefaults(); + return prefs; + } + + /** + * Fill everything with ts defaults. + */ + public void fillWithDefaults() { + super.clear(); + addWithDefaults(); + } + + /** + * Adds default values if not existent. + */ + public void addWithDefaults() { + fillDefaultBooleans(); + fillDefaultColors(); + fillDefaultFloats(); + fillDefaultIntegers(); + fillDefaultLongs(); + fillDefaultStrings(); + } + + /** + * Fill with default strings. + */ + public void fillDefaultStrings() { + initString("lang.about", "About"); + initString("lang.about.info", "This program used to be the diploma thesis of Paul C. Buetow. Please contact vs-sim@dev.buetow.org, if you find any errors!"); + initString("lang.activate", "activate"); + initString("lang.activated", "activated"); + initString("lang.actualize", "Activation"); + initString("lang.all", "All"); + initString("lang.antialiasing", "Anti-Aliasing"); + initString("lang.cancel", "Abort"); + initString("lang.client", "Client"); + initString("lang.clientrequest.start", "Start client request"); + initString("lang.close", "Close"); + initString("lang.colorchooser", "Color chooser"); + initString("lang.colorchooser2", "Please select color"); + initString("lang.copy", "Copy"); + initString("lang.crashed", "Crashed"); + initString("lang.dat", "Simulation (.dat)"); + initString("langactivate", "deactivate"); + initString("langactivated", "deactivated"); + initString("lang.default", "Defaults"); + initString("lang.edit", "Edit"); + initString("lang.editor", "Editor"); + initString("lang.event", "Event"); + initString("lang.event.add.global", "Insert global event"); + initString("lang.event.add.local", "Insert local event"); + initString("lang.event.add.time", "at"); + initString("lang.events", "Events"); + initString("lang.events.process", "Process events"); + initString("lang.file", "File"); + initString("lang.filter", "Filter"); + initString("lang.loging.active", "Logging"); + initString("lang.loging.clear", "Delete logs"); + initString("lang.message", "Message"); + initString("lang.message.recv", "Message received"); + initString("lang.message.sent", "Message sent"); + initString("lang.mode.expert", "Expert mode"); + initString("lang.name", "VS-Simulator 1.2-beta"); + initString("lang.ok", "OK"); + initString("lang.open", "Open"); + initString("lang.pause", "Pause"); + initString("lang.prefs", "Preferences"); + initString("lang.prefs.color", "Color preferences"); + initString("lang.prefs.diverse", "Diverse preferences"); + initString("lang.prefs.ext", "Extended preferences"); + initString("lang.prefs.message", "Message preferences"); + initString("lang.prefs.message.defaults", "Message prefs. for new processes"); + initString("lang.prefs.more", "More preferences"); + initString("lang.prefs.process", "Process preferences"); + initString("lang.prefs.process", "Standard process preferences"); + initString("lang.prefs.process.defaults", "Preferences for new processes"); + initString("lang.prefs.process.ext", "Extended process preferences"); + initString("lang.prefs.protocols", "Protocol preferences"); + initString("lang.prefs.simulator", "Simulator preferences"); + initString("lang.process", "Process"); + initString("lang.process.add.new", "Insert new process"); + initString("lang.process.crash", "Crash process"); + initString("lang.process.edit", "Edit process"); + initString("lang.process.id", "PID"); + initString("lang.process.new", "New process"); + initString("lang.process.not.selected", "No process selected"); + initString("lang.process.recover", "Recover process"); + initString("lang.process.remove", "Remove process"); + initString("lang.process.selected", "Selected process"); + initString("lang.process.time.local", "Local time"); + initString("lang.processes.all", "All processes"); + initString("lang.protocol", "Protocol"); + initString("lang.protocol.client", "Client side"); + initString("lang.protocol.editor", "Protocol editor"); + initString("lang.protocol.server", "Server side"); + initString("lang.protocol.tasks.activation", "Client-/Server protocol activation"); + initString("lang.protocol.tasks.client", "Client Task-Manager (Client request)"); + initString("lang.protocols", "Protocols"); + initString("lang.quit", "Quit"); + initString("lang.recovered", "Recovered"); + initString("lang.remove", "Remove"); + initString("lang.replay", "Repeat"); + initString("lang.reset", "Reset"); + initString("lang.save", "Save"); + initString("lang.saveas", "Save as"); + initString("lang.server", "Server"); + initString("lang.serverrequest.start", "Start server request"); + initString("lang.simulator", "Simulator"); + initString("lang.simulator.close", "Close simulation"); + initString("lang.simulator.finished", "Simulation closed"); + initString("lang.simulator.new", "New simulation"); + initString("lang.simulator.paused", "Simulation paused"); + initString("lang.simulator.resetted", "Simulation resetted"); + initString("lang.simulator.started", "Simulation started"); + initString("lang.start", "Start"); + initString("lang.stop", "Stop"); + initString("lang.takeover", "Take over"); + initString("lang.task", "Task"); + initString("lang.task.manager", "Event editor"); + initString("lang.tasks.fullfilled", "Fullfilled tasks"); + initString("lang.tasks.global", "GLobal tasks"); + initString("lang.tasks.local", "Local tasks"); + initString("lang.time", "Time"); + initString("lang.time.lamport", "Lamport time"); + initString("lang.time.vector", "Vector time"); + initString("lang.timed.global", "Global events"); + initString("lang.timed.local", "Local events"); + initString("lang.type", "Type"); + initString("lang.value", "Value"); + initString("lang.variable", "Variable"); + initString("lang.variables", "Variables"); + initString("lang.variables.global", "Global variables"); + initString("lang.window.close", "Close window"); + initString("lang.window.new", "New window"); + + /* Protocol names */ + initString("lang.events.implementations.VSProcessCrashEvent", "Process Crash Event"); + initString("lang.events.implementations.VSProcessCrashEvent.short", "Process Crash"); + initString("lang.events.implementations.VSProcessRecoverEvent", "Process Recover Event"); + initString("lang.events.implementations.VSProcessRecoverEvent.short", "Process Recover"); + initString("lang.protocols.implementations.VSBasicMulticastProtocol", "Basic Multicast Protocol"); + initString("lang.protocols.implementations.VSBasicMulticastProtocol.short", "Basic Multicast"); + initString("lang.protocols.implementations.VSBerkelyTimeProtocol", "Berkley algorithm for internal sync."); + initString("lang.protocols.implementations.VSBerkelyTimeProtocol.short", "Berkley Protocol"); + initString("lang.protocols.implementations.VSBroadcastProtocol", "Broadcast Protocol"); + initString("lang.protocols.implementations.VSBroadcastProtocol.short", "Broadcast"); + initString("lang.protocols.implementations.VSDummyProtocol", "Example/Dummy Protocol"); + initString("lang.protocols.implementations.VSDummyProtocol.short", "Example/Dummy"); + initString("lang.protocols.implementations.VSExternalTimeSyncProtocol", "Christians method for external sync."); + initString("lang.protocols.implementations.VSExternalTimeSyncProtocol.short", "Christians"); + initString("lang.protocols.implementations.VSInternalTimeSyncProtocol", "Internal Synchronization Protocol"); + initString("lang.protocols.implementations.VSInternalTimeSyncProtocol.short", "Internal sync."); + initString("lang.protocols.implementations.VSOnePhaseCommitProtocol", "One-Phase Commit Protocol"); + initString("lang.protocols.implementations.VSOnePhaseCommitProtocol.short", "1-Phase Commit"); + initString("lang.protocols.implementations.VSPingPongProtocol", "Ping-Pong Protocol"); + initString("lang.protocols.implementations.VSPingPongProtocol.short", "Ping-Pong"); + initString("lang.protocols.implementations.VSReliableMulticastProtocol", "Reliable Multicast Protocol"); + initString("lang.protocols.implementations.VSReliableMulticastProtocol.short", "Reliable Multicast"); + initString("lang.protocols.implementations.VSTwoPhaseCommitProtocol", "Two-Phase Commit"); + initString("lang.protocols.implementations.VSTwoPhaseCommitProtocol.short", "2-Phase Commit"); + } + + /** + * Fill with default integers. + */ + public void fillDefaultIntegers() { + /* Simulator prefs */ + initInteger("sim.process.num", 3, "Number of processes", 1, 6); + initInteger("message.prob.outage", 0, "Message lost prob.", 0, 100, "%"); + initInteger("process.prob.crash", 0, "Process crash prob.", 0, 100, "%"); + initInteger("sim.seconds", 15, "Simulation duration", 5, 120, "s"); + + /* Internal prefs */ + initInteger("keyevent.about", KeyEvent.VK_A, null, 0, 100); + initInteger("keyevent.cancel", KeyEvent.VK_A, null, 0, 100); + initInteger("keyevent.close", KeyEvent.VK_C, null, 0, 100); + initInteger("keyevent.default", KeyEvent.VK_F, null, 0, 100); + initInteger("keyevent.edit", KeyEvent.VK_E, null, 0, 100); + initInteger("keyevent.file", KeyEvent.VK_D, null, 0, 100); + initInteger("keyevent.new", KeyEvent.VK_N, null, 0, 100); + initInteger("keyevent.actualize", KeyEvent.VK_A, null, 0, 100); + initInteger("keyevent.takeover", KeyEvent.VK_B, null, 0, 100); + initInteger("keyevent.ok", KeyEvent.VK_O, null, 0, 100); + initInteger("keyevent.open", KeyEvent.VK_O, null, 0, 100); + initInteger("keyevent.pause", KeyEvent.VK_P, null, 0, 100); + initInteger("keyevent.prefs", KeyEvent.VK_P, null, 0, 100); + initInteger("keyevent.prefs.ext", KeyEvent.VK_E, null, 0, 100); + initInteger("keyevent.quit", KeyEvent.VK_B, null, 0, 100); + initInteger("keyevent.replay", KeyEvent.VK_W, null, 0, 100); + initInteger("keyevent.reset", KeyEvent.VK_R, null, 0, 100); + initInteger("keyevent.save", KeyEvent.VK_S, null, 0, 100); + initInteger("keyevent.saveas", KeyEvent.VK_V, null, 0, 100); + initInteger("keyevent.simulator", KeyEvent.VK_S, null, 0, 100); + initInteger("keyevent.start", KeyEvent.VK_S, null, 0, 100); + initInteger("keyevent.stop", KeyEvent.VK_P, null, 0, 100); + + initInteger("div.window.prefs.xsize", 400, "Configuration window X-Axis", 550, 3200, "px"); + initInteger("div.window.prefs.ysize", 400, "Configuration window Y-Axis", 640, 2400, "px"); + initInteger("div.window.logsize", 300, "Log window Y-Axis", 100, 1000, "px"); + initInteger("div.window.splitsize", 320, "Toolbar X-Axis", 100, 1000, "px"); + initInteger("div.window.xsize", 1024, "Main window X-Axis", 750, 3200, "px"); + initInteger("div.window.ysize", 768, "Main window Y-Axis", 600, 2400, "px"); + } + + /** + * Fill with default floats. + */ + public void fillDefaultFloats() { + /* Simulator prefs */ + initFloat("process.clock.variance", 0, "Clock variance"); + initFloat("sim.clock.speed", 0.5f, "Simulation play speed"); + } + + /** + * Fill default longs. + */ + public void fillDefaultLongs() { + /* Simulator prefs */ + initLong("message.sendingtime.min", 500, "Max transmission time", "ms"); + initLong("message.sendingtime.max", 2000, "Min transmission time", "ms"); + } + + /** + * Fill with default colors. + */ + public void fillDefaultColors() { + /* Internal prefs */ + initColor("col.background", new Color(0xFF, 0xFF, 0xFF)); + initColor("col.process.default", new Color(0x00, 0x00, 0x00)); + initColor("col.process.running", new Color(0x0D, 0xD8, 0x09)); + initColor("col.process.crashed", new Color(0xff, 0x00, 0x00)); + initColor("col.process.highlight", new Color(0xff, 0xA5, 0x00)); + initColor("col.process.line", new Color(0x00, 0x00, 0x00)); + initColor("col.process.secondline", new Color(0xAA, 0xAA, 0xAA)); + initColor("col.process.sepline", new Color(0xff, 0x00, 0x00)); + initColor("col.process.stopped", new Color(0x00, 0x00, 0x00)); + initColor("col.message.arrived", new Color(0x00, 0x85, 0xD2)); + initColor("col.message.sending", new Color(0x0D, 0xD8, 0x09)); + initColor("col.message.lost", new Color(0xFF, 0x00, 0x00)); + } + + /** + * Fill with default booleans. + */ + public void fillDefaultBooleans() { + initBoolean("sim.mode.expert", false, "Expert mode"); + initBoolean("sim.message.own.recv", false, "Processes receive own messages"); + initBoolean("sim.message.prob.mean", true, "Use mean value of message lost prob."); + initBoolean("sim.message.sendingtime.mean", true, "Use mean value of transmission times"); + initBoolean("sim.messages.relevant", true, "Only show relevant messages"); + initBoolean("sim.periodic", false, "Repeat simulation periodically"); + initBoolean("sim.update.lamporttime.all", false, "Lamport timestamps affect all events"); + initBoolean("sim.update.vectortime.all", false, "Vector timestamps affect all events"); + } +} diff --git a/src/main/java/prefs/VSPrefs.java b/src/main/java/prefs/VSPrefs.java new file mode 100644 index 0000000..e7b5295 --- /dev/null +++ b/src/main/java/prefs/VSPrefs.java @@ -0,0 +1,1163 @@ +package prefs; + +import java.awt.Color; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.Set; +import java.util.Vector; + +import serialize.VSSerialize; + +/** + * The class VSPrefs, this class is for dynamic data storage. It can hold + * various different types such as Boolean, Floats, Integers, Strings, Colors. + * + * @author Paul C. Buetow + */ +public class VSPrefs { + /** The Constant BOOLEAN_PREFIX. */ + public static final String BOOLEAN_PREFIX = "Boolean: "; + + /** The Constant COLOR_PREFIX. */ + public static final String COLOR_PREFIX = "Color: "; + + /** The Constant FLOAT_PREFIX. */ + public static final String FLOAT_PREFIX = "Float: "; + + /** The Constant INTEGER_PREFIX. */ + public static final String INTEGER_PREFIX = "Integer: "; + + /** The Constant VECTOR_PREFIX. */ + public static final String VECTOR_PREFIX = "Vector: "; + + /** The Constant LONG_PREFIX. */ + public static final String LONG_PREFIX = "Long: "; + + /** The Constant STRING_PREFIX. */ + public static final String STRING_PREFIX = "String: "; + + /** The color prefs. */ + private HashMap<String,Color> colorPrefs; + + /** The float prefs. */ + private HashMap<String,Float> floatPrefs; + + /** The integer prefs. */ + private HashMap<String,Integer> integerPrefs; + + /** The integer vector prefs. */ + private HashMap<String,Vector<Integer>> vectorPrefs; + + /** The long prefs. */ + private HashMap<String,Long> longPrefs; + + /** The setting restriction prefs. */ + private HashMap<String,VSPrefsRestriction> restrictions; + + /** The description prefs. */ + private HashMap<String,String> descriptionPrefs; + + /** The string prefs. */ + private HashMap<String,String> stringPrefs; + + /** The boolean prefs. */ + private HashMap<String,Boolean> booleanPrefs; + + /** The object prefs. */ + private HashMap<String,Object> objectPrefs; + + /** The units. */ + private HashMap<String,String> units; + + /** The id counter. */ + private static int idCounter; + + /** The id. */ + protected int id; + + /** + * Instantiates a new lang.process.removeprefs. + */ + public VSPrefs() { + colorPrefs = new HashMap<String,Color>(); + descriptionPrefs = new HashMap<String,String>(); + floatPrefs = new HashMap<String,Float>(); + integerPrefs = new HashMap<String,Integer>(); + vectorPrefs = new HashMap<String,Vector<Integer>>(); + longPrefs = new HashMap<String,Long>(); + restrictions = new HashMap<String,VSPrefsRestriction>(); + stringPrefs = new HashMap<String,String>(); + booleanPrefs = new HashMap<String,Boolean>(); + objectPrefs = new HashMap<String,Object>(); + units = new HashMap<String,String>(); + id = ++idCounter; + } + + /** + * Clear. + */ + protected synchronized void clear() { + colorPrefs.clear(); + floatPrefs.clear(); + integerPrefs.clear(); + vectorPrefs.clear(); + longPrefs.clear(); + stringPrefs.clear(); + booleanPrefs.clear(); + objectPrefs.clear(); + descriptionPrefs.clear(); + restrictions.clear(); + } + + /* Unit methods */ + + /** + * Gets the unit. + * + * @param fullKey the full key + * + * @return the unit + */ + public synchronized String getUnit(String fullKey) { + return units.get(fullKey); + } + + /** + * Sets the unit. + * + * @param key the key + * @param unit the unit + */ + public synchronized void initUnit(String key, String unit) { + if (unit == null /*|| units.containsKey(key)*/) + return; + units.put(key, unit); + } + + /* Description methods */ + /** + * Sets the description if unset. + * + * @param key the key + * @param descr the descr + */ + public synchronized void initDescription(String key, String descr) { + if (descr == null /*|| descriptionPrefs.containsKey(key)*/) + return; + descriptionPrefs.put(key, descr); + } + + /** + * Gets the description. + * + * @param fullKey the full key + * + * @return the description + */ + public synchronized String getDescription(String fullKey) { + return descriptionPrefs.get(fullKey); + } + + /* Restriction methods */ + + /** + * Gets the restriction. + * + * @param fullKey the full key + * + * @return the restriction + */ + public synchronized VSPrefsRestriction getRestriction(String fullKey) { + return restrictions.get(fullKey); + } + + /** + * Sets the restriction. + * + * @param key the key + * @param settingRestriction the setting restriction + */ + public synchronized void initRestriction(String key, + VSPrefsRestriction settingRestriction) { + restrictions.put(key, settingRestriction); + } + + /* Object methods */ + + /** + * Object exists. + * + * @param key the key + * + * @return true, if successful + */ + public synchronized boolean objectExists(String key) { + return null != objectPrefs.get(key); + } + + /** + * Gets the object. + * + * @param key the key + * + * @return the object + */ + public synchronized Object getObject(String key) { + Object val = objectPrefs.get(key); + + if (val == null) { + System.err.println("Fatal: No such object config value \"" + key + "\""); + System.exit(1); + } + + return val; + } + + /** + * Removes the object. + * + * @param key the key + */ + public synchronized void removeObject(String key) { + objectPrefs.remove(key); + } + + /** + * Sets the object. + * + * @param key the key + * @param val the val + */ + public synchronized void setObject(String key, Object val) { + objectPrefs.put(key, val); + } + + /* Boolean methods */ + + /** + * Gets the boolean. + * + * @param key the key + * + * @return the boolean + */ + public boolean getBoolean(String key) { + return getBooleanObj(key).booleanValue(); + } + + /** + * Gets the boolean key set. + * + * @return the boolean key set + */ + public synchronized Set<String> getBooleanKeySet() { + return booleanPrefs.keySet(); + } + + /** + * Gets the boolean obj. + * + * @param key the key + * + * @return the boolean obj + */ + public synchronized Boolean getBooleanObj(String key) { + Boolean val = booleanPrefs.get(key); + + if (val == null) + return Boolean.valueOf(false); + + return val; + } + + /** + * Inits the boolean. + * + * @param key the key + * @param val the val + */ + public synchronized void initBoolean(String key, Boolean val) { + if (!booleanPrefs.containsKey(key)) + booleanPrefs.put(key, val); + } + + /** + * Inits the boolean. + * + * @param key the key + * @param val the val + */ + public void initBoolean(String key, boolean val) { + initBoolean(key, Boolean.valueOf(val)); + } + + /** + * Inits the boolean. + * + * @param key the key + * @param val the val + * @param descr the descr + */ + public void initBoolean(String key, boolean val, String descr) { + initBoolean(key, val); + initDescription(BOOLEAN_PREFIX + key, descr); + } + + /** + * Sets the boolean. + * + * @param key the key + * @param val the val + */ + public synchronized void setBoolean(String key, Boolean val) { + booleanPrefs.put(key, val); + } + + /** + * Sets the boolean. + * + * @param key the key + * @param val the val + */ + public void setBoolean(String key, boolean val) { + setBoolean(key, Boolean.valueOf(val)); + } + + /* Color methods */ + + /** + * Gets the color. + * + * @param key the key + * + * @return the color + */ + public synchronized Color getColor(String key) { + Color color = colorPrefs.get(key); + + if (color == null) { + System.err.println("Fatal: No such color config value \"" + + key + "\""); + System.exit(1); + } + + return color; + } + + /** + * Gets the color key set. + * + * @return the color key set + */ + public synchronized Set<String> getColorKeySet() { + return colorPrefs.keySet(); + } + + /** + * Inits the color. + * + * @param key the key + * @param color the color + */ + public synchronized void initColor(String key, Color color) { + if (!colorPrefs.containsKey(key)) + colorPrefs.put(key, color); + } + + /** + * Inits the color. + * + * @param key the key + * @param val the val + * @param descr the descr + */ + public void initColor(String key, Color val, String descr) { + initColor(key, val); + initDescription(COLOR_PREFIX + key, descr); + } + + /** + * Sets the color. + * + * @param key the key + * @param color the color + */ + public synchronized void setColor(String key, Color color) { + colorPrefs.put(key, color); + } + + /* Float methods */ + + /** + * Gets the float. + * + * @param key the key + * + * @return the float + */ + public float getFloat(String key) { + return getFloatObj(key).floatValue(); + } + + /** + * Gets the float key set. + * + * @return the float key set + */ + public synchronized Set<String> getFloatKeySet() { + return floatPrefs.keySet(); + } + + /** + * Gets the float obj. + * + * @param key the key + * + * @return the float obj + */ + public synchronized Float getFloatObj(String key) { + Float val = floatPrefs.get(key); + + if (val == null) { + System.err.println("Fatal: No such float config value \"" + + key + "\""); + System.exit(1); + } + + return val; + } + + /** + * Inits the float. + * + * @param key the key + * @param val the val + */ + public synchronized void initFloat(String key, Float val) { + if (!floatPrefs.containsKey(key)) + floatPrefs.put(key, val); + } + + /** + * Inits the float. + * + * @param key the key + * @param val the val + */ + public void initFloat(String key, float val) { + initFloat(key, Float.valueOf(val)); + } + + /** + * Inits the float. + * + * @param key the key + * @param val the val + * @param descr the descr + */ + public void initFloat(String key, float val, String descr) { + initFloat(key, val); + initDescription(FLOAT_PREFIX + key, descr); + } + + /** + * Inits the float plus unit. + * + * @param key the key + * @param val the val + * @param descr the descr + * @param unit the unit + */ + public void initFloat(String key, float val, String descr, String unit) { + initFloat(key, val, descr); + initUnit(FLOAT_PREFIX + key, unit); + } + + /** + * Sets the float. + * + * @param key the key + * @param val the val + */ + public synchronized void setFloat(String key, Float val) { + floatPrefs.put(key, val); + } + + /** + * Sets the float. + * + * @param key the key + * @param val the val + */ + public void setFloat(String key, float val) { + setFloat(key, Float.valueOf(val)); + } + + /* Integer methods */ + + /** + * Gets the integer. + * + * @param key the key + * + * @return the integer + */ + public int getInteger(String key) { + return getIntegerObj(key).intValue(); + } + + /** + * Gets the integer key set. + * + * @return the integer key set + */ + public synchronized Set<String> getIntegerKeySet() { + return integerPrefs.keySet(); + } + + /** + * Gets the integer obj. + * + * @param key the key + * + * @return the integer obj + */ + public synchronized Integer getIntegerObj(String key) { + Integer val = integerPrefs.get(key); + + if (val == null) { + System.err.println("Fatal: No such integer config value \"" + key + "\""); + System.exit(1); + } + + return val; + } + + /** + * Inits the integer. + * + * @param key the key + * @param val the val + */ + public void initInteger(String key, int val) { + if (!integerPrefs.containsKey(key)) + setInteger(key, Integer.valueOf(val)); + } + + /** + * Inits the integer. + * + * @param key the key + * @param val the val + * @param descr the descr + */ + public void initInteger(String key, int val, String descr) { + initInteger(key, val); + initDescription(INTEGER_PREFIX + key, descr); + } + + /** + * Inits the integer. + * + * @param key the key + * @param val the val + * @param descr the descr + * @param r the restriction + */ + public void initInteger(String key, int val, String descr, + VSPrefsRestriction.VSIntegerPrefsRestriction r) { + initInteger(key, val, descr); + initRestriction(INTEGER_PREFIX + key, r); + } + + /** + * Inits the integer. + * + * @param key the key + * @param val the val + * @param descr the descr + * @param r the restriction + */ + public void initInteger(String key, int val, String descr, + VSPrefsRestriction.VSIntegerPrefsRestriction r, + String unit) { + initInteger(key, val, descr, r); + initUnit(INTEGER_PREFIX + key, unit); + } + + /** + * Inits the integer. + * + * @param key the key + * @param val the val + * @param descr the descr + * @param minValue the min value + * @param maxValue the max value + */ + public void initInteger(String key, int val, String descr, int minValue, + int maxValue) { + initInteger(key, val, descr, + new VSPrefsRestriction.VSIntegerPrefsRestriction( + minValue, maxValue)); + } + + /** + * Inits the integer plus unit. + * + * @param key the key + * @param val the val + * @param descr the descr + * @param minValue the min value + * @param maxValue the max value + * @param unit the unit + */ + public void initInteger(String key, int val, String descr, int minValue, + int maxValue, String unit) { + initInteger(key, val, descr, minValue, maxValue); + initUnit(INTEGER_PREFIX + key, unit); + } + + /** + * Sets the integer. + * + * @param key the key + * @param val the val + */ + public synchronized void setInteger(String key, Integer val) { + integerPrefs.put(key, val); + } + + /** + * Sets the integer. + * + * @param key the key + * @param val the val + */ + public void setInteger(String key, int val) { + setInteger(key, Integer.valueOf(val)); + } + + /* Integer vector methods */ + + /** + * Gets the integer key set. + * + * @return the integer key set + */ + public synchronized Set<String> getVectorKeySet() { + return vectorPrefs.keySet(); + } + + /** + * Gets the integer obj. + * + * @param key the key + * + * @return the integer obj + */ + public synchronized Vector<Integer> getVector(String key) { + Vector<Integer> val = vectorPrefs.get(key); + + if (val == null) { + System.err.println("Fatal: No such integer config value \"" + key + "\""); + System.exit(1); + } + + return val; + } + + /** + * Inits the integer. + * + * @param key the key + * @param val the val + */ + public synchronized void initVector(String key, Vector<Integer> val) { + if (!vectorPrefs.containsKey(key)) + setVector(key, val); + } + + /** + * Inits the integer vector. + * + * @param key the key + * @param val the val + * @param descr the descr + */ + public void initVector(String key, Vector<Integer> val, String descr) { + initVector(key, val); + initDescription(VECTOR_PREFIX + key, descr); + } + + /** + * Inits the integer vector plus unit. + * + * @param key the key + * @param val the val + * @param descr the descr + */ + public void initVector(String key, Vector<Integer> val, String descr, + String unit) { + initVector(key, val, descr); + initUnit(VECTOR_PREFIX + key, unit); + } + + /** + * Sets the integer vector. + * + * @param key the key + * @param val the val + */ + public synchronized void setVector(String key, Vector<Integer> val) { + vectorPrefs.put(key, val); + } + + /* Long methods */ + + /** + * Gets the long. + * + * @param key the key + * + * @return the long + */ + public long getLong(String key) { + return getLongObj(key).longValue(); + } + + /** + * Gets the long key set. + * + * @return the long key set + */ + public synchronized Set<String> getLongKeySet() { + return longPrefs.keySet(); + } + + /** + * Gets the long obj. + * + * @param key the key + * + * @return the long obj + */ + public synchronized Long getLongObj(String key) { + Long val = longPrefs.get(key); + + if (val == null) { + System.err.println("Fatal: No such long config value \"" + key + "\""); + System.exit(1); + } + + return val; + } + + /** + * Inits the long. + * + * @param key the key + * @param val the val + */ + public synchronized void initLong(String key, Long val) { + if (!longPrefs.containsKey(key)) + longPrefs.put(key, val); + } + + /** + * Sets the long if unset. + * + * @param key the key + * @param val the val + */ + public void initLong(String key, long val) { + initLong(key, Long.valueOf(val)); + } + + /** + * Inits the long. + * + * @param key the key + * @param val the val + * @param descr the descr + */ + public void initLong(String key, long val, String descr) { + initLong(key, val); + initDescription(LONG_PREFIX + key, descr); + } + + /** + * Inits the long unit. + * + * @param key the key + * @param val the val + * @param descr the descr + * @param unit the unit + */ + public void initLong(String key, long val, String descr, String unit) { + initLong(key, val, descr); + initUnit(LONG_PREFIX + key, unit); + } + + /** + * Deletes the long. + * + * @param key the key + */ + public synchronized void deleteLong(String key) { + longPrefs.remove(key); + } + + /** + * Sets the long. + * + * @param key the key + * @param val the val + */ + public synchronized void setLong(String key, Long val) { + longPrefs.put(key, val); + } + + /** + * Sets the long. + * + * @param key the key + * @param val the val + */ + public void setLong(String key, long val) { + setLong(key, Long.valueOf(val)); + } + + /* String methods */ + + /** + * Gets the string. + * + * @param key the key + * + * @return the string + */ + public synchronized String getString(String key) { + String val = stringPrefs.get(key); + + if (val == null) { + System.err.println("Fatal: No such string config value \"" + key + "\""); + System.exit(1); + } + + return val; + } + + /** + * Gets the string key set. + * + * @return the string key set + */ + public synchronized Set<String> getStringKeySet() { + return stringPrefs.keySet(); + } + + /** + * Inits the string. + * + * @param key the key + * @param val the val + */ + public synchronized void initString(String key, String val) { + //if (!stringPrefs.containsKey(key)) + stringPrefs.put(key, val); + } + + /** + * Inits the string. + * + * @param key the key + * @param val the val + * @param descr the descr + */ + public void initString(String key, String val, String descr) { + initString(key, val); + initDescription(STRING_PREFIX + key, descr); + } + + /** + * Sets the string. + * + * @param key the key + * @param val the val + */ + public synchronized void setString(String key, String val) { + stringPrefs.put(key, val); + } + + /* (non-Javadoc) + * @see serialize.VSSerializable#serialize(serialize.VSSerialize, + * java.io.ObjectOutputStream) + */ + protected synchronized void serialize_( + VSSerialize serialize, ObjectOutputStream objectOutputStream) + throws IOException { + /** For later backwards compatibility, to add more stuff */ + objectOutputStream.writeObject(Boolean.valueOf(false)); + + objectOutputStream.writeObject(booleanPrefs); + objectOutputStream.writeObject(colorPrefs); + objectOutputStream.writeObject(descriptionPrefs); + objectOutputStream.writeObject(floatPrefs); + objectOutputStream.writeObject(integerPrefs); + objectOutputStream.writeObject(longPrefs); + objectOutputStream.writeObject(stringPrefs); + objectOutputStream.writeObject(units); + objectOutputStream.writeObject(vectorPrefs); + objectOutputStream.writeObject(restrictions); + + /** For later backwards compatibility, to add more stuff */ + objectOutputStream.writeObject(Boolean.valueOf(false)); + } + + /* (non-Javadoc) + * @see serialize.VSSerializable#deserialize(serialize.VSSerialize, + * java.io.ObjectInputStream) + */ + @SuppressWarnings("unchecked") + protected synchronized void deserialize_(VSSerialize serialize, + ObjectInputStream objectInputStream) + throws IOException, ClassNotFoundException { + objectPrefs.clear(); + + /** For later backwards compatibility, to add more stuff */ + objectInputStream.readObject(); + + booleanPrefs = (HashMap<String,Boolean>) objectInputStream.readObject(); + colorPrefs = (HashMap<String,Color>) objectInputStream.readObject(); + descriptionPrefs = (HashMap<String,String>) objectInputStream.readObject(); + floatPrefs = (HashMap<String,Float>) objectInputStream.readObject(); + integerPrefs = (HashMap<String,Integer>) objectInputStream.readObject(); + longPrefs = (HashMap<String,Long>) objectInputStream.readObject(); + stringPrefs = (HashMap<String,String>) objectInputStream.readObject(); + units = (HashMap<String,String>) objectInputStream.readObject(); + vectorPrefs = (HashMap<String,Vector<Integer>>) objectInputStream.readObject(); + restrictions = (HashMap<String,VSPrefsRestriction>) objectInputStream.readObject(); + + /** For later backwards compatibility, to add more stuff */ + objectInputStream.readObject(); + } + + /** + * Copies integers into another VSPrefs object. + * + * @param copyInto the copy into + * @param keys the keys + */ + public void copyIntegers(VSPrefs copyInto, String[] keys) { + for (String key : keys) + copyInto.initInteger(key, + getInteger(key), + getDescription(INTEGER_PREFIX + key), + (VSPrefsRestriction.VSIntegerPrefsRestriction) + getRestriction(INTEGER_PREFIX + key), + getUnit(INTEGER_PREFIX + key)); + } + + /** + * Copies longs into another VSPrefs object. + * + * @param copyInto the copy into + * @param keys the keys + */ + public void copyLongs(VSPrefs copyInto, String[] keys) { + for (String key : keys) + copyInto.initLong(key, getLong(key), + getDescription(LONG_PREFIX + key), + getUnit(LONG_PREFIX + key)); + } + + /** + * Copies floats into another VSPrefs object. + * + * @param copyInto the copy into + * @param keys the keys + */ + public void copyFloats(VSPrefs copyInto, String[] keys) { + for (String key : keys) + copyInto.initFloat(key, getFloat(key), + getDescription(FLOAT_PREFIX + key), + getUnit(FLOAT_PREFIX + key)); + } + + /** + * Copies strings into another VSPrefs object. + * + * @param copyInto the copy into + * @param keys the keys + */ + public void copyStrings(VSPrefs copyInto, String[] keys) { + for (String key : keys) + copyInto.initString(key, getString(key), + getDescription(STRING_PREFIX + key)); + } + + /** + * Copies color references into another VSPrefs object. + * + * @param copyInto the copy into + * @param keys the keys + */ + public void copyColors(VSPrefs copyInto, String[] keys) { + for (String key : keys) { + Color color = getColor(key); + float comp[] = color.getComponents(null); + copyInto.initColor(key, new Color(comp[0], comp[1], comp[2]), + getDescription(COLOR_PREFIX + key)); + } + } + + /** + * Copies colors. + * + * @param copyInto the copy into + * @param keys the keys + */ + public void copyBooleans(VSPrefs copyInto, String[] keys) { + for (String key : keys) + copyInto.initBoolean(key, getBoolean(key), + getDescription(BOOLEAN_PREFIX + key)); + } + + /* (non-Javadoc) + * @see java.lang.Object#toString() + */ + public String toString() { + String descr = ""; + + Set<String> set = null; + + set = getIntegerKeySet(); + if (set.size() > 0) { + descr += INTEGER_PREFIX; + for (String key : set) + descr += key + "=" + getInteger(key) + "; "; + } + + set = getVectorKeySet(); + if (set.size() > 0) { + descr += VECTOR_PREFIX; + for (String key : set) + descr += key + "=" + getVector(key) + "; "; + } + + set = getLongKeySet(); + if (set.size() > 0) { + descr += LONG_PREFIX; + for (String key : set) + descr += key + "=" + getLong(key) + "; "; + } + + set = getFloatKeySet(); + if (set.size() > 0) { + descr += FLOAT_PREFIX; + for (String key : set) + descr += key + "=" + getFloat(key) + "; "; + } + + set = getBooleanKeySet(); + if (set.size() > 0) { + descr += BOOLEAN_PREFIX; + for (String key : set) + descr += key + "=" + getBoolean(key) + "; "; + } + + set = getStringKeySet(); + if (set.size() > 0) { + descr += STRING_PREFIX; + for (String key : set) + descr += key + "=" + getString(key) + "; "; + } + + if (descr.endsWith("; ")) + return descr.substring(0, descr.length() - 2); + + return descr; + } + + /** + * Gets the iD. + * + * @return the iD + */ + public int getID() { + return id; + } + + /** + * Checks if the prefs are empty. + * + * @return true, if empty + */ + public boolean isEmpty() { + if (!colorPrefs.isEmpty()) + return false; + + if (!floatPrefs.isEmpty()) + return false; + + if (!integerPrefs.isEmpty()) + return false; + + if (!vectorPrefs.isEmpty()) + return false; + + if (!longPrefs.isEmpty()) + return false; + + if (!stringPrefs.isEmpty()) + return false; + + if (!booleanPrefs.isEmpty()) + return false; + + return true; + } + + /** + * Returns all full keys. + * + * @return All full keys + */ + public ArrayList<String> getAllFullKeys() { + ArrayList<String> allKeys = new ArrayList<String>(); + + Set<String> set = null; + + set = getIntegerKeySet(); + for (String key : set) + allKeys.add(INTEGER_PREFIX + key); + + set = getVectorKeySet(); + for (String key : set) + allKeys.add(VECTOR_PREFIX + key); + + set = getLongKeySet(); + for (String key : set) + allKeys.add(LONG_PREFIX + key); + + set = getFloatKeySet(); + for (String key : set) + allKeys.add(FLOAT_PREFIX + key); + + set = getBooleanKeySet(); + for (String key : set) + allKeys.add(BOOLEAN_PREFIX + key); + + set = getStringKeySet(); + for (String key : set) + allKeys.add(STRING_PREFIX + key); + + Collections.sort(allKeys); + + return allKeys; + } +} diff --git a/src/main/java/prefs/VSPrefsRestriction.java b/src/main/java/prefs/VSPrefsRestriction.java new file mode 100644 index 0000000..27e828d --- /dev/null +++ b/src/main/java/prefs/VSPrefsRestriction.java @@ -0,0 +1,137 @@ +package prefs; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.util.Vector; + +/** + * The class VSPrefsRestriction. + */ +abstract public class VSPrefsRestriction implements Serializable { + private static final long serialVersionUID = 2L; + + /** + * The class VSIntegerPrefsRestriction. + */ + public static class VSIntegerPrefsRestriction extends VSPrefsRestriction { + private static final long serialVersionUID = 2L; + /** The min value. */ + private int minValue; + + /** The max value. */ + private int maxValue; + + /** + * Instantiates a new integer setting restriction. + * + * @param minValue the min value + * @param maxValue the max value + */ + public VSIntegerPrefsRestriction(int minValue, int maxValue) { + this.minValue = minValue; + this.maxValue = maxValue; + } + + /** + * Gets the min value. + * + * @return the min value + */ + public int getMinValue() { + return minValue; + } + + /** + * Gets the max value. + * + * @return the max value + */ + public int getMaxValue() { + return maxValue; + } + + /* (non-Javadoc) + * @see prefs.VSPrefsRestriction#writeObject(java.io.ObjectOutputStream) + */ + public void writeObject(ObjectOutputStream out) + throws IOException { + out.writeObject(Integer.valueOf(minValue)); + out.writeObject(Integer.valueOf(maxValue)); + } + + /* (non-Javadoc) + * @see prefs.VSPrefsRestriction#readObject(java.io.ObjectInputStream) + */ + public void readObject(ObjectInputStream in) + throws IOException, ClassNotFoundException { + minValue = ((Integer) in.readObject()).intValue(); + maxValue = ((Integer) in.readObject()).intValue(); + } + } + + /** + * The class VSStringPrefsRestriction. + */ + public static class VSStringPrefsRestriction extends VSPrefsRestriction { + private static final long serialVersionUID = 2L; + + /** The possible selections. */ + Vector<String> possibleSelections; + + /** + * Instantiates a new string setting restriction. + * + * @param possibleSelections the possible selections + */ + public VSStringPrefsRestriction(String [] possibleSelections) { + this.possibleSelections = new Vector<String>(); + + for (String elem : possibleSelections) + this.possibleSelections.add(elem); + } + + /** + * Gets the possible selections. + * + * @return the possible selections + */ + public Vector<String> getPossibleSelections() { + return possibleSelections; + } + + /* (non-Javadoc) + * @see prefs.VSPrefsRestriction#writeObject(java.io.ObjectOutputStream) + */ + public void writeObject(ObjectOutputStream out) + throws IOException { + out.writeObject(possibleSelections); + } + + /* (non-Javadoc) + * @see prefs.VSPrefsRestriction#readObject(java.io.ObjectInputStream) + */ + @SuppressWarnings("unchecked") + public void readObject(ObjectInputStream in) + throws IOException, ClassNotFoundException { + possibleSelections = (Vector<String>) in.readObject(); + } + } + + /** + * Serializes the object. + * + * @param out The output stream + */ + abstract public void writeObject(ObjectOutputStream out) + throws IOException; + + /** + * Deserializes the object. + * + * @param in The input stream + */ + abstract public void readObject(ObjectInputStream in) + throws IOException, ClassNotFoundException; +} diff --git a/src/main/java/prefs/VSSerializablePrefs.java b/src/main/java/prefs/VSSerializablePrefs.java new file mode 100644 index 0000000..b175b41 --- /dev/null +++ b/src/main/java/prefs/VSSerializablePrefs.java @@ -0,0 +1,37 @@ +package prefs; + +//import java.util.*; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; + +import serialize.VSSerializable; +import serialize.VSSerialize; + +/** + * The class VSSerializablePrefs, this class is used if the VSPrefs should + * be serializable. + * + * @author Paul C. Buetow + */ +public class VSSerializablePrefs extends VSPrefs implements VSSerializable { + /* (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); + } + + /* (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); + } +} diff --git a/src/main/java/prefs/editors/VSAbstractBetterEditor.java b/src/main/java/prefs/editors/VSAbstractBetterEditor.java new file mode 100644 index 0000000..87296b6 --- /dev/null +++ b/src/main/java/prefs/editors/VSAbstractBetterEditor.java @@ -0,0 +1,101 @@ +package prefs.editors; + +import java.awt.Color; +import java.awt.Container; +import java.awt.event.ActionEvent; + +import javax.swing.BoxLayout; +import javax.swing.JPanel; + +import prefs.VSPrefs; + +/** + * The class VSAbstractBetterEditor, is an improved VSAbstractEditor. + * + * @author Paul C. Buetow + */ +public abstract class VSAbstractBetterEditor extends VSAbstractEditor { + /** The content pane. */ + private Container contentPane; + + /** The title. */ + private String title; + + /** + * An simple constructor. + * + * @param prefs the prefs + * @param prefsToEdit the prefs to edit + * @param title the title + */ + public VSAbstractBetterEditor(VSPrefs prefs, VSPrefs prefsToEdit, + String title) { + super(prefs, prefsToEdit); + this.title = title; + this.contentPane = createContentPane(); + } + + /** + * Gets the title. + * + * @return the title + */ + public String getTitle() { + return title; + } + + /** + * Gets the content pane. + * + * @return the content pane + */ + public Container getContentPane() { + contentPane.setBackground(Color.WHITE); + return contentPane; + } + + /** + * Creates the content pane. + * + * @return the j panel + */ + private JPanel createContentPane() { + JPanel panel = new JPanel(); + panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS)); + + JPanel editPanel = getEditPanel(); + JPanel buttonPanel = getButtonPanel(); + + panel.add(editPanel); + panel.add(buttonPanel); + + return panel; + } + + /* (non-Javadoc) + * @see prefs.editors.VSAbstractEditor#addToButtonPanelFront( + * javax.swing.JPanel) + */ + protected void addToButtonPanelFront(JPanel buttonPanel) { } + + /* (non-Javadoc) + * @see prefs.editors.VSAbstractEditor#addToButtonPanelLast( + * javax.swing.JPanel) + */ + protected void addToButtonPanelLast(JPanel buttonPanel) { } + + /* (non-Javadoc) + * @see prefs.editors.VSAbstractEditor#addToEditTableLast() + */ + protected void addToEditTableLast() { } + + /* (non-Javadoc) + * @see prefs.editors.VSAbstractEditor#actionPerformed( + * java.awt.event.ActionEvent) + */ + public void actionPerformed(ActionEvent e) { + //String actionCommand = e.getActionCommand(); + /* More action in the super class!!! */ + super.actionPerformed(e); + } +} diff --git a/src/main/java/prefs/editors/VSAbstractEditor.java b/src/main/java/prefs/editors/VSAbstractEditor.java new file mode 100644 index 0000000..266b62c --- /dev/null +++ b/src/main/java/prefs/editors/VSAbstractEditor.java @@ -0,0 +1,1056 @@ +package prefs.editors; + +import java.awt.Color; +import java.awt.Component; +import java.awt.GridBagLayout; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.Set; +import java.util.Vector; + +import javax.swing.BoxLayout; +import javax.swing.JButton; +import javax.swing.JCheckBox; +import javax.swing.JComboBox; +import javax.swing.JComponent; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JTextField; + +import prefs.VSPrefs; +import prefs.VSPrefsRestriction; +import utils.VS3Tupel; +import utils.VSFrame; + +/** + * The class VSAbstractEditor, an object of this class is used in order to + * edit a VSPrefs object. + * + * @author Paul C. Buetow + */ +public abstract class VSAbstractEditor implements ActionListener { + /** The boolean keys. */ + private ArrayList<String> booleanKeys; + + /** The color keys. */ + private ArrayList<String> colorKeys; + + /** The float keys. */ + private ArrayList<String> floatKeys; + + /** The integer keys. */ + private ArrayList<String> integerKeys; + + /** The vector keys. */ + private ArrayList<String> vectorKeys; + + /** The long keys. */ + private ArrayList<String> longKeys; + + /** The string keys. */ + private ArrayList<String> stringKeys; + + /** The boolean fields. */ + private HashMap<String,JCheckBox> booleanFields; + + /** The integer fields. */ + private HashMap<String,JComboBox<Integer>> integerFields; + + /** The vector fields. */ + private HashMap<String,JTextField> vectorFields; + + /** The color fields. */ + private HashMap<String,JTextField> colorFields; + + /** The float fields. */ + private HashMap<String,JTextField> floatFields; + + /** The long fields. */ + private HashMap<String,JTextField> longFields; + + /** The string fields. */ + private HashMap<String,JTextField> stringFields; + + /** The prefs to edit map. */ + private HashMap<String,VSPrefs> prefsToEditMap; + + /** The button panel. */ + private JPanel buttonPanel; + + /** The edit panel. */ + private JPanel editPanel; + + /** The edit table. */ + private VSEditorTable editTable; + + /** The frame. */ + private VSFrame frame; + + /** The expert mode changed. */ + private boolean expertModeChanged; + + /** The prefs. */ + protected VSPrefs prefs; + + /** The prefs to edit. */ + protected VSPrefs prefsToEdit; + + /** The Constant MIN_UNIT_LENGTH. */ + protected static final int MIN_UNIT_LENGTH = 5; + + /** The Constant VALUE_FIELD_COLS. */ + protected static final int VALUE_FIELD_COLS = 9; + + /** The Constant ALL_PREFERENCES. */ + public static final int ALL_PREFERENCES = 0; + + /** The Constant SIMULATION_PREFERENCES. */ + public static final int SIMULATION_PREFERENCES = 1; + + /** + * The standard constructor. + * + * @param prefs the prefs + * @param prefsToEdit the prefs to edit + */ + public VSAbstractEditor(VSPrefs prefs, VSPrefs prefsToEdit) { + init(prefs, prefsToEdit); + } + + /** + * Adds components to the front of the button panel . + * + * @param buttonPanel the button panel + */ + abstract protected void addToButtonPanelFront(JPanel buttonPanel); + + /** + * Adds components to last of the button panel. + * + * @param buttonPanel the button panel + */ + abstract protected void addToButtonPanelLast(JPanel buttonPanel); + + /** + * Adds the to edit table last. + */ + abstract protected void addToEditTableLast(); + + /** + * Sets the default prefs. + * + * @param prefs the new prefs + */ + public void setPrefs(VSPrefs prefs) { + this.prefs = prefs; + } + + /** + * Sets the prefs to edit. + * + * @param prefsToEdit the new prefs to edit + */ + public void setPrefsToEdit(VSPrefs prefsToEdit) { + this.prefsToEdit = prefsToEdit; + } + + /** + * Sets the frame being used by the editor, if any. + * + * @param frame the new frame + */ + public void setFrame(VSFrame frame) { + this.frame = frame; + } + + /** + * Gets the frame. + * + * @return the frame + */ + public VSFrame getFrame() { + return frame; + } + + /** + * The given editors frame will get disposed if the "OK" button has been + * pressed. This can only happen if the editor has its own frame. + */ + protected void disposeFrameIfExists() { + if (frame != null) + frame.dispose(); + } + + /** + * The given editors frame will get disposed if its parent component + * disposes. This can only happen if the editor has its own frame. + */ + protected void disposeFrameWithParentIfExists() { + if (frame != null) + frame.disposeWithParent(); + } + + /** + * Inits the editor. + * + * @param prefs the prefs + * @param prefsToEdit the prefs to edit + */ + private void init(VSPrefs prefs, VSPrefs prefsToEdit) { + this.prefs = prefs; + this.prefsToEdit = prefsToEdit; + + editPanel = createEditPanel(); + buttonPanel = createButtonPanel(); + + prefsToEditMap = new HashMap<String,VSPrefs>(); + + colorFields = new HashMap<String,JTextField>(); + floatFields = new HashMap<String,JTextField>(); + integerFields = new HashMap<String,JComboBox<Integer>>(); + vectorFields = new HashMap<String,JTextField>(); + longFields = new HashMap<String,JTextField>(); + booleanFields = new HashMap<String,JCheckBox>(); + stringFields = new HashMap<String,JTextField>(); + + colorKeys = filterKeys(prefsToEdit.getColorKeySet()); + floatKeys = filterKeys(prefsToEdit.getFloatKeySet()); + integerKeys = filterKeys(prefsToEdit.getIntegerKeySet()); + vectorKeys = filterKeys(prefsToEdit.getVectorKeySet()); + longKeys = filterKeys(prefsToEdit.getLongKeySet()); + booleanKeys = filterKeys(prefsToEdit.getBooleanKeySet()); + stringKeys = filterKeys(prefsToEdit.getStringKeySet()); + + fillEditPanelFront(prefsToEdit); + fillEditPanel(prefsToEdit); + } + + /** + * Filters out all keys to edit. + * + * @param set the set which contains all keys of a given hash + * + * @return the filtered keys + */ + private ArrayList<String> filterKeys(Set<String> set) { + ArrayList<String> filtered = new ArrayList<String>(); + boolean expertMode = prefs.getBoolean("sim.mode.expert"); + + for (String elem : set) { + if (!elem.startsWith("lang.") && !elem.startsWith("keyevent.")) { + if (expertMode) + filtered.add(elem); + else if (!elem.startsWith("col.") && (!elem.startsWith("div."))) + filtered.add(elem); + } + } + + return filtered; + } + + /** + * Creates the button panel. + * + * @return the panel + */ + private JPanel createButtonPanel() { + JPanel buttonPanel = new JPanel(); + buttonPanel.setBackground(Color.WHITE); + addToButtonPanelFront(buttonPanel); + + JButton resetButton = new JButton( + prefs.getString("lang.reset")); + resetButton.setMnemonic(prefs.getInteger("keyevent.reset")); + resetButton.addActionListener(this); + buttonPanel.add(resetButton); + + addToButtonPanelLast(buttonPanel); + + return buttonPanel; + } + + /** + * Creates the unit panel. + * + * @param comp the comp + * @param key the key + * + * @return the panel + */ + private JPanel createUnitPanel(VSPrefs prefsToEdit, Component comp, + String fullKey) { + JPanel unitPanel = new JPanel(new GridBagLayout()); + unitPanel.setBackground(Color.WHITE); + unitPanel.setBorder(null); + + String unitText = prefsToEdit.getUnit(fullKey); + if (unitText == null) + unitText = ""; + + unitText = " " + unitText; + while (unitText.length() < MIN_UNIT_LENGTH) + unitText = unitText + " "; + JLabel unitLabel = new JLabel(unitText); + + unitPanel.setLayout(new BoxLayout(unitPanel, BoxLayout.X_AXIS)); + unitPanel.add(comp); + unitPanel.add(unitLabel); + + return unitPanel; + } + + /** + * Creates the edit panel. + * + * @return the panel + */ + private JPanel createEditPanel() { + JPanel editPanel = new JPanel(); + editPanel.setLayout(new BoxLayout(editPanel, BoxLayout.Y_AXIS)); + editPanel.setBackground(Color.WHITE); + + editTable = new VSEditorTable(prefs); + JScrollPane scrollPane = new JScrollPane(editTable); + editPanel.add(scrollPane); + + return editPanel; + } + + /** + * Creates the integer component. + * + * @param fullKey the full key + * @param key the key + * @param prefsToEdit the prefs to edit + * + * @return the tupel representing the component + */ + protected VS3Tupel<String,Component,JComboBox<Integer>> createIntegerComponent( + String fullKey, String key, VSPrefs prefsToEdit) { + String descr = prefs.getDescription(fullKey); + if (descr == null) + descr = prefsToEdit.getDescription(fullKey); + String label = descr == null ? fullKey : descr; + Integer integer = prefsToEdit.getInteger(key); + Integer initialSelection[] = { integer }; + JComboBox<Integer> valComboBox = new JComboBox<>(initialSelection); + VSPrefsRestriction settingRestriction = + prefsToEdit.getRestriction(fullKey); + + int minValue, maxValue; + if (settingRestriction != null) { + VSPrefsRestriction.VSIntegerPrefsRestriction + integerVSPrefsRestriction = + (VSPrefsRestriction.VSIntegerPrefsRestriction) + settingRestriction; + minValue = integerVSPrefsRestriction.getMinValue(); + maxValue = integerVSPrefsRestriction.getMaxValue(); + + } else { + minValue = 0; + maxValue = 100; + } + + for (int i = minValue; i <= maxValue; ++i) + valComboBox.addItem(Integer.valueOf(i)); + valComboBox.setBorder(null); + + return new VS3Tupel<String,Component,JComboBox<Integer>>(label, + createUnitPanel(prefsToEdit, valComboBox, fullKey), + valComboBox); + } + + /** + * Creates the vector component. + * + * @param fullKey the full key + * @param key the key + * @param prefsToEdit the prefs to edit + * + * @return the tupel representing the component + */ + protected VS3Tupel<String,Component,JTextField> createVectorComponent( + String fullKey, String key, VSPrefs prefsToEdit) { + String descr = prefs.getDescription(fullKey); + if (descr == null) + descr = prefsToEdit.getDescription(fullKey); + String label = descr == null ? fullKey : descr; + + Vector<Integer> vec = prefsToEdit.getVector(key); + JTextField valField = new JTextField(); + valField.setBorder(null); + valField.setText(vec.toString()); + + return new VS3Tupel<String,Component,JTextField>(label, + createUnitPanel(prefsToEdit, valField, fullKey), valField); + } + + /** + * Creates the boolean component. + * + * @param fullKey the full key + * @param key the key + * @param prefsToEdit the prefs to edit + */ + protected VS3Tupel<String,Component,JCheckBox> createBooleanComponent( + String fullKey, String key, VSPrefs prefsToEdit) { + final String activated = prefs.getString("lang.activated"); + String descr = prefs.getDescription(fullKey); + if (descr == null) + descr = prefsToEdit.getDescription(fullKey); + String label = descr == null ? fullKey : descr; + JCheckBox valField = new JCheckBox(activated, + prefsToEdit.getBoolean(key)); + valField.setBackground(Color.WHITE); + valField.setBorder(null); + return new VS3Tupel<String,Component,JCheckBox>(label, + createUnitPanel(prefsToEdit, valField, fullKey), valField); + } + + /** + * Creates the long component. + * + * @param fullKey the full key + * @param key the key + * @param prefsToEdit the prefs to edit + * + * @return the tupel representing the component + */ + protected VS3Tupel<String,Component,JTextField> createLongComponent( + String fullKey, String key, VSPrefs prefsToEdit) { + String descr = prefs.getDescription(fullKey); + if (descr == null) + descr = prefsToEdit.getDescription(fullKey); + String label = descr == null ? fullKey : descr; + JTextField valField = new JTextField(VALUE_FIELD_COLS); + valField.addKeyListener(new java.awt.event.KeyAdapter() { + public void keyTyped(java.awt.event.KeyEvent e) { + JTextField valField = (JTextField)e.getSource(); + if (valField.getText().length() >= valField.getColumns() + 10) + e.consume(); + } + }); + valField.setText(""+prefsToEdit.getLong(key)); + valField.setBorder(null); + return new VS3Tupel<String,Component,JTextField>(label, + createUnitPanel(prefsToEdit, valField, fullKey), valField); + } + + /** + * Creates the float component. + * + * @param fullKey the full key + * @param key the key + * @param prefsToEdit the prefs to edit + * + * @return the tupel representing the component + */ + protected VS3Tupel<String,Component,JTextField> createFloatComponent( + String fullKey, String key, VSPrefs prefsToEdit) { + String descr = prefs.getDescription(fullKey); + if (descr == null) + descr = prefsToEdit.getDescription(fullKey); + String label = descr == null ? fullKey : descr; + JTextField valField = new JTextField(VALUE_FIELD_COLS); + valField.addKeyListener(new java.awt.event.KeyAdapter() { + public void keyTyped(java.awt.event.KeyEvent e) { + JTextField valField = (JTextField)e.getSource(); + if (valField.getText().length() >= valField.getColumns() + 10) + e.consume(); + } + }); + valField.setText(""+prefsToEdit.getFloat(key)); + valField.setBorder(null); + return new VS3Tupel<String,Component,JTextField>(label, + createUnitPanel(prefsToEdit, valField, fullKey), valField); + } + + /** + * Creates the color component. + * + * @param fullKey the full key + * @param key the key + * @param prefsToEdit the prefs to edit + * + * @return the tupel representing the component + */ + protected VS3Tupel<String,Component,JTextField> createColorComponent( + String fullKey, String key, final VSPrefs prefsToEdit) { + String descr = prefs.getDescription(fullKey); + if (descr == null) + descr = prefsToEdit.getDescription(fullKey); + String label = descr == null ? fullKey : descr; + final JTextField valField = new JTextField(VALUE_FIELD_COLS); + Color color = prefsToEdit.getColor(key); + valField.setBackground(color); + valField.setEditable(false); + valField.addMouseListener(new MouseListener() { + public void mouseExited(MouseEvent e) { } + public void mouseReleased(MouseEvent e) { } + public void mouseEntered(MouseEvent e) { } + public void mousePressed(MouseEvent e) { } + public void mouseClicked(MouseEvent e) { + JFrame parentFrame = getFrame(); + JFrame frame = new VSFrame( + prefs.getString("lang.name") + " - " + + prefs.getString( + "lang.colorchooser"),parentFrame); + frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + + JComponent colorChooserPane = new VSColorChooser(prefs, + valField); + colorChooserPane.setOpaque(true); + + frame.setContentPane(colorChooserPane); + frame.pack(); + frame.setVisible(true); + } + }); + valField.setBorder(null); + return new VS3Tupel<String,Component,JTextField>(label, + createUnitPanel(prefsToEdit, valField, fullKey), valField); + } + + /** + * Creates the string component. + * + * @param fullKey the full key + * @param key the key + * @param prefsToEdit the prefs to edit + * + * @return the tupel representing the component + */ + protected VS3Tupel<String,Component,JTextField> createStringComponent( + String fullKey, String key, VSPrefs prefsToEdit) { + String descr = prefs.getDescription(fullKey); + if (descr == null) + descr = prefsToEdit.getDescription(fullKey); + String label = descr == null ? fullKey : descr; + JTextField valField = new JTextField(VALUE_FIELD_COLS); + valField.addKeyListener(new java.awt.event.KeyAdapter() { + public void keyTyped(java.awt.event.KeyEvent e) { + JTextField valField = (JTextField)e.getSource(); + if (valField.getText().length() >= valField.getColumns() + 10) + e.consume(); + } + }); + valField.setText(prefsToEdit.getString(key)); + valField.setBorder(null); + return new VS3Tupel<String,Component,JTextField>(label, + createUnitPanel(prefsToEdit, valField, fullKey), valField); + } + + /** + * Fills the edit panel at the front. May be overloaded by another class. + * + * @param prefsToEdit the prefs to edit + */ + protected void fillEditPanelFront(VSPrefs prefsToEdit) { + } + + /** + * Fills the edit panel. + * + * @param prefsToEdit the prefs to edit + */ + private void fillEditPanel(VSPrefs prefsToEdit) { + HashMap<String,Component> components = new HashMap<String,Component>(); + HashMap<String,String> labels = new HashMap<String,String>(); + + for (String key : integerKeys) { + String fullKey = VSPrefs.INTEGER_PREFIX + key; + VS3Tupel<String,Component,JComboBox<Integer>> tupel = + createIntegerComponent(fullKey, key, prefsToEdit); + labels.put(fullKey, tupel.getA()); + components.put(fullKey, tupel.getB()); + integerFields.put(key, tupel.getC()); + } + + for (String key : vectorKeys) { + String fullKey = VSPrefs.VECTOR_PREFIX + key; + VS3Tupel<String,Component,JTextField> tupel = + createVectorComponent(fullKey, key, prefsToEdit); + labels.put(fullKey, tupel.getA()); + components.put(fullKey, tupel.getB()); + vectorFields.put(key, tupel.getC()); + } + + for (String key : booleanKeys) { + String fullKey = VSPrefs.BOOLEAN_PREFIX + key; + VS3Tupel<String,Component,JCheckBox> tupel = + createBooleanComponent(fullKey, key, prefsToEdit); + labels.put(fullKey, tupel.getA()); + components.put(fullKey, tupel.getB()); + booleanFields.put(key, tupel.getC()); + } + + for (String key : longKeys) { + String fullKey = VSPrefs.LONG_PREFIX + key; + VS3Tupel<String,Component,JTextField> tupel = + createLongComponent(fullKey, key, prefsToEdit); + labels.put(fullKey, tupel.getA()); + components.put(fullKey, tupel.getB()); + longFields.put(key, tupel.getC()); + } + + + for (String key : floatKeys) { + String fullKey = VSPrefs.FLOAT_PREFIX + key; + VS3Tupel<String,Component,JTextField> tupel = + createFloatComponent(fullKey, key, prefsToEdit); + labels.put(fullKey, tupel.getA()); + components.put(fullKey, tupel.getB()); + floatFields.put(key, tupel.getC()); + } + + + for (String key : colorKeys) { + String fullKey = VSPrefs.COLOR_PREFIX + key; + VS3Tupel<String,Component,JTextField> tupel = + createColorComponent(fullKey, key, prefsToEdit); + labels.put(fullKey, tupel.getA()); + components.put(fullKey, tupel.getB()); + colorFields.put(key, tupel.getC()); + } + + for (String key : stringKeys) { + String fullKey = VSPrefs.STRING_PREFIX + key; + VS3Tupel<String,Component,JTextField> tupel = + createStringComponent(fullKey, key, prefsToEdit); + labels.put(fullKey, tupel.getA()); + components.put(fullKey, tupel.getB()); + stringFields.put(key, tupel.getC()); + } + + ArrayList<String> fullKeys = new ArrayList<String>(); + fullKeys.addAll(components.keySet()); + Collections.sort(fullKeys); + + boolean flag = false; + for (String fullKey : fullKeys) { + String key = fullKey.substring(fullKey.indexOf(' ')+1); + if (key.startsWith("sim.")) { + if (!flag) { + flag = true; + addSeparator(prefs.getString("lang.prefs.simulator")); + } + addVariable(labels.get(fullKey), components.get(fullKey), + prefsToEdit); + } + } + + flag = false; + for (String fullKey : fullKeys) { + String key = fullKey.substring(fullKey.indexOf(' ')+1); + if (key.startsWith("process.")) { + if (!flag) { + flag = true; + if (this instanceof VSProcessEditor) + addSeparator(prefs.getString("lang.prefs.process")); + else + addSeparator(prefs.getString( + "lang.prefs.process.defaults")); + } + addVariable(labels.get(fullKey), components.get(fullKey), + prefsToEdit); + } + } + + flag = false; + for (String fullKey : fullKeys) { + String key = fullKey.substring(fullKey.indexOf(' ')+1); + if (key.startsWith("message.")) { + if (!flag) { + flag = true; + if (this instanceof VSProcessEditor) + addSeparator(prefs.getString( + "lang.prefs.message")); + else + addSeparator(prefs.getString( + "lang.prefs.message.defaults")); + } + addVariable(labels.get(fullKey), components.get(fullKey), + prefsToEdit); + } + } + + flag = false; + for (String fullKey : fullKeys) { + String key = fullKey.substring(fullKey.indexOf(' ')+1); + if (key.startsWith("col.")) { + if (!flag) { + flag = true; + addSeparator(prefs.getString("lang.prefs.color")); + } + addVariable(labels.get(fullKey), components.get(fullKey), + prefsToEdit); + } + } + + flag = false; + for (String fullKey : fullKeys) { + String key = fullKey.substring(fullKey.indexOf(' ')+1); + if (key.startsWith("div.")) { + if (!flag) { + flag = true; + addSeparator(prefs.getString("lang.prefs.diverse")); + } + addVariable(labels.get(fullKey), components.get(fullKey), + prefsToEdit); + } + } + + addToEditTableLast(); + editTable.fireTableDataChanged(); + } + + /** + * Filters out stuff. + * + * @param set The set to filter stuff out from + * @param filter Only return elemens of the filter which are in the set + * @param prefix The prefix to use + * + * @return The filtered keys + */ + private ArrayList<String> filterOut(Set<String> set, + ArrayList<String> filter, + String prefix) { + ArrayList<String> ret = new ArrayList<String>(); + + for (String key : set) { + String fullKey = prefix + key; + if (filter.contains(fullKey)) + ret.add(fullKey); + } + + return ret; + } + + /** + * Adds the to editor more variables. + * + * @param label the label + * @param prefsKey the prefs key + * @param prefsToAdd the prefs to add + * @param addOnlyThisVariables only add variables which are in this list + */ + protected void addToEditor(String label, String prefsKey, + VSPrefs prefsToAdd, + ArrayList<String> addOnlyThisVariables) { + addSeparator(label); + prefsKey = "(" + prefsKey + ")"; + + ArrayList<String> fullKeys = new ArrayList<String>(); + + fullKeys.addAll(filterOut(prefsToAdd.getIntegerKeySet(), + addOnlyThisVariables, + VSPrefs.INTEGER_PREFIX)); + fullKeys.addAll(filterOut(prefsToAdd.getVectorKeySet(), + addOnlyThisVariables, + VSPrefs.VECTOR_PREFIX)); + fullKeys.addAll(filterOut(prefsToAdd.getFloatKeySet(), + addOnlyThisVariables, + VSPrefs.FLOAT_PREFIX)); + fullKeys.addAll(filterOut(prefsToAdd.getLongKeySet(), + addOnlyThisVariables, + VSPrefs.LONG_PREFIX)); + fullKeys.addAll(filterOut(prefsToAdd.getBooleanKeySet(), + addOnlyThisVariables, + VSPrefs.BOOLEAN_PREFIX)); + fullKeys.addAll(filterOut(prefsToAdd.getStringKeySet(), + addOnlyThisVariables, + VSPrefs.STRING_PREFIX)); + + Collections.sort(fullKeys); + + for (String fullKey : fullKeys) { + String key = fullKey.substring(fullKey.indexOf(": ") + 2); + if (fullKey.startsWith(VSPrefs.INTEGER_PREFIX)) { + VS3Tupel<String,Component,JComboBox<Integer>> tupel = + createIntegerComponent(fullKey, key, prefsToAdd); + this.integerKeys.add(prefsKey+key); + this.integerFields.put(prefsKey+key, tupel.getC()); + addVariable(prefsKey, tupel.getA(), tupel.getB(), prefsToAdd); + + } else if (fullKey.startsWith(VSPrefs.VECTOR_PREFIX)) { + VS3Tupel<String,Component,JTextField> tupel = + createVectorComponent(fullKey, key, prefsToAdd); + this.vectorKeys.add(prefsKey+key); + this.vectorFields.put(prefsKey+key, tupel.getC()); + addVariable(prefsKey, tupel.getA(), tupel.getB(), prefsToAdd); + + } else if (fullKey.startsWith(VSPrefs.BOOLEAN_PREFIX)) { + VS3Tupel<String,Component,JCheckBox> tupel = + createBooleanComponent(fullKey, key, prefsToAdd); + this.booleanKeys.add(prefsKey + key); + this.booleanFields.put(prefsKey+key, tupel.getC()); + addVariable(prefsKey, tupel.getA(), tupel.getB(), prefsToAdd); + + } else if (fullKey.startsWith(VSPrefs.LONG_PREFIX)) { + VS3Tupel<String,Component,JTextField> tupel = + createLongComponent(fullKey, key, prefsToAdd); + this.longKeys.add(prefsKey+key); + this.longFields.put(prefsKey+key, tupel.getC()); + addVariable(prefsKey, tupel.getA(), tupel.getB(), prefsToAdd); + + } else if (fullKey.startsWith(VSPrefs.FLOAT_PREFIX)) { + VS3Tupel<String,Component,JTextField> tupel = + createFloatComponent(fullKey, key, prefsToAdd); + this.floatKeys.add(prefsKey + key); + this.floatFields.put(prefsKey+key, tupel.getC()); + addVariable(prefsKey, tupel.getA(), tupel.getB(), prefsToAdd); + + } else if (fullKey.startsWith(VSPrefs.STRING_PREFIX)) { + VS3Tupel<String,Component,JTextField> tupel = + createStringComponent(fullKey, key, prefsToAdd); + this.stringKeys.add(prefsKey + key); + this.stringFields.put(prefsKey+key, tupel.getC()); + addVariable(prefsKey, tupel.getA(), tupel.getB(), prefsToAdd); + } + } + } + + /** + * Adds a separator. + * + * @param label the label + */ + protected void addSeparator(String label) { + editTable.addSeparator(label); + } + + /** + * Adds a variable. + * + * @param label the label + * @param component the component + * @param prefs the prefs + */ + private void addVariable(String label, Component component, VSPrefs prefs) { + addVariable("", label, component, prefs); + } + + /** + * Adds a variable. + * + * @param prefsKey the prefs key + * @param label the label + * @param component the component + * @param prefs the prefs + */ + private void addVariable(String prefsKey, String label, + Component component, VSPrefs prefs) { + prefsToEditMap.put(prefsKey, prefs); + editTable.addVariable(label, component); + } + + /** + * Reset edit panel. + */ + protected void resetPrefs() { + for (String key : integerKeys) { + JComboBox<Integer> valComboBox = integerFields.get(key); + valComboBox.setSelectedIndex(0); + } + + for (String key : booleanKeys) { + String keys[] = getKeys(key); + JCheckBox valField = booleanFields.get(key); + valField.setSelected(prefsToEditMap.get( + keys[1]).getBoolean(keys[0])); + } + + for (String key : vectorKeys) { + String keys[] = getKeys(key); + JTextField valField = vectorFields.get(key); + valField.setText(""+prefsToEditMap.get(keys[1]).getVector(keys[0])); + } + + for (String key : floatKeys) { + String keys[] = getKeys(key); + JTextField valField = floatFields.get(key); + valField.setText(""+prefsToEditMap.get(keys[1]).getFloat(keys[0])); + } + + for (String key : longKeys) { + String keys[] = getKeys(key); + JTextField valField = longFields.get(key); + valField.setText(""+prefsToEditMap.get(keys[1]).getLong(keys[0])); + } + + for (String key : colorKeys) { + String keys[] = getKeys(key); + JTextField valField = colorFields.get(key); + valField.setBackground(prefsToEditMap.get( + keys[1]).getColor(keys[0])); + } + + for (String key : stringKeys) { + String keys[] = getKeys(key); + JTextField valField = stringFields.get(key); + valField.setText(prefsToEditMap.get(keys[1]).getString(keys[0])); + } + } + + /** + * Gets the keys. + * + * @param key the key + * + * @return [0] := key, [1] := prefsKey + */ + private String[] getKeys(String key) { + String keys[] = { key, "" }; + + if (key.startsWith("(")) { + keys[1] = key.substring(0, key.indexOf(")") + 1); + keys[0] = key.substring(key.indexOf(")")+1); + } + + return keys; + } + + /** + * Saves the prefs. + */ + protected void savePrefs() { + boolean expertMode = prefs.getBoolean("sim.mode.expert"); + + for (String key : integerKeys) { + String keys[] = getKeys(key); + JComboBox<Integer> valComboBox = integerFields.get(key); + prefsToEditMap.get( + keys[1]).setInteger(keys[0], + (Integer) valComboBox.getSelectedItem()); + } + + for (String key : vectorKeys) { + String keys[] = getKeys(key); + JTextField valField = vectorFields.get(key); + + try { + String val = valField.getText(); + Vector<Integer> vec = utils.VSTools.parseIntegerVector(val); + prefsToEditMap.get(keys[1]).setVector(keys[0], vec); + } catch (exceptions.VSParseIntegerVectorException e) { + } + + valField.setText(""+ + prefsToEditMap.get(keys[1]).getVector(keys[0])); + } + + for (String key : booleanKeys) { + String keys[] = getKeys(key); + JCheckBox valField = booleanFields.get(key); + prefsToEditMap.get(keys[1]).setBoolean( + keys[0], valField.isSelected()); + } + + for (String key : floatKeys) { + String keys[] = getKeys(key); + JTextField valField = floatFields.get(key); + + try { + Float val = Float.valueOf(valField.getText()); + prefsToEditMap.get(keys[1]).setFloat(keys[0], val); + + } catch (NumberFormatException e) { + valField.setText(""+ + prefsToEditMap.get(keys[1]).getFloat(keys[0])); + } + } + + for (String key : longKeys) { + String keys[] = getKeys(key); + JTextField valField = longFields.get(key); + + try { + Long val = Long.valueOf(valField.getText()); + prefsToEditMap.get(keys[1]).setLong(keys[0], val); + + } catch (NumberFormatException e) { + valField.setText(""+ + prefsToEditMap.get(keys[1]).getLong(keys[0])); + } + } + + for (String key : colorKeys) { + String keys[] = getKeys(key); + JTextField valField = colorFields.get(key); + prefsToEditMap.get(keys[1]).setColor( + keys[0], valField.getBackground()); + } + + for (String key : stringKeys) { + String keys[] = getKeys(key); + JTextField valField = stringFields.get(key); + prefsToEditMap.get(keys[1]).setString(keys[0], valField.getText()); + } + + expertModeChanged = expertMode != prefs.getBoolean("sim.mode.expert"); + } + + /** + * Check if the expert mode has changed. + * + * @return true, if it has changed. false, if it has not changed. + */ + public boolean expertModeChanged() { + boolean ret = expertModeChanged; + + if (expertModeChanged) + expertModeChanged = false; + + return ret; + } + + /* (non-Javadoc) + * @see java.awt.event.ActionListener#actionPerformed( + * java.awt.event.ActionEvent) + */ + public void actionPerformed(ActionEvent e) { + String actionCommand = e.getActionCommand(); + + if (actionCommand.equals(prefs.getString("lang.takeover"))) { + savePrefs(); + + } else if (actionCommand.equals(prefs.getString("lang.reset"))) { + resetPrefs(); + } + } + + /** + * Gets the edit panel + * + * @return the edit panel + */ + public JPanel getEditPanel() { + return editPanel; + } + + /** + * Gets the edit table + * + * @return the edit table + */ + public VSEditorTable getEditTable() { + return editTable; + } + + /** + * Gets the button panel. + * + * @return the button panel + */ + public JPanel getButtonPanel() { + return buttonPanel; + } +} diff --git a/src/main/java/prefs/editors/VSColorChooser.java b/src/main/java/prefs/editors/VSColorChooser.java new file mode 100644 index 0000000..ac67ace --- /dev/null +++ b/src/main/java/prefs/editors/VSColorChooser.java @@ -0,0 +1,61 @@ +package prefs.editors; + +import java.awt.BorderLayout; +import java.awt.Color; + +import javax.swing.BorderFactory; +import javax.swing.JColorChooser; +import javax.swing.JPanel; +import javax.swing.JTextField; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; + +import prefs.VSPrefs; + +/** + * The class VSColorChooser, is for selecting a color within an editor. + * + * @author Paul C. Buetow + */ +public class VSColorChooser extends JPanel implements ChangeListener { + /** The serial version uid */ + private static final long serialVersionUID = 1L; + + /** The color chooser. */ + protected JColorChooser colorChooser; + + /** The color. */ + private Color color; + + /** The val field. */ + private JTextField valField; + + /** + * Instantiates a new VSColorChooser object. + * + * @param prefs the prefs + * @param valField the val field + */ + public VSColorChooser(VSPrefs prefs, JTextField valField) { + super(new BorderLayout()); + this.color = valField.getBackground(); + this.valField = valField; + + colorChooser = new JColorChooser(Color.yellow); + colorChooser.setColor(color); + colorChooser.getSelectionModel().addChangeListener(this); + colorChooser.setBorder(BorderFactory.createTitledBorder( + prefs.getString("lang.colorchooser2"))); + add(colorChooser, BorderLayout.CENTER); + } + + /* (non-Javadoc) + * @see javax.swing.event.ChangeListener#stateChanged( + * javax.swing.event.ChangeEvent) + */ + public void stateChanged(ChangeEvent e) { + Color newColor = colorChooser.getColor(); + valField.setBackground(newColor); + valField.repaint(); + } +} diff --git a/src/main/java/prefs/editors/VSEditorFrame.java b/src/main/java/prefs/editors/VSEditorFrame.java new file mode 100644 index 0000000..e418801 --- /dev/null +++ b/src/main/java/prefs/editors/VSEditorFrame.java @@ -0,0 +1,98 @@ +package prefs.editors; + +import java.awt.Component; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JPanel; + +import prefs.VSPrefs; +import utils.VSFrame; + +/** + * The class VSEditorFrame, this is a wrapper around an VSAbstractEditor + * object, which should be displayed in its own frame. + * + * @author Paul C. Buetow + */ +public class VSEditorFrame extends VSFrame implements ActionListener { + /** The serial version uid */ + private static final long serialVersionUID = 1L; + + /** The editor. */ + private VSAbstractBetterEditor editor; + + /** The prefs. */ + private VSPrefs prefs; + + /** + * Instantiates a new VSEditorFrame object. + * + * @param prefs the prefs + * @param relativeTo the relative to + * @param editor the editor + */ + public VSEditorFrame(VSPrefs prefs, Component relativeTo, + VSAbstractBetterEditor editor) { + super(editor.getTitle(), relativeTo); + this.prefs = prefs; + this.editor = editor; + init(); + } + + /** + * Inits the VSEditorFrame object. + */ + private void init() { + editor.setFrame(this); + fillButtonPanel(editor.getButtonPanel()); + setContentPane(editor.getContentPane()); + setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + setSize(prefs.getInteger("div.window.prefs.xsize"), + prefs.getInteger("div.window.prefs.ysize")); + setResizable(false); + setVisible(true); + } + + /** + * Fills the button panel. + * + * @param buttonPanel the button panel + */ + private void fillButtonPanel(JPanel buttonPanel) { + JButton okButton = new JButton( + prefs.getString("lang.ok")); + okButton.setMnemonic(prefs.getInteger("keyevent.ok")); + okButton.addActionListener(this); + buttonPanel.add(okButton, 0); + + JButton cancelButton = new JButton( + prefs.getString("lang.cancel")); + cancelButton.setMnemonic(prefs.getInteger("keyevent.cancel")); + cancelButton.addActionListener(this); + buttonPanel.add(cancelButton, 1); + buttonPanel.repaint(); + } + + /* (non-Javadoc) + * @see java.awt.event.ActionListener#actionPerformed( + * java.awt.event.ActionEvent) + */ + public void actionPerformed(ActionEvent e) { + String actionCommand = e.getActionCommand(); + + if (actionCommand.equals(prefs.getString("lang.ok"))) { + editor.actionPerformed(e); + dispose(); + + } else if (actionCommand.equals(prefs.getString("lang.cancel"))) { + editor.actionPerformed(e); + dispose(); + + } else { + editor.actionPerformed(e); + } + } +} diff --git a/src/main/java/prefs/editors/VSEditorTable.java b/src/main/java/prefs/editors/VSEditorTable.java new file mode 100644 index 0000000..7be0dbf --- /dev/null +++ b/src/main/java/prefs/editors/VSEditorTable.java @@ -0,0 +1,290 @@ +package prefs.editors; + +import java.awt.Color; +import java.awt.Component; +import java.awt.Dimension; +import java.util.ArrayList; + +import javax.swing.AbstractCellEditor; +import javax.swing.JTable; +import javax.swing.JTextField; +import javax.swing.JTextPane; +import javax.swing.table.AbstractTableModel; +import javax.swing.table.TableCellEditor; +import javax.swing.table.TableCellRenderer; +import javax.swing.table.TableColumn; +import javax.swing.text.Style; +import javax.swing.text.StyleConstants; + +import prefs.VSPrefs; + +/** + * The class VSEditorTable, each VSAbstractEditor uses an object of this class + * for displaying all editable items! + * + * @author Paul C. Buetow + */ +public class VSEditorTable extends JTable { + /** The serial version uid */ + private static final long serialVersionUID = 1L; + + /** The nodes. */ + private ArrayList<VSNode> nodes; + + /** The model. */ + private VSEditorTableModel model; + + /** + * The class VSNode. + */ + private class VSNode { + /** The key. */ + private String key; + + /** The comp. */ + private Component comp; + + /** + * Instantiates a new VSNode object. + * + * @param key the key + */ + public VSNode(String key) { + this.key = key; + } + + /** + * Instantiates a new VSNode object. + * + * @param key the key + * @param comp the comp + */ + public VSNode(String key, Component comp) { + this.key = key; + this.comp = comp; + } + + /** + * Gets the key. + * + * @return the key + */ + public String getKey() { + return key; + } + + /** + * Gets the component. + * + * @return the component + */ + public Component getComponent() { + return comp; + } + + /** + * Gets the renderer component. + * + * @return the renderer component + */ + public Component getRendererComponent() { + return comp; + } + + /** + * Checks if it is a separator. + * + * @return true, if is separator + */ + public boolean isSeparator() { + return comp == null; + } + } + + /** + * The class VSEditorTableModel, it is the model of a VSEditorTable. + */ + private class VSEditorTableModel extends AbstractTableModel + implements TableCellRenderer { + /** The serial version uid */ + private static final long serialVersionUID = 1L; + + /** + * Instantiates a new lang.process.removeeditor table model. + */ + public VSEditorTableModel() { + } + + /* (non-Javadoc) + * @see javax.swing.table.AbstractTableModel#getColumnName(int) + */ + public String getColumnName(int col) { + return ""; + } + + /* (non-Javadoc) + * @see javax.swing.table.TableModel#getRowCount() + */ + public int getRowCount() { + return nodes.size(); + } + + /* (non-Javadoc) + * @see javax.swing.table.TableModel#getColumnCount() + */ + public int getColumnCount() { + return 2; + } + + /* (non-Javadoc) + * @see javax.swing.table.TableModel#getValueAt(int, int) + */ + public Object getValueAt(int row, int col) { + VSNode node = nodes.get(row); + + if (node.isSeparator()) { + if (col == 1) + return ""; + + return node.getKey(); + } + + if (col == 0) + return node.getKey(); + + return node.getComponent(); + } + + /* (non-Javadoc) + * @see javax.swing.table.AbstractTableModel#isCellEditable(int, int) + */ + public boolean isCellEditable(int row, int col) { + if (col == 0) + return false; + + if (nodes.get(row).isSeparator()) + return false; + + return true; + } + + /* (non-Javadoc) + * @see javax.swing.table.AbstractTableModel#setValueAt( + * java.lang.Object, int, int) + */ + public void setValueAt(Object value, int row, int col) { + } + + /* (non-Javadoc) + * @see + * javax.swing.table.TableCellRenderer#getTableCellRendererComponent( + * javax.swing.JTable, java.lang.Object, boolean, boolean, int, int) + */ + public Component getTableCellRendererComponent(JTable table, + Object object, boolean isSelected, boolean hasFocus, int + row, int col) { + + VSNode node = nodes.get(row); + + if (node.isSeparator()) { + JTextPane pane = new JTextPane(); + if (col == 0) { + pane.setText(node.getKey()); + Style style = pane.addStyle("Bold", null); + StyleConstants.setBold(style, true); + } + pane.setBackground(new Color(0xCF, 0xCF, 0XCF)); + return pane; + } + + if (col == 0) { + JTextField field = new JTextField(" "+node.getKey()+":"); + field.setBorder(null); + field.setEditable(false); + field.setBackground(Color.WHITE); + return field; + } + + return node.getRendererComponent(); + } + } + + /** + * The class VSTableCellEditor, is the editor of the VSEditorTable + */ + private class VSTableCellEditor extends AbstractCellEditor + implements TableCellEditor { + /** The serial version uid */ + private static final long serialVersionUID = 1L; + + /* (non-Javadoc) + * @see javax.swing.table.TableCellEditor#getTableCellEditorComponent( + * javax.swing.JTable, java.lang.Object, boolean, int, int) + */ + public Component getTableCellEditorComponent(JTable table, + Object object, + boolean isSelected, + int row, + int col) { + return nodes.get(row).getComponent(); + } + + /* (non-Javadoc) + * @see javax.swing.CellEditor#getCellEditorValue() + */ + public Object getCellEditorValue() { + return new String(""); + } + } + + /** + * Instantiates a new VSEditorTable object. + * + * @param prefs the prefs + */ + public VSEditorTable(VSPrefs prefs) { + //this.prefs = prefs; + this.nodes = new ArrayList<VSNode>(); + this.model = new VSEditorTableModel(); + setModel(model); + setDefaultRenderer(Object.class, model); + setDefaultEditor(Object.class, new VSTableCellEditor()); + setIntercellSpacing(new Dimension(5, 5)); + setRowHeight(25); + setBackground(Color.WHITE); + getTableHeader().setVisible(false); + TableColumn col = getColumnModel().getColumn(1); + col.setMinWidth(100); + col.setMaxWidth(100); + col.setResizable(false); + + col = getColumnModel().getColumn(0); + col.sizeWidthToFit(); + } + + /** + * Adds the variable. + * + * @param key the key + * @param comp the comp + */ + public void addVariable(String key, Component comp) { + nodes.add(new VSNode(key, comp)); + } + + /** + * Adds the separator. + * + * @param text the text + */ + public void addSeparator(String text) { + nodes.add(new VSNode(text)); + } + + /** + * Fires that the table data has changed. + */ + public void fireTableDataChanged() { + model.fireTableDataChanged(); + } +} diff --git a/src/main/java/prefs/editors/VSProcessEditor.java b/src/main/java/prefs/editors/VSProcessEditor.java new file mode 100644 index 0000000..105152e --- /dev/null +++ b/src/main/java/prefs/editors/VSProcessEditor.java @@ -0,0 +1,107 @@ +package prefs.editors; + +import java.awt.event.ActionEvent; +import java.util.ArrayList; + +import javax.swing.JButton; +import javax.swing.JPanel; + +import core.VSInternalProcess; +import events.VSRegisteredEvents; +import prefs.VSPrefs; +import protocols.VSAbstractProtocol; + +/** + * The class VSProcessEditor, is for editing a VSInternalProcess object. + * + * @author Paul C. Buetow + */ +public class VSProcessEditor extends VSAbstractBetterEditor { + /** The process. */ + private VSInternalProcess process; + + /** The TAKEOVE r_ button. */ + public static boolean TAKEOVER_BUTTON; + + /** + * Instantiates a new VSProcessEditor object. + * + * @param prefs the prefs + * @param process the process + */ + public VSProcessEditor(VSPrefs prefs, VSInternalProcess process) { + super(prefs, process, prefs.getString("lang.name") + " - " + + prefs.getString("lang.prefs.process"));; + this.process = process; + disposeFrameWithParentIfExists(); + makeProtocolVariablesEditable(); + } + + /* (non-Javadoc) + * @see prefs.editors.VSAbstractBetterEditor#addToButtonPanelFront( + * javax.swing.JPanel) + */ + protected void addToButtonPanelFront(JPanel buttonPanel) { + JButton takeoverButton = new JButton( + prefs.getString("lang.takeover")); + takeoverButton.setMnemonic(prefs.getInteger("keyevent.takeover")); + takeoverButton.addActionListener(this); + buttonPanel.add(takeoverButton); + } + + /** + * Make protocol variables editable. + */ + protected void makeProtocolVariablesEditable() { + ArrayList<String> editableProtocolsClassnames = + VSRegisteredEvents.getEditableProtocolsClassnames(); + + //String protocolString = " " + prefs.getString("lang.protocol"); + String clientString = " " + prefs.getString("lang.client"); + String serverString = " " + prefs.getString("lang.server"); + + for (String protocolClassname : editableProtocolsClassnames) { + String protocolShortname = + VSRegisteredEvents.getShortnameByClassname( + protocolClassname); + VSAbstractProtocol protocol = + process.getProtocolObject(protocolClassname); + protocol.onClientInit(); + protocol.onServerInit(); + + ArrayList<String> clientVariables = + VSRegisteredEvents.getProtocolClientVariables( + protocolClassname); + if (clientVariables != null) + addToEditor(protocolShortname + clientString, + protocolShortname, protocol, clientVariables); + + ArrayList<String> serverVariables = + VSRegisteredEvents.getProtocolServerVariables( + protocolClassname); + if (serverVariables != null) + addToEditor(protocolShortname + serverString, + protocolShortname, protocol, serverVariables); + } + } + + /* (non-Javadoc) + * @see prefs.editors.VSAbstractBetterEditor#actionPerformed( + * java.awt.event.ActionEvent) + */ + public void actionPerformed(ActionEvent e) { + String actionCommand = e.getActionCommand(); + + if (actionCommand.equals(prefs.getString("lang.ok"))) { + savePrefs(); + process.updateFromPrefs(); + + } else if (actionCommand.equals(prefs.getString("lang.takeover"))) { + savePrefs(); + process.updateFromPrefs(); + + } else { + super.actionPerformed(e); + } + } +} diff --git a/src/main/java/prefs/editors/VSSimulatorEditor.java b/src/main/java/prefs/editors/VSSimulatorEditor.java new file mode 100644 index 0000000..9ee0e58 --- /dev/null +++ b/src/main/java/prefs/editors/VSSimulatorEditor.java @@ -0,0 +1,120 @@ +package prefs.editors; + +import java.awt.event.ActionEvent; + +import javax.swing.JButton; +import javax.swing.JPanel; + +import prefs.VSPrefs; +import simulator.VSSimulator; +import simulator.VSSimulatorFrame; + +/** + * The class VSSimulatorEditor, is for editing a VSSimulator object. + * + * @author Paul C. Buetow + */ +public class VSSimulatorEditor extends VSAbstractBetterEditor { + /** The constant OPENED_NEW_WINDOW */ + public static final boolean OPENED_NEW_WINDOW = true; + + /** The constant OPENED_NEW_TAB */ + public static final boolean OPENED_NEW_TAB = false; + + /** The simulator frame. */ + private VSSimulatorFrame simulatorFrame; + + /** The simulator. */ + private VSSimulator simulator; + + /** The TAKEOVE r_ button. */ + public static boolean TAKEOVER_BUTTON; + + /** The dont start new simulator. */ + private boolean dontStartNewSimulator; + + /** Open a new simulator window. */ + private boolean openedNewWindow; + + /** + * Instantiates a new VSSimulatorEditor object. + * + * @param prefs the prefs + * @param simulatorFrame the simulator frame + * @param simulator the simulator + */ + public VSSimulatorEditor(VSPrefs prefs, VSSimulatorFrame simulatorFrame, + VSSimulator simulator) { + super(prefs, prefs, prefs.getString("lang.name") + + " - " + prefs.getString("lang.prefs")); + this.dontStartNewSimulator = true;//simulator != null; + this.simulatorFrame = simulatorFrame; + this.simulator = simulator; + } + + /** + * Instantiates a new VSSimulatorEditor object. + * + * @param prefs the prefs + * @param simulatorFrame the simulator frame + */ + public VSSimulatorEditor(VSPrefs prefs, VSSimulatorFrame simulatorFrame, + boolean openedNewWindow) { + super(prefs, prefs, prefs.getString("lang.name") + + " - " + prefs.getString("lang.prefs")); + this.simulatorFrame = simulatorFrame; + this.openedNewWindow = openedNewWindow; + } + + /* (non-Javadoc) + * @see prefs.editors.VSAbstractBetterEditor#addToButtonPanelFront( + * javax.swing.JPanel) + */ + protected void addToButtonPanelFront(JPanel buttonPanel) { + if (TAKEOVER_BUTTON) { + TAKEOVER_BUTTON = false; + JButton takeoverButton = new JButton( + prefs.getString("lang.takeover")); + takeoverButton.setMnemonic(prefs.getInteger("keyevent.takeover")); + takeoverButton.addActionListener(this); + buttonPanel.add(takeoverButton); + } + } + + /* (non-Javadoc) + * @see prefs.editors.VSAbstractBetterEditor#actionPerformed( + * java.awt.event.ActionEvent) + */ + public void actionPerformed(ActionEvent e) { + String actionCommand = e.getActionCommand(); + + if (actionCommand.equals(prefs.getString("lang.takeover"))) { + savePrefs(); + + if (simulator != null) { + if (expertModeChanged()) + simulator.fireExpertModeChanged(); + simulator.updateFromPrefs(); + } + + } else if (actionCommand.equals(prefs.getString("lang.cancel"))) { + if (!dontStartNewSimulator && openedNewWindow) + simulatorFrame.dispose(); + + } else if (actionCommand.equals(prefs.getString("lang.ok"))) { + savePrefs(); + if (expertModeChanged()) { + if (simulator != null) + simulator.fireExpertModeChanged(); + } + if (!dontStartNewSimulator) + simulatorFrame.addSimulator(new VSSimulator(prefsToEdit, + simulatorFrame)); + else if (simulator != null) + simulator.updateFromPrefs(); + + } else { + super.actionPerformed(e); + } + } +} diff --git a/src/main/java/protocols/VSAbstractProtocol.java b/src/main/java/protocols/VSAbstractProtocol.java new file mode 100644 index 0000000..70d7595 --- /dev/null +++ b/src/main/java/protocols/VSAbstractProtocol.java @@ -0,0 +1,450 @@ +package protocols; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.util.ArrayList; + +import core.VSInternalProcess; +import core.VSMessage; +import core.VSMessageStub; +import core.VSTask; +import events.VSAbstractEvent; +import events.internal.VSProtocolScheduleEvent; +import serialize.VSSerialize; +import simulator.VSSimulatorVisualization; + +/** + * The class VSAbstractProtocol, this class defined the basic framework of a + * protocol. + * + * @author Paul C. Buetow + */ +abstract public class VSAbstractProtocol extends VSAbstractEvent { + /** The protocol has an onServerStart method */ + protected static final boolean HAS_ON_SERVER_START = true; + + /** The protocol has an onClientStart method */ + protected static final boolean HAS_ON_CLIENT_START = false; + + /** True, if onServerStart is used, false if onClientStart is used */ + private boolean hasOnServerStart; + + /** The protocol object is a server. */ + private boolean isServer; + + /** The protocol object is a client. */ + private boolean isClient; + + /** The protocol object server is initialized. */ + private boolean isServerInitialized; + + /** The protocol object client is initialized. */ + private boolean isClientInitialized; + + /** The current protocol object's context is a server. */ + private boolean currentContextIsServer; + + /** The protocol's server schedules */ + private ArrayList<VSTask> serverSchedules = new ArrayList<VSTask>(); + + /** The protocol's client schedules */ + private ArrayList<VSTask> clientSchedules = new ArrayList<VSTask>(); + + /** + * A simple constructor. + * + * @param hasOnServerStart true, if the protocol uses an onServerStart + * method. false, if the protocol uses an onClientStart method instead. + */ + public VSAbstractProtocol(boolean hasOnServerStart) { + this.hasOnServerStart = hasOnServerStart; + } + + /** + * Sends a message. + * + * @param message the message to send + */ + public void sendMessage(VSMessage message) { + if (process == null) + return; + + process.increaseLamportTime(); + process.increaseVectorTime(); + + VSMessageStub stub = new VSMessageStub(message); + VSInternalProcess internalProcess = (VSInternalProcess) process; + + if (currentContextIsServer) + stub.init(internalProcess, getClassname(), + VSMessage.IS_SERVER_MESSAGE); + else + stub.init(internalProcess, getClassname(), + VSMessage.IS_CLIENT_MESSAGE); + + internalProcess.sendMessage(message); + } + + /** + * Checks if it's the incorrect protocol + * + * @param message the message to check against + * + * @return true, if is incorrect protocol + */ + private final boolean isIncorrectProtocol(VSMessage message) { + return !message.getProtocolClassname().equals(getClassname()); + } + + /* (non-Javadoc) + * @see events.VSAbstractEvent#onStart() + */ + public final void onStart() { + if (hasOnServerStart) { + if (isServer) { + currentContextIsServer(true); + if (!isServerInitialized) + onInit(); + onServerStart(); + } + } else { + if (isClient) { + currentContextIsServer(false); + if (!isClientInitialized) + onInit(); + onClientStart(); + } + } + } + + /* (non-Javadoc) + * @see events.VSAbstractEvent#onInit() + */ + public final void onInit() { + if (isClient) { + currentContextIsServer(false); + onClientInit(); + isClientInitialized = true; + } + + if (isServer) { + currentContextIsServer(true); + onServerInit(); + isServerInitialized = true; + } + } + + /** + * Runs a client schedule + */ + public final void onClientScheduleStart() { + if (isClient) { + currentContextIsServer(false); + onClientSchedule(); + } + } + + /** + * Runs a server schedule + */ + public final void onServerScheduleStart() { + if (isServer) { + currentContextIsServer(true); + onServerSchedule(); + } + } + + /** + * On message recv. + * + * @param message the message + */ + public final void onMessageRecvStart(VSMessage message) { + if (isIncorrectProtocol(message)) + return; + + if (isServer) { + currentContextIsServer(true); + if (!isServerInitialized) + onInit(); + onServerRecv(message); + } + + if (isClient) { + currentContextIsServer(false); + if (!isClientInitialized) + onInit(); + onClientRecv(message); + } + } + + /** + * Check's if its a relevant message. + * + * @param message the message to check + * + * @return true, if it's a relevant meessage. false if the protocol + * is wrong or if the server recv a server message/the client recv a + * client message. Clients should only recv server messages and servers + * should only recv client messages. + */ + public final boolean isRelevantMessage(VSMessage message) { + if (isIncorrectProtocol(message)) + return false; + + if (message.isServerMessage()) { + if (!isClient) + return false; + } else { + if (!isServer) + return false; + } + + return true; + } + + /** + * Sets if the current context is server. + * + * @param currentContextIsServer the context. + */ + public final void currentContextIsServer(boolean currentContextIsServer) { + this.currentContextIsServer = currentContextIsServer; + } + + /** + * Checks how the protocol will start + * + * @return true, if this protocol uses onServerStart instead of + * onClientStart + */ + public final boolean hasOnServerStart() { + return hasOnServerStart; + } + + /** + * Sets if is server. + * + * @param isServer the is server + */ + public final void isServer(boolean isServer) { + this.isServer = isServer; + } + + /** + * Checks if is server. + * + * @return true, if the protocol has activated the server part + */ + public final boolean isServer() { + return isServer; + } + + /** + * Sets if is client. + * + * @param isClient the is client + */ + public final void isClient(boolean isClient) { + this.isClient = isClient; + } + + /** + * Checks if is client. + * + * @return true, if the protocol has activated the client part + */ + public final boolean isClient() { + return isClient; + } + + /** + * Resets the protocol. + */ + public void reset() { + currentContextIsServer(true); + isServer = false; + onServerReset(); + serverSchedules.clear(); + + currentContextIsServer(false); + isClient = false; + onClientReset(); + clientSchedules.clear(); + } + + /** + * Reschedules the protocol for a new time and runs onClientSchedule or + * onServerSchedule + * + * @param time The process' local time to run the schedule at. + */ + public final void scheduleAt(long time) { + VSInternalProcess internalProcess = (VSInternalProcess) process; + VSAbstractEvent scheduleEvent = + new VSProtocolScheduleEvent(this, currentContextIsServer); + VSTask scheduleTask = + new VSTask(time, internalProcess, scheduleEvent, VSTask.LOCAL); + + if (currentContextIsServer) + serverSchedules.add(scheduleTask); + else + clientSchedules.add(scheduleTask); + + VSSimulatorVisualization canvas = internalProcess.getSimulatorCanvas(); + canvas.getTaskManager().addTask(scheduleTask); + } + + /** + * Removes all schedules of the protocol (server or client) + */ + public final void removeSchedules() { + VSInternalProcess internalProcess = (VSInternalProcess) process; + + if (currentContextIsServer) { + internalProcess.getSimulatorCanvas(). + getTaskManager().removeAllTasks(serverSchedules); + serverSchedules.clear(); + + } else { + internalProcess.getSimulatorCanvas(). + getTaskManager().removeAllTasks(clientSchedules); + clientSchedules.clear(); + } + } + + /** + * On client init. + */ + abstract public void onClientInit(); + + /** + * On client start. + */ + public void onClientStart() { }; + + /** + * On client reset. + */ + abstract public void onClientReset(); + + /** + * On client schedule. + */ + abstract public void onClientSchedule(); + + /** + * On client recv. + * + * @param message the message + */ + abstract public void onClientRecv(VSMessage message); + + /** + * On server init. + */ + abstract public void onServerInit(); + + /** + * On server start. + */ + public void onServerStart() { }; + + /** + * On server reset. + */ + abstract public void onServerReset(); + + /** + * On server recv. + * + * @param message the message + */ + abstract public void onServerRecv(VSMessage message); + + /** + * On server schedule. + */ + abstract public void onServerSchedule(); + + /** + * Gets the num processes. + * + * @return the num processes + */ + public final int getNumProcesses() { + if (process == null) + return 0; + + VSInternalProcess internalProcess = (VSInternalProcess) process; + return internalProcess.getSimulatorCanvas().getNumProcesses(); + } + + /* (non-Javadoc) + * @see events.VSAbstractEvent#createShortname()() + */ + protected String createShortname(String savedShortname) { + return savedShortname; + } + + /* (non-Javadoc) + * @see prefs.VSPrefs#toString() + */ + public String toString() { + if (process == null) + return ""; + + StringBuffer buffer = new StringBuffer(); + + buffer.append(prefs.getString("lang.protocol")); + buffer.append(": "); + buffer.append(getShortname()); + buffer.append(" "); + + if (currentContextIsServer) + buffer.append(prefs.getString("lang.server")); + else + buffer.append(prefs.getString("lang.client")); + + return buffer.toString(); + } + + /* (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); + + /** For later backwards compatibility, to add more stuff */ + objectOutputStream.writeObject(Boolean.valueOf(false)); + + objectOutputStream.writeObject(Boolean.valueOf(hasOnServerStart)); + + /** 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); + + if (VSSerialize.DEBUG) + System.out.println("Deserializing: VSAbstractProtocol"); + + /** For later backwards compatibility, to add more stuff */ + objectInputStream.readObject(); + + this.hasOnServerStart = ((Boolean) objectInputStream.readObject()).booleanValue(); + /** For later backwards compatibility, to add more stuff */ + objectInputStream.readObject(); + } +} diff --git a/src/main/java/protocols/implementations/README b/src/main/java/protocols/implementations/README new file mode 100644 index 0000000..fd8effa --- /dev/null +++ b/src/main/java/protocols/implementations/README @@ -0,0 +1,10 @@ +How to add a new protocol: + +1. Copy the file VSDummyProtocol.java into VSYourOwnNiceProtocol.java + +2. Edit VSYourOwnNiceProtocol.java and replace the classname! + +3. Edit the initialize method of events.RegisteredEvents.java and add the classname +of your protocol. E.g.: "protocols.implementations.VSYourOwnNiceProtocol" + + diff --git a/src/main/java/protocols/implementations/VSBasicMulticastProtocol.java b/src/main/java/protocols/implementations/VSBasicMulticastProtocol.java new file mode 100644 index 0000000..cfd5399 --- /dev/null +++ b/src/main/java/protocols/implementations/VSBasicMulticastProtocol.java @@ -0,0 +1,86 @@ +package protocols.implementations; + +import core.VSMessage; +import protocols.VSAbstractProtocol; + +/** + * The class VSBasicMulticastProtocol, an implementation of the basic multicast + * protocol. + * + * @author Paul C. Buetow + */ +public class VSBasicMulticastProtocol extends VSAbstractProtocol { + /** + * Instantiates a new VSBasicMulticast object. + */ + public VSBasicMulticastProtocol() { + super(VSAbstractProtocol.HAS_ON_CLIENT_START); + setClassname(getClass().toString()); + } + + /* (non-Javadoc) + * @see events.VSAbstractProtocol#onClientInit() + */ + public void onClientInit() { + } + + /* (non-Javadoc) + * @see protocols.VSAbstractProtocol#onClientReset() + */ + public void onClientReset() { + } + + /* (non-Javadoc) + * @see protocols.VSAbstractProtocol#onClientStart() + */ + public void onClientStart() { + VSMessage message = new VSMessage(); + message.setBoolean("isMulticast", true); + sendMessage(message); + } + + /* (non-Javadoc) + * @see protocols.VSAbstractProtocol#onClientRecv(core.VSMessage) + */ + public void onClientRecv(VSMessage recvMessage) { + } + + /* (non-Javadoc) + * @see protocols.VSAbstractProtocol#onClientSchedule() + */ + public void onClientSchedule() { + } + + /* (non-Javadoc) + * @see events.VSAbstractProtocol#onServerInit() + */ + public void onServerInit() { + } + + /* (non-Javadoc) + * @see protocols.VSAbstractProtocol#onServerReset() + */ + public void onServerReset() { + } + + /* (non-Javadoc) + * @see protocols.VSAbstractProtocol#onServerRecv(core.VSMessage) + */ + public void onServerRecv(VSMessage recvMessage) { + if (recvMessage.getBoolean("isMulticast")) + log("Multicast received"); + } + + /* (non-Javadoc) + * @see protocols.VSAbstractProtocol#onServerSchedule() + */ + public void onServerSchedule() { + } + + /* (non-Javadoc) + * @see protocols.VSAbstractProtocol#toString() + */ + public String toString() { + return super.toString(); + } +} diff --git a/src/main/java/protocols/implementations/VSBerkelyTimeProtocol.java b/src/main/java/protocols/implementations/VSBerkelyTimeProtocol.java new file mode 100644 index 0000000..05d0eae --- /dev/null +++ b/src/main/java/protocols/implementations/VSBerkelyTimeProtocol.java @@ -0,0 +1,204 @@ +package protocols.implementations; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Vector; + +import core.VSMessage; +import protocols.VSAbstractProtocol; + +/** + * The class VSBerkelyTimeProtocol, an implementation of the berkely time + * protocol. + * + * @author Paul C. Buetow + */ +public class VSBerkelyTimeProtocol extends VSAbstractProtocol { + /** + * Instantiates a new berkely time protocol. + */ + public VSBerkelyTimeProtocol() { + super(VSAbstractProtocol.HAS_ON_SERVER_START); + setClassname(getClass().toString()); + } + + /** Integer: Process ID, Long: Local time of the process */ + private HashMap<Integer,Long> processTimes = new HashMap<Integer,Long>(); + + /** Integer: Process ID, Long: Time of receiving the response from the + * process + */ + private HashMap<Integer,Long> recvTimes = new HashMap<Integer,Long>(); + + /** Integer: Process ID, Long: Calculated process times (using the RTT) */ + private HashMap<Integer,Long> realTimesRTT = new HashMap<Integer,Long>(); + + /** Contains all process IDs of processes which want to justify their + * time + */ + private ArrayList<Integer> peers = new ArrayList<Integer>(); + + /** Time the request/response has started */ + private long requestTime; + + /* (non-Javadoc) + * @see events.VSAbstractProtocol#onServerInit() + */ + public void onServerInit() { + Vector<Integer> vec = new Vector<Integer>(); + vec.add(1); + vec.add(3); + initVector("pids", vec, "PIDs of participating processes"); + } + + /* (non-Javadoc) + * @see protocols.VSAbstractProtocol#onServerReset() + */ + public void onServerReset() { + //System.out.println("FOOBAR"); + processTimes.clear(); + recvTimes.clear(); + realTimesRTT.clear(); + peers.clear(); + } + + /* (non-Javadoc) + * @see protocols.VSAbstractProtocol#onServerStart() + */ + public void onServerStart() { + //System.out.println("FOO"); + peers.addAll(getVector("pids")); + requestTime = process.getTime(); + VSMessage message = new VSMessage(); + message.setBoolean("isRequest", true); + sendMessage(message); + } + + /* (non-Javadoc) + * @see protocols.VSAbstractProtocol#onServerRecv(core.VSMessage) + */ + public void onServerRecv(VSMessage recvMessage) { + /* Ignore all protocol messages which are not a response message, + e.g. itself */ + if (!recvMessage.getBoolean("isResponse")) + return; + + Integer processID = recvMessage.getIntegerObj("processID"); + + if (peers.contains(processID)) + peers.remove(processID); + else + return; /* Process has been handled already or is not listed */ + + Long time = Long.valueOf(recvMessage.getLong("time")); + + processTimes.put(processID, time); + recvTimes.put(processID, Long.valueOf(process.getTime())); + + /* All peers have told their times */ + if (peers.size() == 0) { + long avgTime = calculateAverageTime(); + /* Set the local's process time to the new avg reference time */ + process.setTime(avgTime); + /* Tell all other processes what to do in order to justify their + times */ + sendJustifyRequests(avgTime); + /* Start "clean" next time */ + onServerReset(); + } + } + + /* (non-Javadoc) + * @see protocols.VSAbstractProtocol#onServerSchedule() + */ + public void onServerSchedule() { + } + + /** + * Calculate the new average time. + * + * @return the long + */ + private long calculateAverageTime() { + long sum = 0; + for (Integer processID : processTimes.keySet()) { + Long localTime = processTimes.get(processID); + Long recvTime = recvTimes.get(processID); + long rtt = recvTime.longValue() - requestTime; + long realProcessTime = localTime + (long) (rtt / 2); + realTimesRTT.put(processID, Long.valueOf(realProcessTime)); + sum += realProcessTime; + } + /* Include the time of the local process */ + sum += process.getTime(); + return (long) sum / (getVector("pids").size() + 1); + } + + /** + * Sends to all clients a value to justify their local clocks. + * + * @param avgTime the avg time + */ + private void sendJustifyRequests(long avgTime) { + for (Integer processID : processTimes.keySet()) { + long realProcessTime = realTimesRTT.get(processID).longValue(); + long diff = avgTime - realProcessTime; + VSMessage message = new VSMessage(); + message.setBoolean("isJustify", true); + message.setLong("timeDiff", diff); + message.setInteger("receiverProcessID", processID); + sendMessage(message); + } + } + + /* (non-Javadoc) + * @see events.VSAbstractProtocol#onClientInit() + */ + public void onClientInit() { + } + + /* (non-Javadoc) + * @see protocols.VSAbstractProtocol#onClientReset() + */ + public void onClientReset() { + } + + /* (non-Javadoc) + * @see protocols.VSAbstractProtocol#onClientRecv(core.VSMessage) + */ + public void onClientRecv(VSMessage recvMessage) { + if (recvMessage.getBoolean("isRequest")) { + VSMessage message = new VSMessage(); + message.setInteger("processID", process.getProcessID()); + message.setLong("time", process.getTime()); + message.setBoolean("isResponse", true); + sendMessage(message); + + } else if (recvMessage.getBoolean("isJustify")) { + /* Check if it's "my" justify message */ + if (recvMessage.getInteger("receiverProcessID") != + process.getProcessID()) + return; + + long timeDiff = recvMessage.getLong("timeDiff"); + //long recvTime = process.getTime(); + long newTime = process.getTime() + timeDiff; + log("New time: " + newTime); + + process.setTime(newTime); + } + } + + /* (non-Javadoc) + * @see protocols.VSAbstractProtocol#onClientSchedule() + */ + public void onClientSchedule() { + } + + /* (non-Javadoc) + * @see protocols.VSAbstractProtocol#toString() + */ + public String toString() { + return super.toString(); + } +} diff --git a/src/main/java/protocols/implementations/VSBroadcastProtocol.java b/src/main/java/protocols/implementations/VSBroadcastProtocol.java new file mode 100644 index 0000000..54fd3b5 --- /dev/null +++ b/src/main/java/protocols/implementations/VSBroadcastProtocol.java @@ -0,0 +1,103 @@ +package protocols.implementations; + +import java.util.ArrayList; + +import core.VSMessage; +import protocols.VSAbstractProtocol; + +/** + * The class VSBroadcastProtocol, an implementation of the broadcast + * sturm protocol. + * + * @author Paul C. Buetow + */ +public class VSBroadcastProtocol extends VSAbstractProtocol { + /** The sent messages. */ + private ArrayList<Integer> sentMessages; + + /** The broadcast count. */ + private static int broadcastCount; + + /** + * Instantiates a new broadcast sturm protocol. + */ + public VSBroadcastProtocol() { + super(VSAbstractProtocol.HAS_ON_CLIENT_START); + setClassname(getClass().toString()); + sentMessages = new ArrayList<Integer>(); + } + + /* (non-Javadoc) + * @see events.VSAbstractProtocol#onClientInit() + */ + public void onClientInit() { + } + + /* (non-Javadoc) + * @see protocols.VSAbstractProtocol#onClientReset() + */ + public void onClientReset() { + } + + /* (non-Javadoc) + * @see protocols.VSAbstractProtocol#onClientStart() + */ + public void onClientStart() { + VSMessage message = new VSMessage(); + message.setInteger("Broadcast", broadcastCount++); + sentMessages.add(message.getIntegerObj("Broadcast")); + sendMessage(message); + } + + /* (non-Javadoc) + * @see protocols.VSAbstractProtocol#onClientRecv(core.VSMessage) + */ + public void onClientRecv(VSMessage recvMessage) { + onServerRecv(recvMessage); + } + + /* (non-Javadoc) + * @see protocols.VSAbstractProtocol#onClientSchedule() + */ + public void onClientSchedule() { + } + + /* (non-Javadoc) + * @see events.VSAbstractProtocol#onServerInit() + */ + public void onServerInit() { + } + + /* (non-Javadoc) + * @see protocols.VSAbstractProtocol#onServerReset() + */ + public void onServerReset() { + sentMessages.clear(); + } + + /* (non-Javadoc) + * @see protocols.VSAbstractProtocol#onServerSchedule() + */ + public void onServerSchedule() { + } + + /* (non-Javadoc) + * @see protocols.VSAbstractProtocol#onServerRecv(core.VSMessage) + */ + public void onServerRecv(VSMessage recvMessage) { + if (!sentMessages.contains(recvMessage.getIntegerObj("Broadcast"))) { + VSMessage message = new VSMessage(); + message.setInteger("Broadcast", + recvMessage.getInteger("Broadcast")); + sentMessages.add(message.getIntegerObj("Broadcast")); + sendMessage(message); + } + } + + /* (non-Javadoc) + * @see protocols.VSAbstractProtocol#toString() + */ + public String toString() { + return super.toString(); + } +} diff --git a/src/main/java/protocols/implementations/VSDummyProtocol.java b/src/main/java/protocols/implementations/VSDummyProtocol.java new file mode 100644 index 0000000..e9e6837 --- /dev/null +++ b/src/main/java/protocols/implementations/VSDummyProtocol.java @@ -0,0 +1,100 @@ +package protocols.implementations; + +import core.VSMessage; +import protocols.VSAbstractProtocol; + +/** + * The class VSDummyProtocol, can be used as a template in order to create + * own protocols. + * + * @author Paul C. Buetow + */ +public class VSDummyProtocol extends VSAbstractProtocol { + /** + * Instantiates a new dummy protocol object. + */ + public VSDummyProtocol() { + super(VSAbstractProtocol.HAS_ON_CLIENT_START); + setClassname(getClass().toString()); + } + + /* (non-Javadoc) + * @see events.VSAbstractProtocol#onClientInit() + */ + public void onClientInit() { + } + + /* (non-Javadoc) + * @see protocols.VSAbstractProtocol#onClientReset() + */ + public void onClientReset() { + log("onClientReset()"); + } + + /* (non-Javadoc) + * @see protocols.VSAbstractProtocol#onClientStart() + */ + public void onClientStart() { + log("onClientStart()"); + + VSMessage message = new VSMessage(); + message.setString("Greeting", "Hello World!"); + message.setInteger("A number", 1); + message.setBoolean("A boolean", true); + message.setFloat("A float", 1.2f); + sendMessage(message); + } + + /* (non-Javadoc) + * @see protocols.VSAbstractProtocol#onClientRecv(core.VSMessage) + */ + public void onClientRecv(VSMessage recvMessage) { + log("onClientRecv("+recvMessage+")"); + + /* + String s = recvMessage.getString("Greeting"); + int n = recvMessage.getInteger("A number"); + boolean b = recvMessage.getBoolean("A boolean"); + float f = recvMessage.getFloat("A float"); + */ + } + + /* (non-Javadoc) + * @see protocols.VSAbstractProtocol#onClientSchedule() + */ + public void onClientSchedule() { + } + + /* (non-Javadoc) + * @see events.VSAbstractProtocol#onServerInit() + */ + public void onServerInit() { + } + + /* (non-Javadoc) + * @see protocols.VSAbstractProtocol#onServerReset() + */ + public void onServerReset() { + log("onClientReset()"); + } + + /* (non-Javadoc) + * @see protocols.VSAbstractProtocol#onServerRecv(core.VSMessage) + */ + public void onServerRecv(VSMessage recvMessage) { + log("onServerRecv("+recvMessage+")"); + } + + /* (non-Javadoc) + * @see protocols.VSAbstractProtocol#onServerSchedule() + */ + public void onServerSchedule() { + } + + /* (non-Javadoc) + * @see protocols.VSAbstractProtocol#toString() + */ + public String toString() { + return super.toString() + "; Dummy Test"; + } +} diff --git a/src/main/java/protocols/implementations/VSExternalTimeSyncProtocol.java b/src/main/java/protocols/implementations/VSExternalTimeSyncProtocol.java new file mode 100644 index 0000000..f044861 --- /dev/null +++ b/src/main/java/protocols/implementations/VSExternalTimeSyncProtocol.java @@ -0,0 +1,118 @@ +package protocols.implementations; + +import core.VSMessage; +import protocols.VSAbstractProtocol; + +/** + * The class VSExternalTimeSyncProtocol, an implementation of the external + * time synchronisation protocol. + * + * @author Paul C. Buetow + */ +public class VSExternalTimeSyncProtocol extends VSAbstractProtocol { + /** The request time. */ + private long requestTime; + + /** The server is waiting for response, if true. */ + private boolean waitingForResponse; + + /** + * Instantiates a new external time sync protocol object. + */ + public VSExternalTimeSyncProtocol() { + super(VSAbstractProtocol.HAS_ON_CLIENT_START); + setClassname(getClass().toString()); + } + + /* (non-Javadoc) + * @see events.VSAbstractProtocol#onClientInit() + */ + public void onClientInit() { + } + + /* (non-Javadoc) + * @see protocols.VSAbstractProtocol#onClientReset() + */ + public void onClientReset() { + } + + /* (non-Javadoc) + * @see protocols.VSAbstractProtocol#onClientStart() + */ + public void onClientStart() { + requestTime = process.getTime(); + waitingForResponse = true; + + /* Multicast message to all processes */ + VSMessage message = new VSMessage(); + message.setBoolean("isClientRequest", true); + sendMessage(message); + } + + /* (non-Javadoc) + * @see protocols.VSAbstractProtocol#onClientRecv(core.VSMessage) + */ + public void onClientRecv(VSMessage recvMessage) { + if (!recvMessage.getBoolean("isServerResponse")) + return; + + if (waitingForResponse) + waitingForResponse = false; + else + return; + + long recvTime = process.getTime(); + long roundTripTime = recvTime - requestTime; + long serverTime = recvMessage.getLong("time"); + long newTime = serverTime + (long) (roundTripTime / 2); + + log("Server time: " + serverTime + "; RTT: " + roundTripTime + "; Old time: " + recvTime + "; New time: " + newTime + "; Offset: " + (newTime - recvTime)); + + process.setTime(newTime); + } + + /* (non-Javadoc) + * @see protocols.VSAbstractProtocol#onClientSchedule() + */ + public void onClientSchedule() { + } + + /* (non-Javadoc) + * @see events.VSAbstractProtocol#onServerInit() + */ + public void onServerInit() { + } + + /* (non-Javadoc) + * @see protocols.VSAbstractProtocol#onServerReset() + */ + public void onServerReset() { + } + + /* (non-Javadoc) + * @see protocols.VSAbstractProtocol#onServerRecv(core.VSMessage) + */ + public void onServerRecv(VSMessage recvMessage) { + if (!recvMessage.getBoolean("isClientRequest")) + return; + + /* Multicast message to all processes */ + VSMessage message = new VSMessage(); + message.setLong("time", process.getTime()); + message.setBoolean("isServerResponse", true); + sendMessage(message); + } + + /* (non-Javadoc) + * @see protocols.VSAbstractProtocol#onServerSchedule() + */ + public void onServerSchedule() { + } + + /* (non-Javadoc) + * @see protocols.VSAbstractProtocol#toString() + */ + public String toString() { + return super.toString(); + } +} diff --git a/src/main/java/protocols/implementations/VSInternalTimeSyncProtocol.java b/src/main/java/protocols/implementations/VSInternalTimeSyncProtocol.java new file mode 100644 index 0000000..e3bd181 --- /dev/null +++ b/src/main/java/protocols/implementations/VSInternalTimeSyncProtocol.java @@ -0,0 +1,123 @@ +package protocols.implementations; + +import core.VSMessage; +import protocols.VSAbstractProtocol; + +/** + * The class VSInternalTimeSyncProtocol, an implementation of the internal + * time synchronisation protocol. + * + * @author Paul C. Buetow + */ +public class VSInternalTimeSyncProtocol extends VSAbstractProtocol { + /** The waiting for response. */ + private boolean waitingForResponse; + + /** + * Instantiates a new internal time sync protocol. + */ + public VSInternalTimeSyncProtocol() { + super(VSAbstractProtocol.HAS_ON_CLIENT_START); + setClassname(getClass().toString()); + } + + /* (non-Javadoc) + * @see events.VSAbstractProtocol#onClientInit() + */ + public void onClientInit() { + initLong("t_min", 2000, "Max. transmission time", "ms"); + initLong("t_max", 500, "Min. transmission time", "ms"); + } + + /* (non-Javadoc) + * @see protocols.VSAbstractProtocol#onClientReset() + */ + public void onClientReset() { + } + + /* (non-Javadoc) + * @see protocols.VSAbstractProtocol#onClientStart() + */ + public void onClientStart() { + waitingForResponse = true; + + /* Multicast message to all processes */ + VSMessage message = new VSMessage(); + message.setBoolean("isClientRequest", true); + sendMessage(message); + } + + /* (non-Javadoc) + * @see protocols.VSAbstractProtocol#onClientRecv(core.VSMessage) + */ + public void onClientRecv(VSMessage recvMessage) { + /* Ignore all protocol messages which are not a response message, + e.g. itself */ + if (!recvMessage.getBoolean("isServerResponse")) + return; + + if (waitingForResponse) + waitingForResponse = false; + else + return; + + long tMax = getLong("t_max"); + long tMin = getLong("t_min"); + long serverTime = recvMessage.getLong("time"); + long newTime = serverTime + (long) ((tMax + tMin) / 2 ); + + log("Server time: " + serverTime + "; (t_min,t_max): (" + tMin + + "," + tMax + "); Old time: " + process.getTime() + + "; New time: " + newTime + "; Offset: " + + (process.getTime() - newTime)); + + process.setTime(newTime); + } + + /* (non-Javadoc) + * @see protocols.VSAbstractProtocol#onClientSchedule() + */ + public void onClientSchedule() { + } + + /* (non-Javadoc) + * @see events.VSAbstractProtocol#onServerInit() + */ + public void onServerInit() { + } + + /* (non-Javadoc) + * @see protocols.VSAbstractProtocol#onServerReset() + */ + public void onServerReset() { + } + + /* (non-Javadoc) + * @see protocols.VSAbstractProtocol#onServerRecv(core.VSMessage) + */ + public void onServerRecv(VSMessage recvMessage) { + /* Ignore all protocol messages which are not a request message, + e.g. itself */ + if (!recvMessage.getBoolean("isClientRequest")) + return; + + /* Multicast message to all processes */ + VSMessage message = new VSMessage(); + message.setLong("time", process.getTime()); + message.setBoolean("isServerResponse", true); + sendMessage(message); + } + + /* (non-Javadoc) + * @see protocols.VSAbstractProtocol#onServerSchedule() + */ + public void onServerSchedule() { + } + + /* (non-Javadoc) + * @see protocols.VSAbstractProtocol#toString() + */ + public String toString() { + return super.toString(); + } +} diff --git a/src/main/java/protocols/implementations/VSOnePhaseCommitProtocol.java b/src/main/java/protocols/implementations/VSOnePhaseCommitProtocol.java new file mode 100644 index 0000000..4dcfe7e --- /dev/null +++ b/src/main/java/protocols/implementations/VSOnePhaseCommitProtocol.java @@ -0,0 +1,148 @@ +package protocols.implementations; + +import java.util.ArrayList; +import java.util.Vector; + +import core.VSMessage; +import protocols.VSAbstractProtocol; + +/** + * The class VSOnePhaseCommitProtocol, an implementation of the one phase + * commit protocol. + * + * @author Paul C. Buetow + */ +public class VSOnePhaseCommitProtocol extends VSAbstractProtocol { + /* Server variables */ + private boolean ackSent; + + /** + * Instantiates a one phase commit protocol. + */ + public VSOnePhaseCommitProtocol() { + super(VSAbstractProtocol.HAS_ON_SERVER_START); + setClassname(getClass().toString()); + } + + /* (non-Javadoc) + * @see events.VSAbstractProtocol#onServerInit() + */ + public void onServerInit() { + /* Can be changed via GUI variables editor of each process */ + Vector<Integer> vec = new Vector<Integer>(); + vec.add(1); + vec.add(3); + + // TODO: Translate + initVector("pids", vec, "PIDs beteiligter Prozesse"); + initLong("timeout", 2500, "Zeit bis erneute Anfrage", "ms"); + } + + /* (non-Javadoc) + * @see protocols.VSAbstractProtocol#onServerReset() + */ + public void onServerReset() { + if (pids != null) { + pids.clear(); + pids.addAll(getVector("pids")); + } + } + + /* (non-Javadoc) + * @see protocols.VSAbstractProtocol#onServerStart() + */ + public void onServerStart() { + if (pids == null) { + pids = new ArrayList<Integer>(); + pids.addAll(getVector("pids")); + } + + if (pids.size() != 0) { + long timeout = getLong("timeout") + process.getTime(); + /* Will run onServerSchedule() at the specified local time */ + scheduleAt(timeout); + + VSMessage message = new VSMessage(); + message.setBoolean("wantAck", true); + sendMessage(message); + } + } + + /* (non-Javadoc) + * @see protocols.VSAbstractProtocol#onServerRecv(core.VSMessage) + */ + public void onServerRecv(VSMessage recvMessage) { + if (pids.size() == 0) + return; + + if (recvMessage.getBoolean("isAck")) { + Integer pid = recvMessage.getIntegerObj("pid"); + if (pids.contains(pid)) + pids.remove(pid); + else + return; + + log("ACK from process " + pid + " received!"); + + if (pids.size() == 0) { + log("ACKs received from all participating processes! " + + "Committed!"); + + /* Remove the active schedule which has been created in the + onServerStart method */ + removeSchedules(); + } + } + } + + /* (non-Javadoc) + * @see protocols.VSAbstractProtocol#onServerSchedule() + */ + public void onServerSchedule() { + onServerStart(); + } + + /* Client variables, coordinator */ + private ArrayList<Integer> pids; + + /* (non-Javadoc) + * @see events.VSAbstractProtocol#onClientInit() + */ + public void onClientInit() { + } + + /* (non-Javadoc) + * @see protocols.VSAbstractProtocol#onClientReset() + */ + public void onClientReset() { + ackSent = false; + } + + /* (non-Javadoc) + * @see protocols.VSAbstractProtocol#onClientRecv(core.VSMessage) + */ + public void onClientRecv(VSMessage recvMessage) { + if (ackSent) + return; + + VSMessage message = new VSMessage(); + message.setBoolean("isAck", true); + message.setInteger("pid", process.getProcessID()); + sendMessage(message); + ackSent = true; + log("Committed"); + } + + /* (non-Javadoc) + * @see protocols.VSAbstractProtocol#onClientSchedule() + */ + public void onClientSchedule() { + } + + /* (non-Javadoc) + * @see protocols.VSAbstractProtocol#toString() + */ + public String toString() { + return super.toString(); + } +} diff --git a/src/main/java/protocols/implementations/VSPingPongProtocol.java b/src/main/java/protocols/implementations/VSPingPongProtocol.java new file mode 100644 index 0000000..b1f3d20 --- /dev/null +++ b/src/main/java/protocols/implementations/VSPingPongProtocol.java @@ -0,0 +1,110 @@ +package protocols.implementations; + +import core.VSMessage; +import protocols.VSAbstractProtocol; + +/** + * The class VSPingPongProtocol, an implementation of the ping pong protocol. + * + * @author Paul C. Buetow + */ +public class VSPingPongProtocol extends VSAbstractProtocol { + /** The client counter. */ + private int clientCounter; + + /** The server counter. */ + private int serverCounter; + + /** + * Instantiates a new ping pong protocol. + */ + public VSPingPongProtocol() { + super(VSAbstractProtocol.HAS_ON_CLIENT_START); + setClassname(getClass().toString()); + } + + /* (non-Javadoc) + * @see events.VSAbstractProtocol#onClientInit() + */ + public void onClientInit() { + } + + /* (non-Javadoc) + * @see protocols.VSAbstractProtocol#onClientReset() + */ + public void onClientReset() { + clientCounter = 0; + } + + /* (non-Javadoc) + * @see protocols.VSAbstractProtocol#onClientStart() + */ + public void onClientStart() { + VSMessage message = new VSMessage(); + message.setBoolean("fromClient", true); + message.setInteger("counter", ++clientCounter); + super.sendMessage(message); + } + + /* (non-Javadoc) + * @see protocols.VSAbstractProtocol#onClientRecv(core.VSMessage) + */ + public void onClientRecv(VSMessage recvMessage) { + if (!recvMessage.getBoolean("fromServer")) + return; + + super.log("message: " + recvMessage.getInteger("counter")); + + VSMessage message = new VSMessage(); + message.setBoolean("fromClient", true); + message.setInteger("counter", ++clientCounter); + super.sendMessage(message); + } + + /* (non-Javadoc) + * @see protocols.VSAbstractProtocol#onClientSchedule() + */ + public void onClientSchedule() { + } + + /* (non-Javadoc) + * @see events.VSAbstractProtocol#onServerInit() + */ + public void onServerInit() { + } + + /* (non-Javadoc) + * @see protocols.VSAbstractProtocol#onServerReset() + */ + public void onServerReset() { + serverCounter = 0; + } + + /* (non-Javadoc) + * @see protocols.VSAbstractProtocol#onServerRecv(core.VSMessage) + */ + public void onServerRecv(VSMessage recvMessage) { + if (!recvMessage.getBoolean("fromClient")) + return; + + super.log("message: " + recvMessage.getInteger("counter")); + + VSMessage message = new VSMessage(); + message.setBoolean("fromServer", true); + message.setInteger("counter", ++serverCounter); + super.sendMessage(message); + } + + /* (non-Javadoc) + * @see protocols.VSAbstractProtocol#onServerSchedule() + */ + public void onServerSchedule() { + } + + /* (non-Javadoc) + * @see protocols.VSAbstractProtocol#toString() + */ + public String toString() { + return super.toString() + "; New message afterwards"; + } +} diff --git a/src/main/java/protocols/implementations/VSReliableMulticastProtocol.java b/src/main/java/protocols/implementations/VSReliableMulticastProtocol.java new file mode 100644 index 0000000..170533a --- /dev/null +++ b/src/main/java/protocols/implementations/VSReliableMulticastProtocol.java @@ -0,0 +1,143 @@ +package protocols.implementations; + +import java.util.ArrayList; +import java.util.Vector; + +import core.VSMessage; +import protocols.VSAbstractProtocol; + +/** + * The class VSReliableMulticastProtocol, an implementation of the reliable + * multicast protocol. + * + * @author Paul C. Buetow + */ +public class VSReliableMulticastProtocol extends VSAbstractProtocol { + /** + * Instantiates a two phase commit protocol object. + */ + public VSReliableMulticastProtocol() { + super(VSAbstractProtocol.HAS_ON_CLIENT_START); + setClassname(getClass().toString()); + } + + /** PIDs of all processes which still have to send an ACK */ + private ArrayList<Integer> pids; + + /* (non-Javadoc) + * @see events.VSAbstractProtocol#onClientInit() + */ + public void onClientInit() { + Vector<Integer> vec = new Vector<Integer>(); + vec.add(1); + vec.add(3); + + super.initVector("pids", vec, "PIDs beteiligter Prozesse"); + super.initLong("timeout", 2500, "Zeit bis erneute Anfrage", "ms"); + } + + /* (non-Javadoc) + * @see protocols.VSAbstractProtocol#onClientReset() + */ + public void onClientReset() { + if (pids != null) { + pids.clear(); + pids.addAll(getVector("pids")); + } + } + + /* (non-Javadoc) + * @see protocols.VSAbstractProtocol#onClientStart() + */ + public void onClientStart() { + if (pids == null) { + pids = new ArrayList<Integer>(); + pids.addAll(getVector("pids")); + } + + if (pids.size() != 0) { + long timeout = getLong("timeout") + process.getTime(); + /* Will run onClientSchedule() at the specified local time */ + scheduleAt(timeout); + + VSMessage message = new VSMessage(); + message.setBoolean("isMulticast", true); + sendMessage(message); + } + } + + /* (non-Javadoc) + * @see protocols.VSAbstractProtocol#onClientRecv(core.VSMessage) + */ + public void onClientRecv(VSMessage recvMessage) { + if (pids.size() != 0 && recvMessage.getBoolean("isAck")) { + Integer pid = recvMessage.getIntegerObj("pid"); + + if (pids.contains(pid)) + pids.remove(pid); + else + return; + + log("ACK from process " + pid + " received!"); + + + if (pids.size() == 0) { + log("ACKs from all involved processes received!"); + + /* Remove the active schedule which has been created in the + onClientStart method */ + removeSchedules(); + } + } + } + + /* (non-Javadoc) + * @see protocols.VSAbstractProtocol#onClientSchedule() + */ + public void onClientSchedule() { + onClientStart(); + } + + /** True if ACK has been sent already */ + private boolean ackSent; + + /* (non-Javadoc) + * @see events.VSAbstractProtocol#onServerInit() + */ + public void onServerInit() { + } + + /* (non-Javadoc) + * @see protocols.VSAbstractProtocol#onServerReset() + */ + public void onServerReset() { + ackSent = false; + } + + /* (non-Javadoc) + * @see protocols.VSAbstractProtocol#onServerRecv(core.VSMessage) + */ + public void onServerRecv(VSMessage recvMessage) { + if (recvMessage.getBoolean("isMulticast")) { + VSMessage message = new VSMessage(); + message.setBoolean("isAck", true); + message.setInteger("pid", process.getProcessID()); + sendMessage(message); + + if (ackSent) { + log("ACK sent again"); + + } else { + log("ACK sent"); + + ackSent = true; + } + } + } + + /* (non-Javadoc) + * @see protocols.VSAbstractProtocol#onServerSchedule() + */ + public void onServerSchedule() { + } +} diff --git a/src/main/java/protocols/implementations/VSTwoPhaseCommitProtocol.java b/src/main/java/protocols/implementations/VSTwoPhaseCommitProtocol.java new file mode 100644 index 0000000..8f9e4a3 --- /dev/null +++ b/src/main/java/protocols/implementations/VSTwoPhaseCommitProtocol.java @@ -0,0 +1,196 @@ +package protocols.implementations; + +import java.util.ArrayList; +import java.util.Vector; + +import core.VSMessage; +import protocols.VSAbstractProtocol; + +/** + * The class VSTwoPhaseCommitProtocol, an implementation of the two phase + * commit protocol. + * + * @author Paul C. Buetow + */ +public class VSTwoPhaseCommitProtocol extends VSAbstractProtocol { + /** + * Instantiates a two phase commit protocol object. + */ + public VSTwoPhaseCommitProtocol() { + super(VSAbstractProtocol.HAS_ON_SERVER_START); + setClassname(getClass().toString()); + } + + /** PIDs of all processes which still have to vote */ + private ArrayList<Integer> votePids; + + /** PIDs of all processes which have to acknowledge that they recv the + * global vote result + */ + private ArrayList<Integer> ackPids; + + /** The gloal vote result */ + private boolean voteResult; + + /* (non-Javadoc) + * @see events.VSAbstractProtocol#onServerInit() + */ + public void onServerInit() { + Vector<Integer> vec = new Vector<Integer>(); + vec.add(2); + vec.add(3); + + initVector("pids", vec, "PIDs beteiligter Prozesse"); + initLong("timeout", 2500, "Zeit bis erneute Anfrage", "ms"); + } + + /* (non-Javadoc) + * @see protocols.VSAbstractProtocol#onServerReset() + */ + public void onServerReset() { + if (votePids != null) { + voteResult = true; + votePids.clear(); + votePids.addAll(getVector("pids")); + ackPids.clear(); + ackPids.addAll(getVector("pids")); + } + } + + /* (non-Javadoc) + * @see protocols.VSAbstractProtocol#onServerStart() + */ + public void onServerStart() { + if (votePids == null) { + voteResult = true; + votePids = new ArrayList<Integer>(); + votePids.addAll(getVector("pids")); + ackPids = new ArrayList<Integer>(); + ackPids.addAll(getVector("pids")); + } + + if (votePids.size() != 0) { + long timeout = getLong("timeout") + process.getTime(); + /* Will run onServerSchedule() at the specified local time */ + scheduleAt(timeout); + + VSMessage message = new VSMessage(); + message.setBoolean("wantVote", true); + sendMessage(message); + + } else if (ackPids.size() != 0) { + long timeout = getLong("timeout") + process.getTime(); + /* Will run onServerSchedule() at the specified local time */ + scheduleAt(timeout); + + VSMessage message = new VSMessage(); + message.setBoolean("isVoteResult", true); + message.setBoolean("voteResult", voteResult); + sendMessage(message); + } + } + + /* (non-Javadoc) + * @see protocols.VSAbstractProtocol#onServerRecv(core.VSMessage) + */ + public void onServerRecv(VSMessage recvMessage) { + if (votePids.size() != 0 && recvMessage.getBoolean("isVote")) { + Integer pid = recvMessage.getIntegerObj("pid"); + if (votePids.contains(pid)) + votePids.remove(pid); + else + return; + + boolean vote = recvMessage.getBoolean("vote"); + log("Vote from process " + pid + " received! Result: " + vote); + + if (!vote) + voteResult = false; + + if (votePids.size() == 0) { + log("Votes from all involved processes received! Global result: " + voteResult); + + /* Remove the active schedule which has been created in the + onServerStart method */ + removeSchedules(); + /* Create a new schedule and send the vote result */ + onServerStart(); + } + + } else if (ackPids.size() != 0 && recvMessage.getBoolean("isAck")) { + Integer pid = recvMessage.getIntegerObj("pid"); + if (ackPids.contains(pid)) + ackPids.remove(pid); + else + return; + + if (ackPids.size() == 0) { + /* Remove the active schedule which has been created in the + onServerStart method */ + removeSchedules(); + log("All participants have received the vote"); + } + } + } + + /* (non-Javadoc) + * @see protocols.VSAbstractProtocol#onServerSchedule() + */ + public void onServerSchedule() { + onServerStart(); + } + + /* Server variables */ + private boolean voteSent; + private boolean myVote; + + /* (non-Javadoc) + * @see events.VSAbstractProtocol#onClientInit() + */ + public void onClientInit() { + initInteger("ackProb", 50, "Festschreibw'keit", 0, 100, "%"); + } + + /* (non-Javadoc) + * @see protocols.VSAbstractProtocol#onClientReset() + */ + public void onClientReset() { + voteSent = false; + } + + /* (non-Javadoc) + * @see protocols.VSAbstractProtocol#onClientRecv(core.VSMessage) + */ + public void onClientRecv(VSMessage recvMessage) { + if (recvMessage.getBoolean("wantVote")) { + if (!voteSent) { + voteSent = true; + myVote = process.getRandomPercentage() <= getInteger("ackProb"); + } + + VSMessage message = new VSMessage(); + message.setBoolean("isVote", true); + message.setBoolean("vote", myVote); + message.setInteger("pid", process.getProcessID()); + sendMessage(message); + + log("Vote " + myVote + " sent"); + + + } else if (recvMessage.getBoolean("isVoteResult")) { + boolean voteResult = recvMessage.getBoolean("voteResult"); + log("Global voting result received. Result: " + voteResult); + + VSMessage message = new VSMessage(); + message.setBoolean("isAck", true); + message.setInteger("pid", process.getProcessID()); + sendMessage(message); + } + } + + /* (non-Javadoc) + * @see protocols.VSAbstractProtocol#onClientSchedule() + */ + public void onClientSchedule() { + } +} diff --git a/src/main/java/serialize/VSNotSerializable.java b/src/main/java/serialize/VSNotSerializable.java new file mode 100644 index 0000000..f7bec1d --- /dev/null +++ b/src/main/java/serialize/VSNotSerializable.java @@ -0,0 +1,11 @@ +package serialize; + +/** + * The Interface VSNotSerializable, this interface has no methods given and is + * being used to distinguish if the simulator should not serialize an object + * of the implementing class. + * + * @author Paul C. Buetow + */ +public interface VSNotSerializable { +} diff --git a/src/main/java/serialize/VSSerializable.java b/src/main/java/serialize/VSSerializable.java new file mode 100644 index 0000000..c115ad9 --- /dev/null +++ b/src/main/java/serialize/VSSerializable.java @@ -0,0 +1,34 @@ +package serialize; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; + +/** + * The Interface VSSerializable, all classes which take part of the serialize/ + * deserialize proces are implementing this interface. It is preferred over the + * standard Serializable interface of Java because we want not serialize the + * whole class tree of each class but certain variables only! + * + * @author Paul C. Buetow + */ +public interface VSSerializable { + /** + * Serializes + * + * @param serialize The serialize object + * @param objectOutputStream The object output stream + */ + public void serialize(VSSerialize serialize, + ObjectOutputStream objectOutputStream) + throws IOException; + /** + * Deserializes + * + * @param serialize The serialize object + * @param objectInputStream The object input stream + */ + public void deserialize(VSSerialize serialize, + ObjectInputStream objectInputStream) + throws IOException, ClassNotFoundException; +} diff --git a/src/main/java/serialize/VSSerialize.java b/src/main/java/serialize/VSSerialize.java new file mode 100644 index 0000000..a6d3580 --- /dev/null +++ b/src/main/java/serialize/VSSerialize.java @@ -0,0 +1,278 @@ +package serialize; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.util.HashMap; + +import javax.swing.JFileChooser; + +import prefs.VSDefaultPrefs; +import prefs.VSPrefs; +import prefs.VSSerializablePrefs; +import simulator.VSSimulator; +import simulator.VSSimulatorFrame; + +/** + * The class VSSerialize, this class helps do serialize/deserialize a saved + * simulator! + * + * @author Paul C. Buetow + */ +public final class VSSerialize { + /** True if debug mode of serialization/deserialization */ + public static final boolean DEBUG = true; + + /** The last filename used for saveing/opening*/ + public static volatile String LAST_FILENAME = null; + + /** For temp object storage */ + private static HashMap<String,Object> objects; + + /** Holds the current VSSerialize object */ + private static VSSerialize serialize; + + /** + * Creates the VSSerialize object. + */ + public VSSerialize() { + init(); + } + + /** + * Initializes the helper. + */ + private void init() { + serialize = this; + objects = new HashMap<String,Object>(); + } + + /** + * Gets the current VSSerialize object. + * + * @return The current serialize object + */ + public static VSSerialize getSerialize() { + return serialize; + } + + /** + * Sets an object. + * + * @param key The object key + * @param object The object itself + */ + public void setObject(String key, Object object) { + if (DEBUG) + System.out.println("setObject("+key+")"); + + objects.put(key, object); + } + + /** + * Sets an object. + * + * @param num The object number + * @param key The object key + * @param object The object itself + */ + public void setObject(int num, String key, Object object) { + if (DEBUG) + System.out.println("setObject("+key+":"+num+")"); + + objects.put(key + ":" + num, object); + } + + /** + * Checks if an object exists. + * + * @param num The object number + * @param key The object key + * + * @return true, if the object exists. false, if the object does not exist + */ + public boolean objectExists(int num, String key) { + return null != objects.get(key + ":" + num); + } + + /** + * Gets an object. + * + * @param num The object number + * @param key The object key + * + * @return The object itself + */ + public Object getObject(int num, String key) { + Object object = objects.get(key + ":" + num); + + if (object == null) { + System.err.println("No such deserialization helper key " + key + ":" + num); + System.exit(1); + } + + return object; + } + + /** + * Gets an object. + * + * @param key The object key + * + * @return The object itself + */ + public Object getObject(String key) { + Object object = objects.get(key); + + if (object == null) { + System.err.println("No such deserialization helper key " + key); + System.exit(1); + } + + return object; + } + + /** + * Saves the given simulator to the given filename. + * + * @param filename The filename + * @param simulator The simulator + */ + public void saveSimulator(String filename, VSSimulator simulator) { + if (filename == null) { + saveSimulator(simulator); + return; + } + + LAST_FILENAME = filename; + + try { + FileOutputStream fileOutputStream = + new FileOutputStream(filename); + ObjectOutputStream objectOutputStream = + new ObjectOutputStream(fileOutputStream); + + VSSerializablePrefs prefs = (VSSerializablePrefs) simulator.getPrefs(); + prefs.serialize(this, objectOutputStream); + simulator.serialize(this, objectOutputStream); + + } catch (IOException e) { + //e.printStackTrace(); + + } finally { + //objectOutputStream.close(); + } + } + + /** + * Saves the given simulator to a file choosen by the file chooser. + * + * @param simulator The simulator + */ + public void saveSimulator(VSSimulator simulator) { + VSPrefs prefs = simulator.getPrefs(); + VSSimulatorFrame simulatorFrame = simulator.getSimulatorFrame(); + + String saveText = prefs.getString("lang.save"); + JFileChooser fileChooser = new JFileChooser(new File(".").getPath()); + fileChooser.setMultiSelectionEnabled(false); + fileChooser.addChoosableFileFilter(createFileFilter(prefs)); + fileChooser.setApproveButtonText(saveText); + + if (fileChooser.showOpenDialog(simulatorFrame) == + JFileChooser.APPROVE_OPTION) { + String fileName = fileChooser.getSelectedFile().getAbsolutePath(); + System.out.println(saveText + ": " + fileName); + saveSimulator(fileName, simulator); + } + } + + /** + * Opens a simulator from the given filename. + * + * @param filename The filename. + * @param simulatorFrame The simulator frame + * + * @return The simulator object, and null if no success + */ + public VSSimulator openSimulator(String filename, + VSSimulatorFrame simulatorFrame) { + VSSimulator simulator = null; + simulatorFrame.resetCurrentSimulator(); + LAST_FILENAME = filename; + + try { + FileInputStream fileInputStream = new FileInputStream(filename); + ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream); + + VSDefaultPrefs prefs = new VSDefaultPrefs(); + prefs.deserialize(this, objectInputStream); + prefs.addWithDefaults(); + + this.setObject("prefs", prefs); + + simulator = new VSSimulator(prefs, simulatorFrame); + simulatorFrame.addSimulator(simulator); + simulator.deserialize(this, objectInputStream); + + } catch (Exception e) { + e.printStackTrace(); + + } finally { + //objectInputStream.close(); + } + + return simulator; + } + + /** + * Opens a simulator from a file selected from a file chooser. + * + * @param simulatorFrame The simulator frame + * + * @return The simulator object, and null if no success + */ + public VSSimulator openSimulator(VSSimulatorFrame simulatorFrame) { + VSPrefs prefs = simulatorFrame.getPrefs(); + + String openText = prefs.getString("lang.open"); + JFileChooser fileChooser = new JFileChooser( + new File(".").getPath()); + fileChooser.setMultiSelectionEnabled(false); + fileChooser.addChoosableFileFilter(createFileFilter(prefs)); + fileChooser.setApproveButtonText(openText); + + if (fileChooser.showOpenDialog(simulatorFrame) == + JFileChooser.APPROVE_OPTION) { + String fileName = fileChooser.getSelectedFile().getAbsolutePath(); + System.out.println(openText + ": " + fileName); + return openSimulator(fileName, simulatorFrame); + } + + return null; + } + + /** + * Creates a file filter for the file choosers + * + * @param prefs The default prefs + */ + private javax.swing.filechooser.FileFilter createFileFilter( + final VSPrefs prefs) { + return new javax.swing.filechooser.FileFilter() { + public boolean accept(File file) { + if (file.isDirectory()) + return true; + return file.getName().toLowerCase().endsWith(".dat"); + } + + public String getDescription() { + return prefs.getString("lang.dat"); + } + }; + } + +} diff --git a/src/main/java/simulator/VSCreateTask.java b/src/main/java/simulator/VSCreateTask.java new file mode 100644 index 0000000..9a6426b --- /dev/null +++ b/src/main/java/simulator/VSCreateTask.java @@ -0,0 +1,179 @@ +package simulator; + +import core.VSInternalProcess; +import core.VSTask; +import events.VSAbstractEvent; +import events.VSRegisteredEvents; +import events.internal.VSProtocolEvent; + +/** + * The class VSCreateTask, an object of this class represents how new + * VSTask objects are to be created using JComboBox selections of the + * GUI editor.. + * + * @author Paul C. Buetow + */ +public class VSCreateTask { + /** The event classname. */ + private String eventClassname; + + /** The create task menu string. */ + private String menuText; + + /** The protocol classname. */ + private String protocolClassname; + + /** The shortname. */ + private String shortname; + + /** The task is a protocol activation. */ + private boolean isProtocolActivation; + + /** The task is a protocol deactivation. */ + private boolean isProtocolDeactivation; + + /** The task is a client protocol. */ + private boolean isClientProtocol; + + /** True, if the task is a client request. false, if the task is a + * server request + */ + private boolean isRequest; + + /** + * Instantiates a new VSCreateTask object. + * + * @param menuText the menu text + * @param eventClassname the event classname + */ + public VSCreateTask(String menuText, String eventClassname) { + this.menuText = menuText; + this.eventClassname = eventClassname; + } + + /** + * Instantiates a new VSCreateTask dummy object. + * + * @param menuText the menu text + */ + public VSCreateTask(String menuText) { + this.menuText = menuText; + this.eventClassname = null; + } + + /** + * Sets if it is a protocol activation task. + * + * @param isProtocolActivation true, if it is a protocol activation + * task. + */ + public void isProtocolActivation(boolean isProtocolActivation) { + this.isProtocolActivation = isProtocolActivation; + + if (isProtocolActivation) + isProtocolDeactivation(false); + } + + /** + * Sets if it is a protocol deactivation task. + * + * @param isProtocolDeactivation true, if it is a protocol deactivation + * task. + */ + public void isProtocolDeactivation(boolean isProtocolDeactivation) { + this.isProtocolDeactivation = isProtocolDeactivation; + + if (isProtocolDeactivation) + isProtocolActivation(false); + } + + /** + * Sets if it is a client protocol. + * + * @param isClientProtocol the is client protocol + */ + public void isClientProtocol(boolean isClientProtocol) { + this.isClientProtocol = isClientProtocol; + } + + /** + * Sets if it is a client request. + * + * @param isRequest the is client request + */ + public void isRequest(boolean isRequest) { + this.isRequest = isRequest; + } + + /** + * Checks if it is a dummy object.. + * + * @return true, if dummy + */ + public boolean isDummy() { + return eventClassname == null; + } + + /** + * Sets the protocol classname. + * + * @param protocolClassname the protocol classname + */ + public void setProtocolClassname(String protocolClassname) { + this.protocolClassname = protocolClassname; + } + + /** + * Sets the shortname. + * + * @param shortname the shortname + */ + public void setShortname(String shortname) { + this.shortname = shortname; + } + + /** + * Gets the create tasks menu text. + * + * @return The text + */ + public String getMenuText() { + return menuText; + } + + /** + * Creates the task. + * + * @param process the process + * @param time the time + * @param localTimedTask the local timed task + * + * @return the new task + */ + public VSTask createTask(VSInternalProcess process, long time, + boolean localTimedTask) { + VSAbstractEvent event = null; + + if (isRequest) { + event = process.getProtocolObject(eventClassname); + + } else { + event = VSRegisteredEvents.createEventInstanceByClassname( + eventClassname, process); + } + + event.init(process); + if (shortname != null) + event.setShortname(shortname); + + if (isProtocolActivation || isProtocolDeactivation) { + VSProtocolEvent protocolEvent = (VSProtocolEvent) event; + protocolEvent.setProtocolClassname(protocolClassname); + protocolEvent.isProtocolActivation(isProtocolActivation); + protocolEvent.isClientProtocol(isClientProtocol); + } + + return new VSTask(time, process, event, localTimedTask); + } +} + diff --git a/src/main/java/simulator/VSLogging.java b/src/main/java/simulator/VSLogging.java new file mode 100644 index 0000000..66cb563 --- /dev/null +++ b/src/main/java/simulator/VSLogging.java @@ -0,0 +1,201 @@ +package simulator; + +import java.util.ArrayList; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import javax.swing.JTextArea; + +import utils.VSTools; + +/** + * The class VSLogging, an object of this class is responsible for the loging + * of text messages into the simulator's loging window. + * + * @author Paul C. Buetow + */ +public class VSLogging { + /** The loging area. */ + private JTextArea logingArea; + + /** The filter text. */ + private String filterText; + + /** The pause lines. Used for cacheing the loging if the loging is + * deactivated for a while + */ + private ArrayList<StringBuffer> pauseLines; + + /** The loging lines. */ + private ArrayList<StringBuffer> logingLines; + + /** The simulator canvas. */ + private VSSimulatorVisualization simulatorVisualization; + + /** The loging messages are filtered. */ + private boolean isFiltered; + + /** The loging is paused. */ + private boolean isPaused; + + /** The filter pattern. */ + private Pattern filterPattern; + + /** + * Instantiates a new VSLogging object. + */ + public VSLogging() { + logingArea = new JTextArea(0, 0); + logingArea.setEditable(false); + logingArea.setLineWrap(true); + logingArea.setWrapStyleWord(true); + logingLines = new ArrayList<StringBuffer>(); + pauseLines = new ArrayList<StringBuffer>(); + filterText = ""; + } + + /** + * Sets the simulator canvas. + * + * @param sv the simulator canvas + */ + public void setSimulatorCanvas(VSSimulatorVisualization sv) { + this.simulatorVisualization = sv; + } + + /** + * Gets the loging area. + * + * @return the loging area + */ + public JTextArea getLoggingArea() { + return logingArea; + } + + /** + * Loggs a message using the global time. + * + * @param message the message + */ + public void log(String message) { + if (simulatorVisualization == null) + log(message, 0); + else + log(message, simulatorVisualization.getTime()); + } + + /** + * Loggs a message using the specified time. + * + * @param message the message + * @param time the time + */ + public synchronized void log(String message, long time) { + StringBuffer buffer = new StringBuffer(); + buffer.append(VSTools.getTimeString(time)); + buffer.append(": "); + buffer.append(message); + + if (isPaused) + pauseLines.add(buffer); + else + logFiltered(buffer); + } + + /** + * Sets if the loging is paused. + * + * @param isPaused true, if the loging is paused + */ + public synchronized void isPaused(boolean isPaused) { + this.isPaused = isPaused; + + if (!isPaused) { + for (StringBuffer buffer : pauseLines) + logFiltered(buffer); + + pauseLines.clear(); + } + } + + /** + * If the loging is filtered, it's using the pattern matching. + * + * @param buffer the loging buffer to filter + */ + private void logFiltered(StringBuffer buffer) { + logingLines.add(buffer); + if (!isFiltered) { + logingArea.append(buffer.toString()+"\n"); + logingArea.setCaretPosition( + logingArea.getDocument().getLength()); + + } else if (filterPattern != null && + filterPattern.matcher(buffer).find()) { + logingArea.append(buffer.toString()+"\n"); + logingArea.setCaretPosition( + logingArea.getDocument().getLength()); + } + } + + /** + * Checks if the loging is filtered. + * + * @param isFiltered true, if the loging is filtered + */ + public synchronized void isFiltered(boolean isFiltered) { + this.isFiltered = isFiltered; + + if (!isFiltered) + setFilterText(""); + else + filter(); + } + + /** + * Sets the filter text. + * + * @param filterText the new filter text + */ + public synchronized void setFilterText(String filterText) { + this.filterText = filterText; + filter(); + } + + /** + * Clears the loging. + */ + public synchronized void clear() { + logingLines.clear(); + pauseLines.clear(); + logingArea.setText(""); + } + + /** + * Filters the loging. + */ + private void filter() { + try { + filterPattern = Pattern.compile(filterText); + StringBuffer buffer = new StringBuffer(); + + for (StringBuffer line : logingLines) { + if (isFiltered) { + Matcher matcher = filterPattern.matcher(line); + if (matcher.find()) { + buffer.append(line); + buffer.append("\n"); + } + } else { + buffer.append(line); + buffer.append("\n"); + } + } + logingArea.setText(buffer.toString()); + + } catch (Exception e) { + filterPattern = null; + logingArea.setText(""); + } + } +} diff --git a/src/main/java/simulator/VSMain.java b/src/main/java/simulator/VSMain.java new file mode 100644 index 0000000..34a21b7 --- /dev/null +++ b/src/main/java/simulator/VSMain.java @@ -0,0 +1,70 @@ +package simulator; + +import java.awt.Component; +import java.util.Locale; + +import javax.swing.UIManager; + +import events.VSRegisteredEvents; +import prefs.VSDefaultPrefs; +import prefs.VSPrefs; + +/** + * The class VSMain. This class contains the static main method. The simulator + * starts here! + * + * @author Paul C. Buetow + */ +public class VSMain { + /** The global preferences */ + public static VSPrefs prefs; + + /** + * Instantiates a new VSMain object. + * + * @param prefs the prefs + */ + public VSMain(VSPrefs prefs) { + init(prefs, null); + } + + /** + * Instantiates a new VSMain object + * + * @param prefs the prefs + * @param relativeTo the component to open the window relative to + */ + public VSMain(VSPrefs prefs, Component relativeTo) { + init(prefs, relativeTo); + } + + /** + * Inits the VSMain object. + * + * @param prefs the prefs + * @param relativeTo the component to open the window relative to + */ + private void init(VSPrefs prefs, Component relativeTo) { + //VSSimulatorFrame simulatorFrame = + VSMain.prefs = prefs; + new VSSimulatorFrame(prefs, relativeTo); + } + + /** + * The main method. + * + * @param args the arguments + */ + public static void main(String[] args) { + try { + UIManager.setLookAndFeel( + UIManager.getCrossPlatformLookAndFeelClassName()); + } catch (Exception e) { } + + Locale.setDefault(Locale.GERMAN); + javax.swing.JPopupMenu.setDefaultLightWeightPopupEnabled(false); + VSPrefs prefs = VSDefaultPrefs.init(); + VSRegisteredEvents.init(prefs); + new VSMain(prefs); + } +} diff --git a/src/main/java/simulator/VSMenuItemStates.java b/src/main/java/simulator/VSMenuItemStates.java new file mode 100644 index 0000000..941dbf5 --- /dev/null +++ b/src/main/java/simulator/VSMenuItemStates.java @@ -0,0 +1,109 @@ +package simulator; + +/** + * The class VSMenuItemStates. Used by the VSSimulator to update the + * "simulator" bar of the VSSimulatorFrame. + * + * @author Paul C. Buetow + */ +public class VSMenuItemStates { + /** The pause state. */ + private volatile boolean pause; + + /** The replay state. */ + private volatile boolean replay; + + /** The reset state. */ + private volatile boolean reset; + + /** The start state. */ + private volatile boolean start; + + /** + * Instantiates a new VSMenuItemStates object. + * + * @param pause the pause state + * @param replay the replay state + * @param reset the reset state + * @param start the start state + */ + public VSMenuItemStates(boolean pause, boolean replay, boolean reset, + boolean start) { + this.pause = pause; + this.replay = replay; + this.reset = reset; + this.start = start; + } + + /** + * Sets the pause state. + * + * @param pause the new pause state + */ + public void setPause(boolean pause) { + this.pause = pause; + } + + /** + * Sets the replay state. + * + * @param replay the new replay state + */ + public void setReplay(boolean replay) { + this.replay = replay; + } + + /** + * Sets the reset state. + * + * @param reset the new reset state + */ + public void setReset(boolean reset) { + this.reset = reset; + } + + /** + * Sets the start state. + * + * @param start the new start state + */ + public void setStart(boolean start) { + this.start = start; + } + + /** + * Gets the pause state. + * + * @return the pause state + */ + public boolean getPause() { + return pause; + } + + /** + * Gets the replay state. + * + * @return the replay state + */ + public boolean getReplay() { + return replay; + } + + /** + * Gets the reset state. + * + * @return the reset state + */ + public boolean getReset() { + return reset; + } + + /** + * Gets the start state. + * + * @return the start state + */ + public boolean getStart() { + return start; + } +} diff --git a/src/main/java/simulator/VSSimulator.java b/src/main/java/simulator/VSSimulator.java new file mode 100644 index 0000000..4965a71 --- /dev/null +++ b/src/main/java/simulator/VSSimulator.java @@ -0,0 +1,1536 @@ +package simulator; + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.GridBagLayout; +import java.awt.GridLayout; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Vector; + +import javax.swing.AbstractButton; +import javax.swing.AbstractCellEditor; +import javax.swing.BoxLayout; +import javax.swing.ButtonModel; +import javax.swing.JButton; +import javax.swing.JCheckBox; +import javax.swing.JComboBox; +import javax.swing.JLabel; +import javax.swing.JMenuItem; +import javax.swing.JPanel; +import javax.swing.JPopupMenu; +import javax.swing.JScrollPane; +import javax.swing.JSplitPane; +import javax.swing.JTabbedPane; +import javax.swing.JTable; +import javax.swing.JTextArea; +import javax.swing.JTextField; +import javax.swing.ListSelectionModel; +import javax.swing.SwingUtilities; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; +import javax.swing.table.AbstractTableModel; +import javax.swing.table.TableCellEditor; +import javax.swing.table.TableColumn; + +import core.VSInternalProcess; +import core.VSTask; +import core.VSTaskManager; +import events.VSRegisteredEvents; +import exceptions.VSNegativeNumberException; +import prefs.VSPrefs; +import prefs.editors.VSProcessEditor; +import serialize.VSSerializable; +import serialize.VSSerialize; + +/** + * The class VSSimulator, an object of this class represents a whole simulator. + * It may be, that several parallel simulators exist. They are independent + * fron each other. + * + * @author Paul C. Buetow + */ +public class VSSimulator extends JPanel implements VSSerializable { + /** The serial version uid */ + private static final long serialVersionUID = 1L; + + /** The global text fields. */ + private ArrayList<String> globalTextFields; + + /** The local text fields. */ + private ArrayList<String> localTextFields; + + /** The create tasks array list. */ + private ArrayList<VSCreateTask> createTasks; + + /** The filter active check box. */ + private JCheckBox filterActiveCheckBox; + + /** The lamport active check box. */ + private JCheckBox lamportActiveCheckBox; + + /** The vector time active check box. */ + private JCheckBox vectorTimeActiveCheckBox; + + /** The global pid combo box. */ + private JComboBox<String> globalPIDComboBox; + + /** The local pid combo box. */ + private JComboBox<String> localPIDComboBox; + + /** The processes combo box. */ + private JComboBox<String> processesComboBox; + + /** The local add panel. */ + private JPanel localAddPanel; + + /** The local panel. */ + private JPanel localPanel; + + /** The loging panel. */ + private JPanel logingPanel; + + /** The split pane1. */ + private JSplitPane splitPane1; + + /** The split pane h. */ + private JSplitPane splitPaneH; + + /** The split pane v. */ + private JSplitPane splitPaneV; + + /** The tabbed pane. */ + private JTabbedPane tabbedPane; + + /** The loging area. */ + private JTextArea logingArea; + + /** The filter text field. */ + private JTextField filterTextField; + + /** The global text field. */ + private JTextField globalTextField; + + /** The local text field. */ + private JTextField localTextField; + + /** The thread. */ + private Thread thread; + + /** The loging. */ + private VSLogging loging; + + /** The menu item states. */ + private VSMenuItemStates menuItemStates; + + /** The prefs. */ + private VSPrefs prefs; + + /** The simulator canvas. */ + private VSSimulatorVisualization simulatorVisualization; + + /** The simulator frame. */ + private VSSimulatorFrame simulatorFrame; + + /** The task manager. */ + private VSTaskManager taskManager; + + /** The task manager global model. */ + private VSTaskManagerTableModel taskManagerGlobalModel; + + /** The task manager local model. */ + private VSTaskManagerTableModel taskManagerLocalModel; + + /** The task manager global editor. */ + private VSTaskManagerCellEditor taskManagerGlobalEditor; + + /** The task manager local editor. */ + private VSTaskManagerCellEditor taskManagerLocalEditor; + + /** The last selected process num. */ + private int lastSelectedProcessNum; + + /** The last expert state. */ + private boolean lastExpertState; + + /** The simulator counter. */ + private static int simulatorCounter; + + /** The simulator num. */ + private static volatile int simulatorNum; + + /** + * The class VSTaskManagerTableModel, an object of this class handles + * the task manager's JTable. + */ + private class VSTaskManagerTableModel extends AbstractTableModel + implements MouseListener { + /** the serial version uid */ + private static final long serialVersionUID = 1l; + + /** The Constant LOCAL. */ + public static final boolean LOCAL = true; + + /** The Constant GLOBAL. */ + public static final boolean GLOBAL = false; + + /** The Constant ALL_PROCESSES. */ + // public static final boolean ALL_PROCESSES = true; + + /** The Constant ONE_PROCESS. */ + public static final boolean ONE_PROCESS = false; + + /** The tasks. */ + private ArrayList<VSTask> tasks; + + /** The column names. */ + private String columnNames[]; + + /** The num columns. */ + private int numColumns; + + /** The table. */ + //private JTable table; + + /** The editor. */ + //private VSTaskManagerCellEditor editor; + + /** + * Instantiates a new VSTaskManagerTableModel object + * + * @param process the process + * @param localTask true, if this table manages the local task. false, + * if this table manages the global tasks. + */ + public VSTaskManagerTableModel(VSInternalProcess process, + boolean localTask) { + tasks = new ArrayList<VSTask>(); + set(process, localTask, ONE_PROCESS); + columnNames = new String[3]; + columnNames[0]= prefs.getString("lang.time") + " (ms)"; + columnNames[1] = prefs.getString("lang.process.id"); + columnNames[2] = prefs.getString("lang.event"); + numColumns = 3; + } + + /** + * Sets the table. + * + * @param table the table + */ + public void setTable(JTable table) { + /* Maybe needed for future usage */ + //this.table = table; + } + + /** + * Sets the editor. + * + * @param editor the editor + */ + public void setEditor(VSTaskManagerCellEditor editor) { + /* Maybe needed for future usage */ + //this.editor = editor; + } + + /** + * Sets new values. + * + * @param process the process + * @param localTasks true, if this table manages the local tasks. false + * if this table manages the global tasks. + * @param allProcesses true, if this table shows tasks of all processes. + * false, if this table only shows tasks of the specified process. + */ + public void set(VSInternalProcess process, boolean localTasks, + boolean allProcesses) { + + if (allProcesses) { + this.tasks = localTasks + ? taskManager.getLocalTasks() + : taskManager.getGlobalTasks(); + } else { + this.tasks = localTasks + ? taskManager.getProcessLocalTasks(process) + : taskManager.getProcessGlobalTasks(process); + } + + Collections.sort(tasks); + fireTableDataChanged(); + } + + /* (non-Javadoc) + * @see javax.swing.table.AbstractTableModel#getColumnName(int) + */ + public String getColumnName(int col) { + return columnNames[col]; + } + + /* (non-Javadoc) + * @see javax.swing.table.TableModel#getRowCount() + */ + public int getRowCount() { + return tasks == null ? 0 : tasks.size(); + } + + /* (non-Javadoc) + * @see javax.swing.table.TableModel#getColumnCount() + */ + public int getColumnCount() { + return numColumns; + } + + /* (non-Javadoc) + * @see javax.swing.table.TableModel#getValueAt(int, int) + */ + public Object getValueAt(int row, int col) { + VSTask task = tasks.get(row); + + switch (col) { + case 0: + return task.getTaskTime(); + case 1: + return task.getProcess().getProcessID(); + } + + return task.getEvent().getShortname(); + } + + /* (non-Javadoc) + * @see javax.swing.table.AbstractTableModel#isCellEditable(int, int) + */ + public boolean isCellEditable(int row, int col) { + if (col == 2) + return false; + + return true; + } + + /* (non-Javadoc) + * @see javax.swing.table.AbstractTableModel#setValueAt( + * java.lang.Object, int, int) + */ + public void setValueAt(Object value, int row, int col) { + } + + /** + * Adds the task. + * + * @param task the task + */ + public void addTask(VSTask task) { + tasks.add(task); + Collections.sort(tasks); + fireTableDataChanged(); + } + + /** + * Removes the task at a specified row. + * + * @param row the row + * @return The removed task + */ + public VSTask removeTaskAtRow(int row) { + VSTask task = tasks.get(row); + tasks.remove(task); + taskManager.removeTask(task); + fireTableDataChanged(); + return task; + } + + /** + * Checks if a specific row exists + * + * @param row the row + * @return True, if the row exists. False, if not + */ + public boolean rowExists(int row) { + if (row < 0) + return false; + + if (tasks.size() <= row) + return false; + + return true; + } + + /** + * Gets the index of a specific task + * + * @param task The task + * @return The index of the task + */ + public int getIndexOf(VSTask task) { + return tasks.indexOf(task); + } + + /** + * Copies the tasks at a specified rows. + * + * @param rows the rows + */ + private void copyTasksAtRows(int rows[]) { + ArrayList<VSTask> copiedTasks = new ArrayList<VSTask>(); + + for (int row : rows) + /* Use the copy constructor */ + copiedTasks.add(new VSTask(tasks.get(row))); + + for (VSTask task : copiedTasks) { + taskManager.addTask(task, VSTaskManager.PROGRAMMED); + addTask(task); + } + + fireTableDataChanged(); + } + + /* (non-Javadoc) + * @see java.awt.event.MouseListener#mouseClicked( + * java.awt.event.MouseEvent) + */ + public void mouseClicked(MouseEvent me) { + final JTable source = (JTable) me.getSource(); + //final int row = source.rowAtPoint(me.getPoint()); + //final int col = source.columnAtPoint(me.getPoint()); + + if (SwingUtilities.isRightMouseButton(me)) { + ActionListener actionListener = new ActionListener() { + public void actionPerformed(ActionEvent ae) { + String command = ae.getActionCommand(); + int rows[] = source.getSelectedRows(); + + if (command.equals(prefs.getString("lang.remove"))) { + for (int i = rows.length - 1; i >= 0; --i) + removeTaskAtRow(rows[i]); + + } else if (command.equals( + prefs.getString("lang.copy"))) { + copyTasksAtRows(rows); + } + } + }; + + JPopupMenu popup = new JPopupMenu(); + JMenuItem item = new JMenuItem(prefs.getString("lang.remove")); + item.addActionListener(actionListener); + popup.add(item); + + item = new JMenuItem(prefs.getString("lang.copy")); + item.addActionListener(actionListener); + popup.add(item); + + popup.show(me.getComponent(), me.getX(), me.getY()); + } + } + + /* (non-Javadoc) + * @see java.awt.event.MouseListener#mouseEntered( + * java.awt.event.MouseEvent) + */ + public void mouseEntered(MouseEvent me) { } + + /* (non-Javadoc) + * @see java.awt.event.MouseListener#mouseExited( + * java.awt.event.MouseEvent) + */ + public void mouseExited(MouseEvent me) { } + + /* (non-Javadoc) + * @see java.awt.event.MouseListener#mousePressed( + * java.awt.event.MouseEvent) + */ + public void mousePressed(MouseEvent me) { } + + /* (non-Javadoc) + * @see java.awt.event.MouseListener#mouseReleased( + * java.awt.event.MouseEvent) + */ + public void mouseReleased(MouseEvent me) { } + } + + /** + * The class VSTaskManagerCellEditor, an object of this class handles + * the task manager's JTable editor + */ + private class VSTaskManagerCellEditor extends AbstractCellEditor + implements TableCellEditor { + /** the serial version uid */ + private static final long serialVersionUID = 1L; + + /** The JTable model */ + private VSTaskManagerTableModel model; + + /** + * Instantiates a new VSTaskManagerCellEditor object. + * + * @param model the model + */ + public VSTaskManagerCellEditor(VSTaskManagerTableModel model) { + this.model = model; + model.setEditor(this); + } + + /** + * Stops editing + */ + public void stopEditing() { + fireEditingStopped(); + } + + /** + /* (non-Javadoc) + * @see javax.swing.table.TableCellEditor#getTableCellEditorComponent( + * javax.swing.JTable, java.lang.Object, boolean, int, int) + */ + public Component getTableCellEditorComponent(final JTable table, + Object object, + boolean isSelected, + final int row, + final int col) { + switch (col) { + case 0: + Long val = (Long) model.getValueAt(row, col); + final JTextField valField = new JTextField(val.toString()); + valField.setBackground(Color.WHITE); + valField.setBorder(null); + valField.addActionListener(new ActionListener() { + private boolean isRed = false; + public void actionPerformed(ActionEvent ae) { + try { + Long val = Long.valueOf(valField.getText()); + if (val.longValue() < 0) + throw new VSNegativeNumberException(); + VSTask task = model.removeTaskAtRow(row); + task.setTaskTime(val.longValue()); + taskManager.addTask(task, VSTaskManager.PROGRAMMED); + model.addTask(task); + if (isRed) { + valField.setBackground(Color.WHITE); + isRed = false; + } + int index = model.getIndexOf(task); + ListSelectionModel selectionModel = + table.getSelectionModel(); + selectionModel.setSelectionInterval(index, index); + fireEditingStopped(); + + } catch (NumberFormatException exc) { + valField.setBackground(Color.RED); + isRed = true; + + } catch (VSNegativeNumberException exc) { + valField.setBackground(Color.RED); + isRed = true; + } + } + }); + return valField; + case 1: + Integer current[] = { (Integer) model.getValueAt(row, col) }; + final JComboBox<Integer> comboBox = new JComboBox<>(current); + + Integer pids[] = simulatorVisualization.getProcessIDs(); + for (Integer pid : pids) + comboBox.addItem(pid); + + comboBox.setSelectedIndex(0); + comboBox.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent ae) { + int index = comboBox.getSelectedIndex() - 1; + if (model.rowExists(row)) { + VSTask task = model.removeTaskAtRow(row); + VSInternalProcess process = + simulatorVisualization.getProcess(index); + task.setProcess(process); + taskManager.addTask(task, VSTaskManager.PROGRAMMED); + if (allProcessesAreSelected()) + model.addTask(task); + } + + fireEditingStopped(); + } + }); + + return comboBox; + case 2: + break; + } + + return null; + } + + /* (non-Javadoc) + * @see javax.swing.CellEditor#getCellEditorValue() + */ + public Object getCellEditorValue() { + return new String(""); + } + } + + + /** + * Instantiates a new VSSimulator object. + * + * @param prefs the prefs + * @param simulatorFrame the simulator frame + */ + public VSSimulator(VSPrefs prefs, VSSimulatorFrame simulatorFrame) { + init(prefs, simulatorFrame); + } + + /** + * inits the VSSimulator object. + * + * @param prefs the prefs + * @param simulatorFrame the simulator frame + */ + private void init(VSPrefs prefs, VSSimulatorFrame simulatorFrame) { + this.prefs = prefs; + this.simulatorFrame = simulatorFrame; + simulatorNum = ++simulatorCounter; + this.menuItemStates = new VSMenuItemStates(false, false, false, true); + this.localTextFields = new ArrayList<String>(); + this.globalTextFields = new ArrayList<String>(); + + /* Not null if init has been called from the deserialization */ + if (this.loging == null) + this.loging = new VSLogging(); + + loging.log(prefs.getString("lang.simulator.new")); + + fillContentPane(); + updateFromPrefs(); + + splitPaneH.setDividerLocation( + prefs.getInteger("div.window.splitsize")); + + splitPaneV.setDividerLocation( + prefs.getInteger("div.window.ysize") + - prefs.getInteger("div.window.logsize")); + + splitPane1.setDividerLocation((int) (getPaintSize()/2) - 20); + + int numProcesses = simulatorVisualization.getNumProcesses(); + for (int i = 0; i <= numProcesses; ++i) { + localTextFields.add("0000"); + globalTextFields.add("0000"); + } + + processesComboBox.setSelectedIndex(0); + localPIDComboBox.setSelectedIndex(0); + globalPIDComboBox.setSelectedIndex(0); + + thread = new Thread(simulatorVisualization); + thread.start(); + } + + /** + * Fills the content pane. + */ + private void fillContentPane() { + logingArea = loging.getLoggingArea(); + + splitPaneH = new JSplitPane(); + splitPaneV = new JSplitPane(); + + /* Not null if init has been called from the deserialization */ + if (this.simulatorVisualization == null) + simulatorVisualization = new VSSimulatorVisualization( + prefs, this, loging); + + taskManager = simulatorVisualization.getTaskManager(); + loging.setSimulatorCanvas(simulatorVisualization); + + JPanel canvasPanel = new JPanel(); + canvasPanel.setLayout(new GridLayout(1, 1, 3, 3)); + canvasPanel.add(simulatorVisualization); + canvasPanel.setMinimumSize(new Dimension(0, 0)); + canvasPanel.setMaximumSize(new Dimension(0, 0)); + + logingPanel = new JPanel(new BorderLayout()); + logingPanel.add(new JScrollPane(logingArea), BorderLayout.CENTER); + logingPanel.add(createToolsPanel(), BorderLayout.SOUTH); + logingPanel.setPreferredSize(new Dimension(200, 1)); + + splitPaneH.setOrientation(JSplitPane.HORIZONTAL_SPLIT); + splitPaneH.setLeftComponent(createProcessPanel()); + splitPaneH.setRightComponent(canvasPanel); + splitPaneH.setContinuousLayout(true); + splitPaneH.setOneTouchExpandable(true); + + splitPaneV.setOrientation(JSplitPane.VERTICAL_SPLIT); + splitPaneV.setTopComponent(splitPaneH); + splitPaneV.setBottomComponent(logingPanel); + splitPaneV.setContinuousLayout(true); + + this.add(splitPaneV); + } + + /** + * Creates the tools panel. + * + * @return the panel + */ + private JPanel createToolsPanel() { + JPanel toolsPanel = new JPanel(); + boolean expertMode = prefs.getBoolean("sim.mode.expert"); + + toolsPanel.setLayout(new BoxLayout(toolsPanel, BoxLayout.X_AXIS)); + JCheckBox expertActiveCheckBox = + new JCheckBox(prefs.getString("lang.mode.expert")); + + expertActiveCheckBox.setSelected(expertMode); + expertActiveCheckBox.addChangeListener(new ChangeListener() { + public void stateChanged(ChangeEvent ce) { + AbstractButton abstractButton = + (AbstractButton) ce.getSource(); + ButtonModel buttonModel = abstractButton.getModel(); + boolean newState = buttonModel.isSelected(); + if (lastExpertState != newState) { + lastExpertState = newState; + prefs.setBoolean("sim.mode.expert", newState); + fireExpertModeChanged(); + } + } + }); + toolsPanel.add(expertActiveCheckBox); + + if (expertMode) { + lamportActiveCheckBox = new JCheckBox( + prefs.getString("lang.time.lamport")); + lamportActiveCheckBox.setSelected(false); + lamportActiveCheckBox.addChangeListener(new ChangeListener() { + public void stateChanged(ChangeEvent ce) { + AbstractButton abstractButton = + (AbstractButton) ce.getSource(); + ButtonModel buttonModel = abstractButton.getModel(); + simulatorVisualization.showLamport( + buttonModel.isSelected()); + if (buttonModel.isSelected()) + vectorTimeActiveCheckBox.setSelected(false); + } + }); + toolsPanel.add(lamportActiveCheckBox); + + vectorTimeActiveCheckBox = new JCheckBox( + prefs.getString("lang.time.vector")); + vectorTimeActiveCheckBox.setSelected(false); + vectorTimeActiveCheckBox.addChangeListener(new ChangeListener() { + public void stateChanged(ChangeEvent ce) { + AbstractButton abstractButton = + (AbstractButton) ce.getSource(); + ButtonModel buttonModel = abstractButton.getModel(); + simulatorVisualization.showVectorTime( + buttonModel.isSelected()); + if (buttonModel.isSelected()) + lamportActiveCheckBox.setSelected(false); + } + }); + toolsPanel.add(vectorTimeActiveCheckBox); + + JCheckBox antiAliasing = new JCheckBox( + prefs.getString("lang.antialiasing")); + antiAliasing.setSelected(false); + antiAliasing.addChangeListener(new ChangeListener() { + public void stateChanged(ChangeEvent ce) { + AbstractButton abstractButton = + (AbstractButton) ce.getSource(); + ButtonModel buttonModel = abstractButton.getModel(); + simulatorVisualization.isAntiAliased( + buttonModel.isSelected()); + } + }); + toolsPanel.add(antiAliasing); + } + + JCheckBox logingActiveCheckBox = new JCheckBox( + prefs.getString("lang.loging.active")); + logingActiveCheckBox.setSelected(true); + logingActiveCheckBox.addChangeListener(new ChangeListener() { + public void stateChanged(ChangeEvent ce) { + AbstractButton abstractButton = + (AbstractButton) ce.getSource(); + ButtonModel buttonModel = abstractButton.getModel(); + loging.isPaused(!buttonModel.isSelected()); + } + }); + toolsPanel.add(logingActiveCheckBox); + + if (expertMode) { + filterActiveCheckBox = new JCheckBox( + prefs.getString("lang.filter")); + filterActiveCheckBox.setSelected(false); + filterActiveCheckBox.addChangeListener(new ChangeListener() { + public void stateChanged(ChangeEvent ce) { + AbstractButton abstractButton = + (AbstractButton) ce.getSource(); + ButtonModel buttonModel = abstractButton.getModel(); + loging.isFiltered(buttonModel.isSelected()); + if (buttonModel.isSelected()) + loging.setFilterText(filterTextField.getText()); + } + }); + toolsPanel.add(filterActiveCheckBox); + + filterTextField = new JTextField(); + filterTextField.getDocument().addDocumentListener( + new DocumentListener() { + public void insertUpdate(DocumentEvent de) { + loging.setFilterText(filterTextField.getText()); + } + public void removeUpdate(DocumentEvent de) { + loging.setFilterText(filterTextField.getText()); + } + public void changedUpdate(DocumentEvent de) { + loging.setFilterText(filterTextField.getText()); + } + }); + toolsPanel.add(filterTextField); + + JButton clearButton = new JButton( + prefs.getString("lang.loging.clear")); + clearButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent ae) { + String command = ae.getActionCommand(); + if (command.equals( + prefs.getString("lang.loging.clear"))) { + loging.clear(); + } + } + }); + toolsPanel.add(clearButton); + } + + return toolsPanel; + } + + /** + * Creates the process panel. + * + * @return the panel + */ + private JPanel createProcessPanel() { + JPanel editPanel = new JPanel(new GridBagLayout()); + boolean expertMode = prefs.getBoolean("sim.mode.expert"); + editPanel.setLayout(new BoxLayout(editPanel, BoxLayout.Y_AXIS)); + + processesComboBox = new JComboBox<>(); + localPIDComboBox = new JComboBox<>(); + globalPIDComboBox = new JComboBox<>(); + + lastSelectedProcessNum = 0; + int numProcesses = simulatorVisualization.getNumProcesses(); + String processString = prefs.getString("lang.process"); + + for (int i = 0; i < numProcesses; ++i) { + int pid = simulatorVisualization.getProcess(i).getProcessID(); + processesComboBox.addItem(processString + " " + pid); + localPIDComboBox.addItem("PID: " + pid); + globalPIDComboBox.addItem("PID: " + pid); + } + + processesComboBox.addItem(prefs.getString("lang.processes.all")); + localPIDComboBox.addItem(prefs.getString("lang.all")); + globalPIDComboBox.addItem(prefs.getString("lang.all")); + + tabbedPane = new JTabbedPane(JTabbedPane.TOP, + JTabbedPane.WRAP_TAB_LAYOUT); + localPanel = createTaskLabel(VSTaskManagerTableModel.LOCAL); + JPanel globalPanel = createTaskLabel(VSTaskManagerTableModel.GLOBAL); + + splitPane1 = new JSplitPane(); + splitPane1.setOrientation(JSplitPane.VERTICAL_SPLIT); + splitPane1.setTopComponent(localPanel); + splitPane1.setBottomComponent(globalPanel); + splitPane1.setOneTouchExpandable(true); + + if (expertMode) + tabbedPane.addTab(prefs.getString("lang.events"), splitPane1); + + else + tabbedPane.addTab(prefs.getString("lang.events"), localPanel); + + processesComboBox.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent ae) { + localTextFields.set(lastSelectedProcessNum, + localTextField.getText()); + globalTextFields.set(lastSelectedProcessNum, + globalTextField.getText()); + updateTaskManagerTable(); + + int processNum = getSelectedProcessNum(); + localTextField.setText(localTextFields.get(processNum)); + globalTextField.setText(globalTextFields.get(processNum)); + localTextField.setBackground(Color.WHITE); + globalTextField.setBackground(Color.WHITE); + lastSelectedProcessNum = processNum; + + localPIDComboBox.setSelectedIndex(processNum); + globalPIDComboBox.setSelectedIndex(processNum); + + if (processNum == simulatorVisualization.getNumProcesses()) { + tabbedPane.setEnabledAt(1, false); + if (tabbedPane.getSelectedIndex() == 1) + tabbedPane.setSelectedIndex(0); + + } else if (!tabbedPane.isEnabledAt(1)) { + tabbedPane.setEnabledAt(1, true); + } + + if (processNum != simulatorVisualization.getNumProcesses()) { + VSInternalProcess process = getSelectedProcess(); + VSProcessEditor processEditor = + new VSProcessEditor(prefs, process); + tabbedPane.setComponentAt(1, + processEditor.getContentPane()); + } + } + }); + + tabbedPane.add(prefs.getString("lang.variables"), null); + + editPanel.add(processesComboBox); + editPanel.add(tabbedPane); + + return editPanel; + } + + /** + * Creates the label panel. + * + * @param text the text + * + * @return the panel + */ + private JPanel createLabelPanel(String text) { + JPanel panel = new JPanel(); + JLabel label = new JLabel(text); + panel.add(label); + + return panel; + } + + /** + * Creates the task label. + * + * @param localTasks true, if the local task label has to get created. + * false, if the global task label has to get created. + * + * @return the panel + */ + private JPanel createTaskLabel(boolean localTasks) { + JPanel panel = new JPanel(new GridBagLayout()); + panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS)); + + if (localTasks) + panel.add(createLabelPanel(prefs.getString("lang.timed.local"))); + else + panel.add(createLabelPanel(prefs.getString("lang.timed.global"))); + + JScrollPane scrollPane = new JScrollPane(createTaskTable(localTasks)); + panel.add(scrollPane); + + if (localTasks) + localAddPanel = initAddPanel(panel, localTasks); + else + /*globalAddPanel = */ initAddPanel(panel, localTasks); + + return panel; + } + + /** + * Creates the task table. + * + * @param localTasks true, if the local task label has to get created. + * false, if the global task label has to get created. + * + * @return the table + */ + private JTable createTaskTable(boolean localTasks) { + VSInternalProcess process = getSelectedProcess(); + VSTaskManagerTableModel model = + new VSTaskManagerTableModel(process, localTasks); + VSTaskManagerCellEditor cellEditor = + new VSTaskManagerCellEditor(model); + + if (localTasks) { + taskManagerLocalModel = model; + taskManagerLocalEditor = cellEditor; + } else { + taskManagerGlobalModel = model; + taskManagerGlobalEditor = cellEditor; + } + + JTable table = new JTable(model); + table.setDefaultEditor(Object.class, cellEditor); + model.setTable(table); + + table.addMouseListener(model); + + TableColumn col = table.getColumnModel().getColumn(0); + col.setMaxWidth(62); + col.setResizable(false); + + col = table.getColumnModel().getColumn(1); + col.setMaxWidth(40); + col.setResizable(false); + + col = table.getColumnModel().getColumn(2); + col.sizeWidthToFit(); + table.setBackground(Color.WHITE); + + return table; + } + + /** + * Inits the add panel. + * + * @param panel the panel + * @param localTasks true, if the local task label has to get created. + * false, if the global task label has to get created. + * + * @return the panel + */ + private JPanel initAddPanel(JPanel panel, final boolean localTasks) { + JPanel addPanel = new JPanel(); + addPanel.setLayout(new BoxLayout(addPanel, BoxLayout.X_AXIS)); + boolean expertMode = prefs.getBoolean("sim.mode.expert"); + + final JTextField textField = new JTextField(); + if (localTasks) + localTextField = textField; + else + globalTextField = textField; + + textField.setText("0000"); + textField.setBackground(Color.WHITE); + addPanel.add(textField); + + addPanel.add(new JLabel(" ms ")); + + if (localTasks) { + if (expertMode) + addPanel.add(localPIDComboBox); + } else { + addPanel.add(globalPIDComboBox); + } + + final JComboBox<String> comboBox = new JComboBox<>(); + JButton takeoverButton = new JButton(prefs.getString("lang.takeover")); + takeoverButton.setMnemonic(prefs.getInteger("keyevent.takeover")); + takeoverButton.addActionListener(new ActionListener() { + private boolean isRed; + public void actionPerformed(ActionEvent ae) { + String textValue = textField.getText(); + Long longValue = null; + + try { + longValue = Long.valueOf(textValue); + + if (longValue.longValue() < 0) { + makeRed(); + return; + } + + if (isRed) { + makeWhite(); + } + + } catch (NumberFormatException e) { + makeRed(); + } + + if (longValue == null) + return; + + if (takeover(longValue.longValue())) { + if (isRed) + makeWhite(); + + } else { + makeRed(); + } + } + + private void makeWhite() { + textField.setBackground(Color.WHITE); + isRed = false; + } + + private void makeRed() { + textField.setBackground(Color.RED); + isRed = true; + } + + private boolean takeover(long time) { + VSInternalProcess selectedProcess = getSelectedProcess(); + int index = comboBox.getSelectedIndex(); + VSCreateTask createTask = createTasks.get(index); + + if (createTask.isDummy()) + return false; + + ArrayList<VSInternalProcess> processes = + getConcernedProcesses(localTasks); + + for (VSInternalProcess process : processes) { + VSTask task = createTask.createTask(process, time, + localTasks); + taskManager.addTask(task, VSTaskManager.PROGRAMMED); + + if (selectedProcess == null || + process.equals(selectedProcess)) { + if (localTasks) + taskManagerLocalModel.addTask(task); + else + taskManagerGlobalModel.addTask(task); + } + } + + return true; + } + }); + + addPanel.add(takeoverButton); + + boolean createTaskFlag = createTasks == null; + if (createTaskFlag) createTasks = new ArrayList<VSCreateTask>(); + + Vector<String> eventClassnames = + VSRegisteredEvents.getNonProtocolClassnames(); + + comboBox.setMaximumRowCount(20); + String menuText = prefs.getString("lang.events.process"); + comboBox.addItem("----- " + menuText + " -----"); + + if (createTaskFlag) + createTasks.add(new VSCreateTask(menuText)); + + for (String eventClassname : eventClassnames) { + String eventShortname = + VSRegisteredEvents.getShortnameByClassname(eventClassname); + menuText = eventShortname; + comboBox.addItem(menuText); + if (createTaskFlag) + createTasks.add(new VSCreateTask(menuText, eventClassname)); + } + + String activate = prefs.getString("lang.activate"); + String client = prefs.getString("lang.client"); + String clientRequest = prefs.getString("lang.clientrequest.start"); + String deactivate = prefs.getString("langactivate"); + String server = prefs.getString("lang.server"); + String serverRequest = prefs.getString("lang.serverrequest.start"); + String protocol = prefs.getString("lang.protocol"); + + String protocolEventClassname = "events.internal.VSProtocolEvent"; + eventClassnames = VSRegisteredEvents.getProtocolClassnames(); + + for (String eventClassname : eventClassnames) { + String eventShortname_ = + VSRegisteredEvents.getShortnameByClassname(eventClassname); + String eventShortname = null; + + menuText = eventShortname_ + " " + protocol; + comboBox.addItem("----- " + menuText + " -----"); + + if (createTaskFlag) + createTasks.add(new VSCreateTask(menuText)); + + if (VSRegisteredEvents.isOnServerStartProtocol(eventClassname)) + eventShortname = eventShortname_ + " " + serverRequest; + else + eventShortname = eventShortname_ + " " + clientRequest; + + menuText = eventShortname; + comboBox.addItem(menuText); + if (createTaskFlag) { + VSCreateTask createTask = new VSCreateTask(menuText, + eventClassname); + createTask.setShortname(eventShortname); + createTask.isRequest(true); + createTasks.add(createTask); + } + + eventShortname = eventShortname_ + " " + client + " " + activate; + menuText = eventShortname; + comboBox.addItem(menuText); + if (createTaskFlag) { + VSCreateTask createTask = + new VSCreateTask(menuText, protocolEventClassname); + createTask.isProtocolActivation(true); + createTask.isClientProtocol(true); + createTask.setProtocolClassname(eventClassname); + createTask.setShortname(eventShortname); + createTasks.add(createTask); + } + + eventShortname = eventShortname_ + " " + client + " " + deactivate; + menuText = eventShortname; + comboBox.addItem(menuText); + if (createTaskFlag) { + VSCreateTask createTask = + new VSCreateTask(menuText, protocolEventClassname); + createTask.isProtocolDeactivation(true); + createTask.isClientProtocol(true); + createTask.setProtocolClassname(eventClassname); + createTask.setShortname(eventShortname); + createTasks.add(createTask); + } + + eventShortname = eventShortname_ + " " + server + " " + activate; + menuText = eventShortname; + comboBox.addItem(menuText); + if (createTaskFlag) { + VSCreateTask createTask = + new VSCreateTask(menuText, protocolEventClassname); + createTask.isProtocolActivation(true); + createTask.isClientProtocol(false); + createTask.setProtocolClassname(eventClassname); + createTask.setShortname(eventShortname); + createTasks.add(createTask); + } + + eventShortname = eventShortname_ + " " + server + " " + deactivate; + menuText = eventShortname; + comboBox.addItem(menuText); + if (createTaskFlag) { + VSCreateTask createTask = + new VSCreateTask(menuText, protocolEventClassname); + createTask.isProtocolDeactivation(true); + createTask.isClientProtocol(false); + createTask.setProtocolClassname(eventClassname); + createTask.setShortname(eventShortname); + createTasks.add(createTask); + } + } + + panel.add(comboBox); + panel.add(addPanel); + + return addPanel; + } + + /** + * Gets the split size. + * + * @return the split size + */ + public synchronized int getSplitSize() { + return splitPaneH.getDividerLocation(); + } + + /** + * Gets the paint size. + * + * @return the paint size + */ + public synchronized int getPaintSize() { + return splitPaneV.getDividerLocation(); + } + + /** + * Gets the selected process num. + * + * @return the selected process num + */ + private int getSelectedProcessNum() { + return processesComboBox.getSelectedIndex(); + } + + /** + * Checks if 'all processes' is selected + * + * @return True, if 'all processes' are selected, else false + */ + private boolean allProcessesAreSelected() { + return processesComboBox.getSelectedIndex() + 1 + == processesComboBox.getItemCount(); + } + + /** + * Gets the selected process. + * + * @return the selected process + */ + private VSInternalProcess getSelectedProcess() { + int processNum = getSelectedProcessNum(); + return simulatorVisualization.getProcess(processNum); + } + + /** + * Gets the concerned processes. + * + * @param localTasks true, if this table manages the local tasks. false + * if this table manages the global tasks. + * + * @return the concerned processes + */ + private ArrayList<VSInternalProcess> getConcernedProcesses( + boolean localTasks) { + int processNum = localTasks + ? localPIDComboBox.getSelectedIndex() + : globalPIDComboBox.getSelectedIndex(); + + if (processNum == simulatorVisualization.getNumProcesses()) + return simulatorVisualization.getProcessesArray(); + + ArrayList<VSInternalProcess> arr = new ArrayList<VSInternalProcess>(); + arr.add(simulatorVisualization.getProcess(processNum)); + + return arr; + } + + /** + * Update task manager table. + */ + public synchronized void updateTaskManagerTable() { + VSInternalProcess process = getSelectedProcess(); + boolean allProcesses = process == null; + + taskManagerLocalEditor.stopEditing(); + taskManagerGlobalEditor.stopEditing(); + + taskManagerLocalModel.set(process, + VSTaskManagerTableModel.LOCAL, + allProcesses); + + taskManagerGlobalModel.set(process, + VSTaskManagerTableModel.GLOBAL, + allProcesses); + } + + /** + * Update the processes combo box + */ + private void updateProcessesComboBox() { + int numProcesses = simulatorVisualization.getNumProcesses(); + String processString = prefs.getString("lang.process"); + + for (int i = 0; i < numProcesses; ++i) { + int processID = simulatorVisualization.getProcess(i).getProcessID(); + + processesComboBox.removeItemAt(i); + localPIDComboBox.removeItemAt(i); + globalPIDComboBox.removeItemAt(i); + + processesComboBox.insertItemAt(processString + " " + processID, i); + localPIDComboBox.insertItemAt("PID: " + processID, i); + globalPIDComboBox.insertItemAt("PID: " + processID, i); + } + } + + /** + * The simulator has finished. + */ + public synchronized void finish() { + menuItemStates.setStart(false); + menuItemStates.setPause(false); + menuItemStates.setReset(true); + menuItemStates.setReplay(true); + simulatorFrame.updateSimulatorMenu(); + } + + /** + * Gets the simulator num. + * + * @return the simulator num + */ + public synchronized int getSimulatorNum() { + return simulatorNum; + } + + /** + * Gets the menu item states. + * + * @return the menu item states + */ + public synchronized VSMenuItemStates getMenuItemStates() { + return menuItemStates; + } + + /** + * Gets the simulator canvas. + * + * @return the simulator canvas + */ + public synchronized VSSimulatorVisualization getSimulatorCanvas() { + return simulatorVisualization; + } + + /** + * Gets the simulator frame. + * + * @return the simulator frame + */ + public synchronized VSSimulatorFrame getSimulatorFrame() { + return simulatorFrame; + } + + /** + * Update from prefs. + */ + public synchronized void updateFromPrefs() { + simulatorVisualization.setBackground(prefs.getColor("col.background")); + simulatorVisualization.updateFromPrefs(); + } + + /** + * Removes the process at a specified index. + * + * @param index the index + */ + public synchronized void removedAProcessAtIndex(int index) { + if (lastSelectedProcessNum > index) + --lastSelectedProcessNum; + + globalTextFields.remove(index); + localTextFields.remove(index); + + globalPIDComboBox.removeItemAt(index); + localPIDComboBox.removeItemAt(index); + + processesComboBox.removeItemAt(index); + simulatorFrame.updateEditMenu(); + + updateTaskManagerTable(); + } + + /** + * Adds the process at a specified index. + * + * @param index the index + */ + public synchronized void addProcessAtIndex(int index) { + int processID = simulatorVisualization.getProcess(index).getProcessID(); + String processString = prefs.getString("lang.process"); + + localTextFields.add(index, "0000"); + globalTextFields.add(index, "0000"); + + localPIDComboBox.insertItemAt("PID: " + processID, index); + globalPIDComboBox.insertItemAt("PID: " + processID, index); + + processesComboBox.insertItemAt(processString + " " + processID, index); + simulatorFrame.updateEditMenu(); + } + + /** + * Fire expert mode changed. Tell, that the expert mode has changed. + */ + public synchronized void fireExpertModeChanged() { + boolean expertMode = prefs.getBoolean("sim.mode.expert"); + + /* Update the Task Manager GUI */ + int selectedIndex = tabbedPane.getSelectedIndex(); + + if (expertMode) { + tabbedPane.remove(localPanel); + tabbedPane.insertTab(prefs.getString("lang.events"), null, + splitPane1, null, 0); + splitPane1.setTopComponent(localPanel); + //splitPane1.setDividerLocation((int) (getPaintSize()/2) - 20); + + /* addPanel */ + localAddPanel.add(localPIDComboBox, 2); + + } else { + tabbedPane.remove(splitPane1); + tabbedPane.insertTab(prefs.getString("lang.events"), null, + localPanel, null, 0); + + /* addPanel */ + localAddPanel.remove(2); + } + + tabbedPane.setSelectedIndex(selectedIndex); + + /* Update the 'Variables tab' */ + if (getSelectedProcessNum() != + simulatorVisualization.getNumProcesses()) { + VSInternalProcess process = getSelectedProcess(); + VSProcessEditor editor = new VSProcessEditor(prefs, process); + tabbedPane.setComponentAt(1, editor.getContentPane()); + } + + /* Update the tools panel */ + logingPanel.remove(1); + logingPanel.add(createToolsPanel(), BorderLayout.SOUTH); + updateUI(); + } + + /** + * Gets the prefs. + * + * @return the prefs + */ + public synchronized VSPrefs getPrefs() { + return prefs; + } + + /** + * Gets the create tasks objects. Those objects are for creating new tasks + * via the task manager GUI or via right click on the paint area of the + * simulator canvas! + * + * @return The create tasks objects + */ + ArrayList<VSCreateTask> getCreateTaskObjects() { + return createTasks; + } + + /* (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)); + + simulatorVisualization.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: VSSimulator"); + + serialize.setObject("simulator", this); + serialize.setObject("loging", loging); + + /** For later backwards compatibility, to add more stuff */ + objectInputStream.readObject(); + + simulatorVisualization.deserialize(serialize, objectInputStream); + + /** For later backwards compatibility, to add more stuff */ + objectInputStream.readObject(); + + updateFromPrefs(); + updateTaskManagerTable(); + updateProcessesComboBox(); + processesComboBox.setSelectedIndex(processesComboBox.getItemCount()-1); + } +} diff --git a/src/main/java/simulator/VSSimulatorFrame.java b/src/main/java/simulator/VSSimulatorFrame.java new file mode 100644 index 0000000..3cf4e91 --- /dev/null +++ b/src/main/java/simulator/VSSimulatorFrame.java @@ -0,0 +1,628 @@ +package simulator; + +import java.awt.BorderLayout; +import java.awt.Component; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.GridLayout; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.ArrayList; +import java.util.Vector; + +import javax.swing.ImageIcon; +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.JMenuItem; +import javax.swing.JTabbedPane; +import javax.swing.JToolBar; +import javax.swing.KeyStroke; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; + +import core.VSInternalProcess; +import prefs.VSDefaultPrefs; +import prefs.VSPrefs; +import prefs.editors.VSEditorFrame; +import prefs.editors.VSSimulatorEditor; +import serialize.VSSerialize; +import utils.VSAboutFrame; +import utils.VSFrame; + +/** + * The class VSSimulatorFrame, an object of this class represents a window + * of the simulator. The window can have several tabs. Each tab contains + * an independent simulator. + * + * @author Paul C. Buetow + */ +public class VSSimulatorFrame extends VSFrame { + /** The serial version uid */ + private static final long serialVersionUID = 1L; + + /** The pause item. */ + private JMenuItem pauseItem; + + /** The replay item. */ + private JMenuItem replayItem; + + /** The reset item. */ + private JMenuItem resetItem; + + /** The start item. */ + private JMenuItem startItem; + + /** The pause button. */ + private JButton pauseButton; + + /** The replay button. */ + private JButton replayButton; + + /** The reset button. */ + private JButton resetButton; + + /** The start button. */ + private JButton startButton; + + /** The menu edit. */ + private JMenu menuEdit; + + /** The menu file. */ + private JMenu menuFile; + + /** The close item. */ + private JMenuItem closeItem; + + /** The save item. */ + private JMenuItem saveItem; + + /** The save as item. */ + private JMenuItem saveAsItem; + + /** The menu simulator. */ + private JMenu menuSimulator; + + /** The tool bar. */ + private JToolBar toolBar; + + /** The prefs. */ + private VSPrefs prefs; + + /** The simulators. */ + private Vector<VSSimulator> simulators; + + /** The current simulator. */ + private VSSimulator currentSimulator; + + /** The tabbed pane. */ + private JTabbedPane tabbedPane; + + /** The action listener */ + private ActionListener actionListener; + + /** + * Instantiates a new VSSimulatorFrame object. + * + * @param prefs the prefs + * @param relativeTo the component to open the window relative to + */ + public VSSimulatorFrame(VSPrefs prefs, Component relativeTo) { + super(prefs.getString("lang.name"), relativeTo); + this.prefs = prefs; + this.simulators = new Vector<VSSimulator>(); + + final VSPrefs finalPrefs = this.prefs; + actionListener = new ActionListener() { + public void actionPerformed(ActionEvent e) { + Object source = e.getSource(); + String sourceText = null; + + if (source instanceof JMenuItem) + sourceText = ((JMenuItem) source).getText(); + else + sourceText = ((ImageIcon) ((JButton) source).getIcon()). + getDescription(); + + if (sourceText.equals( + finalPrefs.getString("lang.simulator.close"))) { + removeCurrentSimulator(); + + } else if (sourceText.equals( + finalPrefs.getString("lang.simulator.new"))) { + VSPrefs newPrefs = VSDefaultPrefs.init(); + VSSimulatorEditor simulatorEditor = + new VSSimulatorEditor(newPrefs, VSSimulatorFrame.this, + VSSimulatorEditor.OPENED_NEW_TAB); + new VSEditorFrame(newPrefs, VSSimulatorFrame.this, + simulatorEditor); + + } else if (sourceText.equals( + finalPrefs.getString("lang.window.new"))) { + new VSMain(VSDefaultPrefs.init(), + VSSimulatorFrame.this); + + } else if (sourceText.equals( + finalPrefs.getString("lang.window.close"))) { + dispose(); + + } else if (sourceText.equals( + finalPrefs.getString("lang.open"))) { + VSSerialize serialize = new VSSerialize(); + serialize.openSimulator(VSSimulatorFrame.this); + + } else if (sourceText.equals( + finalPrefs.getString("lang.save"))) { + VSSimulatorVisualization simulatorVisualization = + currentSimulator.getSimulatorCanvas(); + boolean flag = !simulatorVisualization.isPaused() + && !simulatorVisualization.isResetted() + && !simulatorVisualization.hasFinished(); + + if (flag) + pauseCurrentSimulator(); + + VSSerialize serialize = new VSSerialize(); + serialize.saveSimulator(VSSerialize.LAST_FILENAME, + currentSimulator); + if (flag) + startCurrentSimulator(); + + } else if (sourceText.equals( + finalPrefs.getString("lang.saveas"))) { + VSSimulatorVisualization simulatorVisualization = + currentSimulator.getSimulatorCanvas(); + boolean flag = !simulatorVisualization.isPaused() + && !simulatorVisualization.isResetted() + && !simulatorVisualization.hasFinished(); + if (flag) + pauseCurrentSimulator(); + + VSSerialize serialize = new VSSerialize(); + serialize.saveSimulator(currentSimulator); + + if (flag) + startCurrentSimulator(); + + } else if (sourceText.equals( + finalPrefs.getString("lang.about"))) { + new VSAboutFrame(finalPrefs, VSSimulatorFrame.this); + + } else if (sourceText.equals( + finalPrefs.getString("lang.quit"))) { + System.exit(0); + + } else if (sourceText.equals( + finalPrefs.getString("lang.start"))) { + startCurrentSimulator(); + + } else if (sourceText.equals( + finalPrefs.getString("lang.pause"))) { + pauseCurrentSimulator(); + + } else if (sourceText.equals( + finalPrefs.getString("lang.reset"))) { + resetCurrentSimulator(); + + } else if (sourceText.equals( + finalPrefs.getString("lang.replay"))) { + VSMenuItemStates menuItemState = + currentSimulator.getMenuItemStates(); + menuItemState.setStart(false); + menuItemState.setPause(true); + menuItemState.setReset(false); + menuItemState.setReplay(true); + currentSimulator.getSimulatorCanvas().reset(); + currentSimulator.getSimulatorCanvas().play(); + updateSimulatorMenu(); + } + } + }; + + setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + + setSize(prefs.getInteger("div.window.xsize"), + prefs.getInteger("div.window.ysize")); + + setJMenuBar(createMenuBar()); + setLayout(new BorderLayout()); + setContentPane(createContentPane()); + setVisible(true); + + pauseButton.setEnabled(false); + replayButton.setEnabled(false); + resetButton.setEnabled(false); + startButton.setEnabled(false); + menuEdit.setEnabled(false); + //menuFile.setEnabled(false); + closeItem.setEnabled(false); + saveItem.setEnabled(false); + saveAsItem.setEnabled(false); + menuSimulator.setEnabled(false); + } + + /** + * Creates the menu bar. + * + * @return the j menu bar + */ + private JMenuBar createMenuBar() { + /* File menu */ + menuFile = new JMenu(prefs.getString("lang.file")); + menuFile.setMnemonic(prefs.getInteger("keyevent.file")); + JMenuItem menuItem; + + menuItem = new JMenuItem(prefs.getString("lang.simulator.new")); + menuItem.setAccelerator(KeyStroke.getKeyStroke( + prefs.getInteger("keyevent.new"), + ActionEvent.ALT_MASK)); + menuItem.addActionListener(actionListener); + menuFile.add(menuItem); + + closeItem = new JMenuItem( + prefs.getString("lang.simulator.close")); + closeItem.setAccelerator(KeyStroke.getKeyStroke( + prefs.getInteger("keyevent.close"), + ActionEvent.ALT_MASK)); + closeItem.addActionListener(actionListener); + menuFile.add(closeItem); + + menuFile.addSeparator(); + + menuItem = new JMenuItem(prefs.getString("lang.window.new")); + menuItem.addActionListener(actionListener); + menuFile.add(menuItem); + + menuItem = new JMenuItem(prefs.getString("lang.window.close")); + menuItem.addActionListener(actionListener); + menuFile.add(menuItem); + + menuFile.addSeparator(); + + menuItem = new JMenuItem(prefs.getString("lang.open")); + menuItem.setAccelerator(KeyStroke.getKeyStroke( + prefs.getInteger("keyevent.open"), + ActionEvent.ALT_MASK)); + menuItem.addActionListener(actionListener); + menuFile.add(menuItem); + + saveItem = new JMenuItem(prefs.getString("lang.save")); + saveItem.setAccelerator(KeyStroke.getKeyStroke( + prefs.getInteger("keyevent.save"), + ActionEvent.ALT_MASK)); + saveItem.addActionListener(actionListener); + menuFile.add(saveItem); + + saveAsItem = new JMenuItem(prefs.getString("lang.saveas")); + saveAsItem.setAccelerator(KeyStroke.getKeyStroke( + prefs.getInteger("keyevent.saveas"), + ActionEvent.ALT_MASK)); + saveAsItem.addActionListener(actionListener); + menuFile.add(saveAsItem); + + menuFile.addSeparator(); + + menuItem = new JMenuItem(prefs.getString("lang.about")); + menuItem.addActionListener(actionListener); + menuFile.add(menuItem); + + menuItem = new JMenuItem(prefs.getString("lang.quit")); + menuItem.addActionListener(actionListener); + menuFile.add(menuItem); + + /* Edit menu */ + menuEdit = new JMenu( + prefs.getString("lang.edit")); + menuEdit.setMnemonic(prefs.getInteger("keyevent.edit")); + updateEditMenu(); + + /* Simulator menu */ + toolBar = new JToolBar(); + menuSimulator = new JMenu( + prefs.getString("lang.simulator")); + menuSimulator.setMnemonic(prefs.getInteger("keyevent.simulator")); + + resetItem = new JMenuItem(prefs.getString("lang.reset")); + resetItem.setAccelerator(KeyStroke.getKeyStroke( + prefs.getInteger("keyevent.reset"), + ActionEvent.ALT_MASK)); + resetItem.addActionListener(actionListener); + resetItem.setEnabled(false); + menuSimulator.add(resetItem); + resetButton = new JButton(getImageIcon("reset.png", + prefs.getString("lang.reset"))); + resetButton.addActionListener(actionListener); + toolBar.add(resetButton); + + replayItem = new JMenuItem( + prefs.getString("lang.replay")); + replayItem.setAccelerator(KeyStroke.getKeyStroke( + prefs.getInteger("keyevent.replay"), + ActionEvent.ALT_MASK)); + replayItem.addActionListener(actionListener); + replayItem.setEnabled(false); + menuSimulator.add(replayItem); + replayButton = new JButton( + getImageIcon("replay.png", prefs.getString("lang.replay"))); + replayButton.addActionListener(actionListener); + toolBar.add(replayButton); + + pauseItem = new JMenuItem(prefs.getString("lang.pause")); + pauseItem.setAccelerator(KeyStroke.getKeyStroke( + prefs.getInteger("keyevent.pause"), + ActionEvent.ALT_MASK)); + pauseItem.addActionListener(actionListener); + menuSimulator.add(pauseItem); + pauseItem.setEnabled(false); + pauseButton = new JButton(getImageIcon("pause.png", + prefs.getString("lang.pause"))); + pauseButton.addActionListener(actionListener); + toolBar.add(pauseButton); + + startItem = new JMenuItem(prefs.getString("lang.start")); + startItem.setAccelerator(KeyStroke.getKeyStroke( + prefs.getInteger("keyevent.start"), + ActionEvent.ALT_MASK)); + startItem.addActionListener(actionListener); + menuSimulator.add(startItem); + startButton = new JButton(getImageIcon("start.png", + prefs.getString("lang.start"))); + startButton.addActionListener(actionListener); + toolBar.add(startButton); + + + JMenuBar mainMenuBar = new JMenuBar(); + mainMenuBar.add(menuFile); + mainMenuBar.add(menuEdit); + mainMenuBar.add(menuSimulator); + + return mainMenuBar; + } + + /** + * Creates the content pane. + * + * @return the container + */ + private Container createContentPane() { + Container pane = getContentPane(); + tabbedPane = new JTabbedPane(JTabbedPane.BOTTOM, + JTabbedPane.SCROLL_TAB_LAYOUT); + + tabbedPane.addChangeListener(new ChangeListener() { + public void stateChanged(ChangeEvent ce) { + JTabbedPane pane = (JTabbedPane) ce.getSource(); + currentSimulator = (VSSimulator) pane.getSelectedComponent(); + if (currentSimulator != null) { + currentSimulator.getSimulatorCanvas().paint(); + updateEditMenu(); + updateSimulatorMenu(); + } + } + }); + + pane.add(toolBar, BorderLayout.PAGE_START); + pane.add(tabbedPane, BorderLayout.CENTER); + + return pane; + } + + /** + * Updates the edit menu. Called if another simulator tab has been selected + * or if processes have been added or removed. + */ + public void updateEditMenu() { + menuEdit.removeAll(); + + JMenuItem globalPrefsItem = new JMenuItem( + prefs.getString("lang.prefs")); + + globalPrefsItem.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent ae) { + VSPrefs simulatorPrefs = currentSimulator.getPrefs(); + VSSimulatorEditor.TAKEOVER_BUTTON = true; + VSSimulatorEditor simulatorEditor = new VSSimulatorEditor( + simulatorPrefs, VSSimulatorFrame.this, currentSimulator); + new VSEditorFrame(prefs, VSSimulatorFrame.this, + simulatorEditor); + } + }); + + menuEdit.add(globalPrefsItem); + menuEdit.addSeparator(); + + if (currentSimulator == null) + return; + + String processString = prefs.getString("lang.process"); + ArrayList<VSInternalProcess> arr = + currentSimulator.getSimulatorCanvas().getProcessesArray(); + + //int numProcesses = arr.size(); + int processNum = 0; + + for (VSInternalProcess process : arr) { + int processID = process.getProcessID(); + JMenuItem processItem = new JMenuItem(processString + " " + + processID); + if (processNum < 9) + processItem.setAccelerator( + KeyStroke.getKeyStroke(0x31+processNum, + ActionEvent.ALT_MASK)); + final int finalProcessNum = processNum++; + processItem.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent ae) { + currentSimulator.getSimulatorCanvas().editProcess( + finalProcessNum); + } + }); + menuEdit.add(processItem); + } + } + + /** + * Updates the simulator menu. Called if the simulator state has changed + * (e.g. start/play/stop/replay etc) + */ + public synchronized void updateSimulatorMenu() { + VSMenuItemStates menuItemState = currentSimulator.getMenuItemStates(); + + pauseItem.setEnabled(menuItemState.getPause()); + replayItem.setEnabled(menuItemState.getReplay()); + resetItem.setEnabled(menuItemState.getReset()); + startItem.setEnabled(menuItemState.getStart()); + + pauseButton.setEnabled(menuItemState.getPause()); + replayButton.setEnabled(menuItemState.getReplay()); + resetButton.setEnabled(menuItemState.getReset()); + startButton.setEnabled(menuItemState.getStart()); + } + + /* (non-Javadoc) + * @see java.awt.Window#dispose() + */ + public void dispose() { + synchronized (simulators) { + for (VSSimulator simulator : simulators) + simulator.getSimulatorCanvas().stopThread(); + } + super.dispose(); + } + + /** + * Adds the simulator. + * + * @param simulator the simulator + */ + public void addSimulator(VSSimulator simulator) { + simulator.setLayout(new GridLayout(1, 1, 3, 3)); + simulator.setMinimumSize(new Dimension(0, 0)); + simulator.setMaximumSize(new Dimension(0, 0)); + + simulators.add(simulator); + tabbedPane.addTab(prefs.getString("lang.simulator") + + " " + simulator.getSimulatorNum(), simulator); + tabbedPane.setSelectedComponent(simulator); + + if (simulators.size() == 1) { + menuEdit.setEnabled(true); + //menuFile.setEnabled(true); + closeItem.setEnabled(true); + saveItem.setEnabled(true); + saveAsItem.setEnabled(true); + menuSimulator.setEnabled(true); + } + } + + /** + * Removes the simulator. + * + * @param simulatorToRemove the simulator to remove + */ + public void removeSimulator(VSSimulator simulatorToRemove) { + if (simulators.size() == 1) { + pauseButton.setEnabled(false); + replayButton.setEnabled(false); + resetButton.setEnabled(false); + startButton.setEnabled(false); + menuEdit.setEnabled(false); + //menuFile.setEnabled(false); + closeItem.setEnabled(false); + saveItem.setEnabled(false); + saveAsItem.setEnabled(false); + menuSimulator.setEnabled(false); + } + + simulators.remove(simulatorToRemove); + tabbedPane.remove(simulatorToRemove); + simulatorToRemove.getSimulatorCanvas().stopThread(); + } + + /** + * Removes the current simulator. + */ + private void removeCurrentSimulator() { + removeSimulator(currentSimulator); + } + + /** + * Gets the current simulator. + * + * @return the current simulator + */ + public VSSimulator getCurrentSimulator() { + return currentSimulator; + } + + /** + * Resets the current simulator + */ + public void resetCurrentSimulator() { + if (currentSimulator == null) + return; + + VSMenuItemStates menuItemState = + currentSimulator.getMenuItemStates(); + menuItemState.setStart(true); + menuItemState.setPause(false); + menuItemState.setReset(false); + menuItemState.setReplay(false); + currentSimulator.getSimulatorCanvas().reset(); + updateSimulatorMenu(); + } + + /** + * Starts the current simulator + */ + public void startCurrentSimulator() { + VSMenuItemStates menuItemState = + currentSimulator.getMenuItemStates(); + menuItemState.setStart(false); + menuItemState.setPause(true); + menuItemState.setReset(false); + menuItemState.setReplay(true); + currentSimulator.getSimulatorCanvas().play(); + updateSimulatorMenu(); + } + + /** + * Pauses the current simulator + */ + public void pauseCurrentSimulator() { + VSMenuItemStates menuItemState = + currentSimulator.getMenuItemStates(); + menuItemState.setStart(true); + menuItemState.setPause(false); + menuItemState.setReset(true); + menuItemState.setReplay(true); + currentSimulator.getSimulatorCanvas().pause(); + updateSimulatorMenu(); + } + + /** + * Gets the image icon. + * + * @param name the name + * @param descr the descr + * + * @return the image icon + */ + private ImageIcon getImageIcon(String name, String descr) { + java.net.URL imageURL = getClass().getResource("/icons/"+name); + + if (imageURL == null) + return new ImageIcon("icons/"+name, descr); + + return new ImageIcon(imageURL, descr); + } + + /** + * Gets the prefs. + * + * @return the prefs + */ + public VSPrefs getPrefs() { + return prefs; + } +} diff --git a/src/main/java/simulator/VSSimulatorVisualization.java b/src/main/java/simulator/VSSimulatorVisualization.java new file mode 100644 index 0000000..2dc4a64 --- /dev/null +++ b/src/main/java/simulator/VSSimulatorVisualization.java @@ -0,0 +1,1814 @@ +package simulator; + +import java.awt.Canvas; +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.RenderingHints; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.HierarchyBoundsListener; +import java.awt.event.HierarchyEvent; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; +import java.awt.event.MouseMotionListener; +import java.awt.image.BufferStrategy; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.util.ArrayList; +import java.util.LinkedList; + +import javax.swing.JMenu; +import javax.swing.JMenuItem; +import javax.swing.JPopupMenu; +import javax.swing.SwingUtilities; + +import core.VSInternalProcess; +import core.VSMessage; +import core.VSTask; +import core.VSTaskManager; +import core.time.VSTime; +import events.VSAbstractEvent; +import events.implementations.VSProcessCrashEvent; +import events.implementations.VSProcessRecoverEvent; +import events.internal.VSMessageReceiveEvent; +import prefs.VSPrefs; +import prefs.editors.VSEditorFrame; +import prefs.editors.VSProcessEditor; +import serialize.VSSerializable; +import serialize.VSSerialize; + +/** + * The class VSSimulatorVisualization. An instance of this object represents the + * graphical paint area of a simulator. It contains all graphic calculations. + * Also the simulator thread takes place in this class in a loop! This class + * is probably the most cryptic of the whole simulator source code. This is + * this way in order to gain more performance of the painting area! + * + * @author Paul C. Buetow + */ +public class VSSimulatorVisualization extends Canvas + implements Runnable, VSSerializable { + + /** The serial version uid */ + private static final long serialVersionUID = 1L; + + /** The highlighted process. */ + private VSInternalProcess highlightedProcess; + + /** The simulator. */ + private VSSimulator simulator; + + /** The prefs. */ + private VSPrefs prefs; + + /** The loging. */ + private VSLogging loging; + + /** The num processes. */ + private volatile int numProcesses; + + /** The seconds spaceing. */ + private int secondsSpaceing; + + /** The thread sleep. */ + private int threadSleep; + + /** The until time. Until then goes the simulator? */ + private long untilTime; + + /** The simulator is paused. */ + private volatile boolean isPaused = true; + + /** The simulator thread is stopped. */ + private volatile boolean hasThreadStopped = false; + + /** The simulator is finished. */ + private volatile boolean hasFinished = false; + + /** The simulator is resetted. */ + private volatile boolean isResetted = false; + + /** The simulator is anti aliased. */ + private volatile boolean isAntiAliased = false; + + /** The simulator's anti aliasing has changed. */ + private volatile boolean isAntiAliasedChanged = false; + + /** The simulator shows the lamport time. */ + private volatile boolean showLamport = false; + + /** The simulator shows the vector time. */ + private volatile boolean showVectorTime = false; + + /** The pause time. */ + private volatile long pauseTime; + + /** The start time. */ + private volatile long startTime; + + /** The global time. */ + private volatile long time; + + /** The last global time. */ + private volatile long lastTime; + + /** The task manager. */ + private VSTaskManager taskManager; + + /** The message lines. */ + private LinkedList<VSMessageLine> messageLines; + + /** The message lines to remove. */ + private LinkedList<VSMessageLine> messageLinesToRemove; + + /** The processes. */ + private ArrayList<VSInternalProcess> processes; + + /** The clock speed. */ + private double clockSpeed; + + /** The clock offset. */ + private double clockOffset; + + /** The simulator time. */ + private long simulatorTime; + + /** The x paint size. */ + double xPaintSize; + + /** The paint size. */ + double paintSize; + + /** The y distance. */ + double yDistance; + + /** The global time x position. */ + double globalTimeXPosition; + + /** The xoffset_plus_xpaintsize. */ + int xoffset_plus_xpaintsize; + + /** The xpaintsize_dividedby_untiltime. */ + double xpaintsize_dividedby_untiltime; + + /** The paint processes offset. */ + int paintProcessesOffset; + + /** The paint secondlines seconds. */ + int paintSecondlinesSeconds; + + /** The paint secondlines line. */ + int paintSecondlinesLine[] = new int[4]; + + /** The paint secondlines y string pos1. */ + int paintSecondlinesYStringPos1; + + /** The paint secondlines y string pos2. */ + int paintSecondlinesYStringPos2; + + /** The paint global time y position. */ + int paintGlobalTimeYPosition; + + /* GFX buffering */ + /** The strategy for buffering. */ + private BufferStrategy strategy; + + /** The graphics object to paint at. */ + private Graphics2D g; + + /** The Constant LINE_WIDTH. */ + private static final int LINE_WIDTH = 5; + + /** The Constant SEPLINE_WIDTH. */ + private static final int SEPLINE_WIDTH = 2; + + /** The Constant XOFFSET. */ + private static final int XOFFSET = 50; + + /** The Constant YOFFSET. */ + private static final int YOFFSET = 30; + + /** The Constant YOUTER_SPACEING. */ + private static final int YOUTER_SPACEING = 15; + + /** The Constant YSEPLINE_SPACEING. */ + private static final int YSEPLINE_SPACEING = 20; + + /** The Constant TEXT_SPACEING. */ + private static final int TEXT_SPACEING = 10; + + /** The Constant ROW_HEIGHT. */ + private static final int ROW_HEIGHT = 14; + + /* Constats, which have to get calculated once after start */ + /** The processline color. */ + private Color processlineColor; + + /** The process secondline color. */ + private Color processSecondlineColor; + + /** The process sepline color. */ + private Color processSeplineColor; + + /** The message arrived color. */ + private Color messageArrivedColor; + + /** The message sending color. */ + private Color messageSendingColor; + + /** The message lost color. */ + private Color messageLostColor; + + /** The background color. */ + private Color backgroundColor; + + /** The message line counter. */ + private long messageLineCounter; + + /** The process counter. Needed for the unique process id's. */ + private int processCounter; + + /** + * The class VSMessageLine, an object of this class represents a message + * line drawn into the painting area. + * + * @author Paul C. Buetow + */ + public class VSMessageLine { + /** The receiver process. */ + private VSInternalProcess receiverProcess; + + /** The color. */ + private Color color; + + /** The send time. */ + private long sendTime; + + /** The recv time. */ + private long recvTime; + + /** The sender num. */ + private int senderNum; + + /** The receiver num. */ + private int receiverNum; + + /** The offset1. */ + private int offset1; + + /** The offset2. */ + private int offset2; + + /** The message has arrived. */ + private boolean isArrived; + + /** The message is lost. */ + private boolean isLost; + + /** The x1. */ + private double x1; + + /** The y1. */ + private double y1; + + /** The x2. */ + private double x2; + + /** The y2. */ + private double y2; + + /** The x. */ + private double x; + + /** The y. */ + private double y; + + /** The outage time. */ + private long outageTime; + + /** The z. */ + private long z; + + /** The message line num. */ + private long messageLineNum; + + /** The task. */ + private VSTask task; + + /** + * Instantiates a new VSMessageLine object. + * + * @param receiverProcess the receiver process + * @param sendTime the send time + * @param recvTime the recv time + * @param outageTime the outage time + * @param senderNum the sender num + * @param receiverNum the receiver num + * @param task the task + */ + public VSMessageLine(VSInternalProcess receiverProcess, long sendTime, + long recvTime, long outageTime, int senderNum, + int receiverNum, VSTask task) { + this.receiverProcess = receiverProcess; + this.sendTime = sendTime; + this.recvTime = recvTime; + this.outageTime = outageTime; + this.senderNum = senderNum; + this.receiverNum = receiverNum; + this.isArrived = false; + this.isLost = false; + this.messageLineNum = ++messageLineCounter; + this.task = task; + + if (senderNum > receiverNum) { + //offset1 = 1; + offset2 = LINE_WIDTH; + } else { + offset1 = LINE_WIDTH - 1; + //offset2 = 1; + } + + /* Needed if the message gets lost after 0ms */ + this.x = getTimeXPosition(sendTime); + this.y = getProcessYPosition(senderNum+1) + offset1; + + recalcOnChange(); + paint(); + } + + /** + * Recalc on change. + */ + public void recalcOnChange() { + x1 = getTimeXPosition(sendTime); + y1 = getProcessYPosition(senderNum+1) + offset1; + x2 = getTimeXPosition(recvTime); + y2 = getProcessYPosition(receiverNum+1) + offset2; + + if (isLost) { + x = getTimeXPosition(z); + y = y1 + ( ( (y2-y1) / (x2-x1)) * (x-x1)); + } + + } + + /** + * Draws the message line. + * + * @param g the grpahics object to draw at + * @param globalTime the global time + */ + public void draw(final Graphics2D g, final long globalTime) { + if (isArrived) { + g.setColor(color); + g.drawLine((int) x1, (int) y1, (int) x2, (int) y2); + + } else if (isLost) { + g.setColor(messageLostColor); + g.drawLine((int) x1, (int) y1, (int) x, (int) y); + + } else if (globalTime >= recvTime) { + checkIfMessageIsRelevant(); + isArrived = true; + + if (receiverProcess.isCrashed()) + color = messageLostColor; + else + color = messageArrivedColor; + + draw(g, globalTime); + + } else if (outageTime >= 0 && outageTime <= globalTime) { + checkIfMessageIsRelevant(); + isLost = true; + draw(g, globalTime);; + + } else { + z = globalTime; + x = globalTimeXPosition; + y = y1 + ( ( (y2-y1) / (x2-x1)) * (x-x1)); + g.setColor(messageSendingColor); + g.drawLine((int) x1, (int) y1, (int) x, (int) y); + } + } + + /** + * Checks if the message is relevant. If it's not relevant, then it will + * get removed. + */ + private void checkIfMessageIsRelevant() { + if (prefs.getBoolean("sim.messages.relevant")) { + VSMessageReceiveEvent event = + (VSMessageReceiveEvent) task.getEvent(); + event.init(receiverProcess); + if (!event.isRelevantMessage()) + removeMessageLine(this); + } + } + + /** + * Called if a process within the simulator has been removed at a + * specified index. + * + * @param index the index + * + * @return true, if the sender or the receiver of the message has been + * removed from the simulator. Else false is returned. + */ + public boolean removedAProcessAtIndex(int index) { + if (index == receiverNum || index == senderNum) + return true; + + if (index < receiverNum) + --receiverNum; + + if (index < senderNum) + --senderNum; + + recalcOnChange(); + + return false; + } + + /** + * Gets the message line num. + * + * @return the message line num + */ + public long getMessageLineNum() { + return messageLineNum; + } + + /** + * Checks one line to another if they equal (have the same message line + * id) + * + * @param line the line to compare against + * + * @return true, if they equal + */ + public boolean equals(VSMessageLine line) { + return messageLineNum == line.getMessageLineNum(); + } + + /** + * Gets the task. + * + * @return the task + */ + public VSTask getTask() { + return task; + } + } + + /** + * Instantiates a new VSSimulatorVisualization object. + * + * @param prefs the prefs + * @param simulator the simulator + * @param loging the loging + */ + public VSSimulatorVisualization(VSPrefs prefs, VSSimulator simulator, + VSLogging loging) { + init(prefs, simulator, loging); + } + + /** + * Instantiates inits the VSSimulatorVisualization object. + * + * @param prefs the prefs + * @param simulator the simulator + * @param loging the loging + */ + private void init(VSPrefs prefs, VSSimulator simulator, + VSLogging loging) { + this.prefs = prefs; + this.simulator = simulator; + this.loging = loging; + this.messageLines = new LinkedList<VSMessageLine>(); + this.messageLinesToRemove = new LinkedList<VSMessageLine>(); + + /* May be not null if called from deserialization */ + if (this.taskManager == null) + this.taskManager = new VSTaskManager(prefs, this); + + /* May be not null if called from deserialization */ + if (this.processes == null) { + this.processes = new ArrayList<VSInternalProcess>(); + + numProcesses = prefs.getInteger("sim.process.num"); + for (int i = 0; i < numProcesses; ++i) + processes.add(createProcess(i)); + } + + updateFromPrefs(); + + final VSPrefs finalPrefs = prefs; + final VSSimulator finalSimulator = simulator; + + addMouseListener(new MouseListener() { + public void mouseClicked(MouseEvent me) { + final VSInternalProcess process = getProcessAtYPos(me.getY()); + + if (SwingUtilities.isRightMouseButton(me)) { + ActionListener actionListener = new ActionListener() { + public void actionPerformed(ActionEvent ae) { + String command = ae.getActionCommand(); + if (command.equals( + finalPrefs.getString("lang.process.edit"))) { + editProcess(process); + + } else if (command.equals( + finalPrefs.getString("lang.process.crash"))) { + VSAbstractEvent event = + new VSProcessCrashEvent(); + + taskManager.addTask(new VSTask( + process.getGlobalTime(), + process, event, + VSTask.GLOBAL)); + + } else if (command.equals( + finalPrefs.getString("lang.process.recover"))) { + VSAbstractEvent event = + new VSProcessRecoverEvent(); + + taskManager.addTask(new VSTask( + process.getGlobalTime(), + process, event, + VSTask.GLOBAL)); + + } else if (command.equals( + finalPrefs.getString("lang.process.remove"))) { + removeProcess(process); + + } else if (command.equals( + finalPrefs.getString("lang.process.add.new"))) { + addProcess(); + } + } + }; + + JPopupMenu popup = new JPopupMenu(); + JMenuItem item = null; + + if (process != null) + item = new JMenuItem( + finalPrefs.getString("lang.process.selected") + + ": " + process.getProcessID()); + else + item = new JMenuItem( + finalPrefs.getString("lang.process.not.selected")); + + item.setEnabled(false); + popup.add(item); + popup.addSeparator(); + + item = new JMenuItem( + finalPrefs.getString("lang.process.edit")); + if (process == null) + item.setEnabled(false); + else + item.addActionListener(actionListener); + popup.add(item); + + item = new JMenuItem( + finalPrefs.getString("lang.process.crash")); + + if (process == null || process.isCrashed() || isPaused || + time == 0 || hasFinished) + item.setEnabled(false); + else + item.addActionListener(actionListener); + popup.add(item); + + item = new JMenuItem( + finalPrefs.getString("lang.process.recover")); + + if (process == null || !process.isCrashed() || isPaused || + time == 0 || hasFinished) + item.setEnabled(false); + else + item.addActionListener(actionListener); + popup.add(item); + + item = new JMenuItem( + finalPrefs.getString("lang.process.remove")); + + if (process == null) + item.setEnabled(false); + else + item.addActionListener(actionListener); + popup.add(item); + + popup.addSeparator(); + + final long xPosTime = getXPositionTime(me.getX()); + String timeString = finalPrefs.getString( + "lang.event.add.time") + + " " + xPosTime + "ms"; + + JMenu subMenu = new JMenu( + finalPrefs.getString("lang.event.add.local") + + " " + timeString); + + ArrayList<VSCreateTask> createTasks = + finalSimulator.getCreateTaskObjects(); + + if (process == null) { + subMenu.setEnabled(false); + } else { + JMenu subSubMenu = null; + for (final VSCreateTask createTask : createTasks) { + if (createTask.isDummy()) { + if (subSubMenu != null) + subMenu.add(subSubMenu); + subSubMenu = new JMenu( + createTask.getMenuText()); + } else { + item = new JMenuItem(createTask.getMenuText()); + item.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + VSTask task = + createTask.createTask(process, + xPosTime, + true); + taskManager.addTask( + task, VSTaskManager.PROGRAMMED); + finalSimulator.updateTaskManagerTable(); + } + }); + subSubMenu.add(item); + } + } + } + + popup.add(subMenu); + + subMenu = new JMenu( + finalPrefs.getString("lang.event.add.global") + + " " + timeString); + if (process == null) { + subMenu.setEnabled(false); + } else { + JMenu subSubMenu = null; + for (final VSCreateTask createTask : createTasks) { + if (createTask.isDummy()) { + if (subSubMenu != null) + subMenu.add(subSubMenu); + subSubMenu = new JMenu( + createTask.getMenuText()); + } else { + item = new JMenuItem(createTask.getMenuText()); + item.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + VSTask task = + createTask.createTask(process, + xPosTime, + false); + taskManager.addTask( + task, VSTaskManager.PROGRAMMED); + finalSimulator.updateTaskManagerTable(); + } + }); + subSubMenu.add(item); + } + } + } + + if (finalPrefs.getBoolean("sim.mode.expert")) + popup.add(subMenu); + + popup.addSeparator(); + + item = new JMenuItem( + finalPrefs.getString("lang.process.add.new")); + + item.addActionListener(actionListener); + popup.add(item); + + + popup.show(me.getComponent(), me.getX(), me.getY()); + + } else { + editProcess(process); + } + } + + public void mouseExited(MouseEvent e) { + if (highlightedProcess != null) { + highlightedProcess.highlightOff(); + highlightedProcess = null; + paint(); + } + } + + public void mouseEntered(MouseEvent e) { } + + public void mousePressed(MouseEvent e) { } + + public void mouseReleased(MouseEvent e) { } + + }); + addMouseMotionListener(new MouseMotionListener() { + public void mouseDragged(MouseEvent e) { } + + public void mouseMoved(MouseEvent e) { + VSInternalProcess p = getProcessAtYPos(e.getY()); + + if (p == null) { + if (highlightedProcess != null) { + highlightedProcess.highlightOff(); + highlightedProcess = null; + } + + if (isPaused) + paint(); + + return; + } + + if (highlightedProcess != null) { + if (highlightedProcess.getProcessID() != p.getProcessID()) { + highlightedProcess.highlightOff(); + highlightedProcess = p; + p.highlightOn(); + } + } else { + highlightedProcess = p; + p.highlightOn(); + } + + if (isPaused) + paint(); + } + + }); + + addHierarchyBoundsListener(new HierarchyBoundsListener() { + public void ancestorMoved(HierarchyEvent e) { } + + public void ancestorResized(HierarchyEvent e) { + recalcOnChange(); + } + }); + } + + /** + * This method gets called if the window border of the simulator canvas + * has changed. This method contains very ugly code. But this has to be in + * order to gain performance! + */ + private void recalcOnChange() { + synchronized (processes) { + if (processes.size() == 0) + return; + } + + processlineColor = prefs.getColor("col.process.line"); + processSecondlineColor = prefs.getColor("col.process.secondline"); + processSeplineColor = prefs.getColor("col.process.sepline"); + messageArrivedColor = prefs.getColor("col.message.arrived"); + messageSendingColor = prefs.getColor("col.message.sending"); + messageLostColor = prefs.getColor("col.message.lost"); + backgroundColor = prefs.getColor("col.background"); + + paintSize = simulator.getPaintSize(); + xPaintSize = simulator.getWidth() - + (3 * XOFFSET + simulator.getSplitSize()); + yDistance = (simulator.getPaintSize() - + 2 * (YOFFSET + YOUTER_SPACEING))/ numProcesses; + xpaintsize_dividedby_untiltime = xPaintSize / (double) untilTime; + + + synchronized (messageLines) { + for (VSMessageLine messageLine : messageLines) + messageLine.recalcOnChange(); + } + + /* paintProcesses optimization, precalc things */ + { + xoffset_plus_xpaintsize = XOFFSET + (int) xPaintSize; + if (numProcesses > 1) + paintProcessesOffset = + (int) ((paintSize-2* (YOFFSET+ + YOUTER_SPACEING+YSEPLINE_SPACEING))/ + (numProcesses-1)); + else + paintProcessesOffset = + (int) ((paintSize-2*(YOFFSET+ + YOUTER_SPACEING+YSEPLINE_SPACEING))); + } + + /* paintSecondlines optimization, precalc things */ + { + int yMax = YOFFSET + YOUTER_SPACEING + + (int) (numProcesses * yDistance); + paintSecondlinesSeconds = (int) untilTime / 1000; + paintSecondlinesLine[1] = YOFFSET; + paintSecondlinesLine[3] = yMax; + paintSecondlinesYStringPos1 = paintSecondlinesLine[1] - 5; + paintSecondlinesYStringPos2 = paintSecondlinesLine[3] + 15; + } + + /* paitnGlobalTime optimization, precalc things */ + { + paintGlobalTimeYPosition = YOFFSET + YOUTER_SPACEING + + (int) (numProcesses * yDistance); + } + + if (strategy != null) { + synchronized (strategy) { + g = (Graphics2D) strategy.getDrawGraphics(); + g.setColor(backgroundColor); + if (isAntiAliased) + g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, + RenderingHints.VALUE_ANTIALIAS_ON); + } + } + } + + /** + * Updates the simulator. + * + * @param globalTime the global time + * @param lastGlobalTime the last global time + */ + private void updateSimulator(long globalTime, long lastGlobalTime) { + if (isPaused || hasFinished) + return; + + long lastSimulatorTime = simulatorTime; + long offset = globalTime - lastGlobalTime; + + clockOffset += offset * clockSpeed; + + while (clockOffset >= 1) { + --clockOffset; + ++simulatorTime; + } + + if (simulatorTime > untilTime) + simulatorTime = untilTime; + + offset = simulatorTime - lastSimulatorTime; + + for (long l = 0; l < offset; ++l) + taskManager.runTasks(l, offset, lastSimulatorTime); + + synchronized (processes) { + for (VSInternalProcess process : processes) + process.syncTime(simulatorTime); + } + } + + /** + * Paints the simulator. + */ + public void paint() { + while (getBufferStrategy() == null) { + createBufferStrategy(3); + strategy = getBufferStrategy(); + + if (strategy != null) { + g = (Graphics2D) strategy.getDrawGraphics(); + g.setColor(backgroundColor); + } + } + + synchronized (strategy) { + if (isAntiAliasedChanged) { + if (isAntiAliased) + g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, + RenderingHints.VALUE_ANTIALIAS_ON); + else + g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, + RenderingHints.VALUE_ANTIALIAS_OFF); + isAntiAliasedChanged = false; + } + + g.fillRect(0, 0, getWidth(), getHeight()); + long globalTime = simulatorTime; + + globalTimeXPosition = getTimeXPosition(globalTime); + paintSecondlines(g); + paintProcesses(g, globalTime); + paintGlobalTime(g, globalTime); + + synchronized (messageLines) { + synchronized (messageLinesToRemove) { + if (messageLinesToRemove.size() > 0) { + for (VSMessageLine removeThis : messageLinesToRemove) + messageLines.remove(removeThis); + messageLinesToRemove.clear(); + } + } + + for (VSMessageLine line : messageLines) + line.draw(g, globalTime); + } + + g.setColor(backgroundColor); + strategy.show(); + } + } + + /** + * Paints the processes. + * + * @param g the graphics object + * @param globalTime the global time + */ + private void paintProcesses(Graphics2D g, long globalTime) { + /* First paint the horizontal process timelines + * Second paint the processes + */ + final int yOffset = YOFFSET + YOUTER_SPACEING + YSEPLINE_SPACEING; + final int xPoints[] = { XOFFSET, xoffset_plus_xpaintsize, + xoffset_plus_xpaintsize, XOFFSET, XOFFSET + }; + final int yPoints[] = { yOffset, yOffset, yOffset + LINE_WIDTH, + yOffset + LINE_WIDTH, yOffset + }; + + synchronized (processes) { + for (VSInternalProcess process : processes) { + final long localTime = process.getTime(); + + g.setColor(process.getColor()); + g.fillPolygon(xPoints, yPoints, 5); + + if (process.hasCrashed()) { + g.setColor(process.getCrashedColor()); + final Long crashHistory[] = process.getCrashHistoryArray(); + final int length = crashHistory.length; + + for (int i = 0; i < length; i += 2) { + final int crashStartPos = + (int) getTimeXPosition( + crashHistory[i].longValue()); + int crashEndPos; + + if (i == length - 1) + crashEndPos = xoffset_plus_xpaintsize; + else + crashEndPos = (int) getTimeXPosition( + crashHistory[i+1].longValue()); + + final int xPointsCrashed[] = { + crashStartPos, crashEndPos, + crashEndPos, crashStartPos, crashStartPos + }; + g.fillPolygon(xPointsCrashed, yPoints, 5); + } + } + + g.setColor(process.getColor()); + g.drawString("P" + process.getProcessID() + ":", XOFFSET - 30, + yPoints[0] + LINE_WIDTH); + + final long tmp = localTime > untilTime ? untilTime : localTime; + final int xPos = 1 + (int) getTimeXPosition(tmp); + final int yStart = yPoints[0] - 14; + final int yEnd = yPoints[0]; + + g.setColor(processlineColor); + g.drawLine(xPos, yStart, xPos, yEnd); + g.drawString(localTime+"ms", xPos + 2, yStart + TEXT_SPACEING); + + if (showLamport) + paintTime(g, process.getLamportTimeArray(), process, + yStart, 25); + else if (showVectorTime) + paintTime(g, process.getVectorTimeArray(), process, + yStart, 20 * numProcesses); + + for (int i = 0; i < 5; ++i) + yPoints[i] += paintProcessesOffset; + } + } + } + + /** + * Paints the time. (e.g. lamport time or vector time) + * + * @param g the graphics object + * @param times the times + * @param process the process + * @param yStart the y start + * @param distance the distance + */ + private void paintTime(final Graphics2D g, final VSTime times[], + final VSInternalProcess process, final int yStart, + final int distance) { + + final int lastPos[] = { -1, -1, -1, -1 }; + + for (VSTime time : times) { + int xPos = (int) getTimeXPosition(time.getGlobalTime()); + int bestRow[] = { -1, -1 }; + + for (int i = 0; i < 4; ++i) { + if (lastPos[i] != -1) { + int diff = xPos - lastPos[i]; + if (diff > distance) { + bestRow[0] = i; + bestRow[1] = -1; + break; + } else if (bestRow[0] == -1) { + bestRow[0] = i; + bestRow[1] = diff; + } else if (diff > bestRow[1]) { + bestRow[0] = i; + bestRow[1] = diff; + } + } else { + bestRow[0] = i; + bestRow[1] = -1; + break; + } + } + + final int row = bestRow[0]; + if (bestRow[1] != -1) + xPos += distance - bestRow[1]; + + g.drawString(time.toString(), xPos + 2, yStart + 3 * + TEXT_SPACEING + row * ROW_HEIGHT); + lastPos[row] = xPos; + } + } + + /** + * Paint the second lines. + * + * @param g the graphics object + */ + private void paintSecondlines(Graphics2D g) { + g.setColor(processSecondlineColor); + + int i; + for (i = 0; i <= paintSecondlinesSeconds; i += secondsSpaceing) { + paintSecondlinesLine[0] = paintSecondlinesLine[2] = + (int) getTimeXPosition(i*1000); + g.drawLine(paintSecondlinesLine[0], paintSecondlinesLine[1], + paintSecondlinesLine[2], paintSecondlinesLine[3]); + + final int xStringPos = paintSecondlinesLine[0] - 5; + g.drawString(i+"s", xStringPos, paintSecondlinesYStringPos1); + if (!showVectorTime && !showLamport) + g.drawString(i+"s", xStringPos, paintSecondlinesYStringPos2); + } + + if (i > paintSecondlinesSeconds) { + paintSecondlinesLine[0] = paintSecondlinesLine[2] = + (int) getTimeXPosition(untilTime); + g.drawLine(paintSecondlinesLine[0], paintSecondlinesLine[1], + paintSecondlinesLine[2], paintSecondlinesLine[3]); + } + } + + /** + * Paints the global time. + * + * @param g the graphics object + * @param globalTime the global time + */ + private void paintGlobalTime(Graphics2D g, long globalTime) { + g.setColor(processSeplineColor); + final int xOffset = (int) globalTimeXPosition; + + final int xPoints[] = { + xOffset, xOffset + SEPLINE_WIDTH, + xOffset + SEPLINE_WIDTH, xOffset, xOffset + }; + final int yOffset = YOFFSET - 8; + final int yPoints[] = { + yOffset, yOffset, paintGlobalTimeYPosition, + paintGlobalTimeYPosition, yOffset + }; + + g.fillPolygon(xPoints, yPoints, 5); + g.drawString(globalTime+"ms", xPoints[1]+1, yPoints[0]+TEXT_SPACEING); + } + + /** + * Gets the process at a specified y pos. + * + * @param yPos the y pos + * + * @return the process at y pos + */ + private VSInternalProcess getProcessAtYPos(int yPos) { + final int reachDistance = (int) (yDistance/3); + int y = YOFFSET + YOUTER_SPACEING + YSEPLINE_SPACEING; + + int yOffset = numProcesses > 1 + ? (int) ((paintSize-2* + (YOFFSET+YOUTER_SPACEING+YSEPLINE_SPACEING))/ + (numProcesses-1)) + : (int) ((paintSize-2* + (YOFFSET+YOUTER_SPACEING+YSEPLINE_SPACEING))); + + for (int i = 0; i < numProcesses; ++i) { + if (yPos < y + reachDistance && yPos > y - reachDistance - + LINE_WIDTH) { + VSInternalProcess process = null; + synchronized (processes) { + process = processes.get(i); + } + return process; + } + y += yOffset; + } + + return null; + } + + /** + * Gets the x position of the given time. + * + * @param time the time + * + * @return the time x position + */ + private double getTimeXPosition(long time) { + return XOFFSET + xpaintsize_dividedby_untiltime * time; + } + + /** + * Gets the time of a given x position + * + * @param xPos the x position + * + * @return the time + */ + private long getXPositionTime(double xPos) { + xPos -= XOFFSET; + + if (xPos <= 0) + return 0; + + else if (xPos >= xPaintSize) + return untilTime; + + return (long) ((untilTime/xPaintSize) * xPos); + } + + /** + * Gets the process y position. + * + * @param i the process num + * + * @return the process y position + */ + private int getProcessYPosition(int i) { + int y; + + if (numProcesses > 1) + y = (int) ((paintSize - + 2 * (YOFFSET + YOUTER_SPACEING + YSEPLINE_SPACEING))/ + (numProcesses-1)); + else + y = (int) ((paintSize - + 2 * (YOFFSET + YOUTER_SPACEING + YSEPLINE_SPACEING))); + + return y * (i - 1) + YOFFSET + YOUTER_SPACEING + YSEPLINE_SPACEING; + } + + /** + * Gets the time. + * + * @return the time + */ + public long getTime() { + return simulatorTime; + } + + /** + * Gets the until time. + * + * @return the until time + */ + public long getUntilTime() { + return untilTime; + } + + /** + * Gets the start time. + * + * @return the start time + */ + public long getStartTime() { + return startTime; + } + + /** + * Gets the next process id. + * + * @return the next process id + */ + public int processIDCount() { + return ++processCounter; + } + + /** + * Gets the task manager. + * + * @return the task manager + */ + public VSTaskManager getTaskManager() { + return taskManager; + } + + /** + * Gets the num of processes. + * + * @return the num of processes + */ + public int getNumProcesses() { + return numProcesses; + } + + /** + * Gets the specified process. + * + * @param processNum the process num to get the process of + * + * @return the process + */ + public VSInternalProcess getProcess(int processNum) { + synchronized (processes) { + if (processNum >= processes.size()) + return null; + + return processes.get(processNum); + } + } + + /* (non-Javadoc) + * @see java.lang.Runnable#run() + */ + public void run() { + while (true) { + while (!hasThreadStopped && (isPaused || hasFinished || + isResetted)) { + try { + Thread.sleep(100); + paint(); + + } catch (Exception e) { + System.out.println(e); + } + } + + if (hasThreadStopped) + break; /* Exit the thread */ + + while (!isPaused && !hasThreadStopped) { + try { + Thread.sleep(threadSleep); + } catch (Exception e) { + System.out.println(e); + } + + updateSimulator(time, lastTime); + + if (simulatorTime == untilTime) { + finish(); + break; + } + + paint(); + lastTime = time; + time = System.currentTimeMillis() - startTime; + } + + updateSimulator(time, lastTime); + paint(); + } + } + + /** + * Starts/plays the simulator. + */ + public void play() { + loging.log(prefs.getString("lang.simulator.started")); + final long currentTime = System.currentTimeMillis(); + + synchronized (processes) { + for (VSInternalProcess p : processes) + p.play(); + } + + if (isResetted) + isResetted = false; + + else if (hasFinished) + hasFinished = false; + + if (isPaused) { + isPaused = false; + startTime += currentTime - pauseTime; + time = currentTime - startTime; + + } else { + startTime = currentTime; + time = 0; + } + + paint(); + } + + /** + * Called if the simulator has finished. + */ + public void finish() { + synchronized (processes) { + for (VSInternalProcess p : processes) + p.finish(); + } + + simulator.finish(); + hasFinished = true; + loging.log(prefs.getString("lang.simulator.finished")); + paint(); + + if (prefs.getBoolean("sim.periodic")) { + VSSimulatorFrame simulatorFrame = simulator.getSimulatorFrame(); + simulatorFrame.resetCurrentSimulator(); + simulatorFrame.startCurrentSimulator(); + } + } + + /** + * Call this, in order to pause the simulator. + */ + public void pause() { + isPaused = true; + synchronized (processes) { + for (VSInternalProcess p : processes) + p.pause(); + } + + pauseTime = System.currentTimeMillis(); + loging.log(prefs.getString("lang.simulator.paused")); + paint(); + } + + /** + * Call this, in order to reset the simulator. + */ + public void reset() { + if (!isResetted) { + loging.log(prefs.getString("lang.simulator.resetted")); + + isResetted = true; + isPaused = false; + hasFinished = false; + startTime = System.currentTimeMillis(); + time = 0; + lastTime = 0; + clockOffset = 0; + simulatorTime = 0; + + synchronized (processes) { + for (VSInternalProcess process : processes) + process.reset(); + } + + /* Reset the task manager AFTER the processes, for the programmed + tasks */ + taskManager.reset(); + + synchronized (processes) { + for (VSInternalProcess process : processes) + process.createRandomCrashTask(); + } + + synchronized (messageLines) { + messageLines.clear(); + } + + synchronized (messageLinesToRemove) { + messageLinesToRemove.clear(); + } + + paint(); + loging.clear(); + } + } + + /** + * Stops the thread of the simulator. + */ + public void stopThread() { + hasThreadStopped = true; + } + + /** + * Checks if the thread has been stopped. + * + * @return true, if is thread has stopped + */ + public boolean hasThreadStopped() { + return hasThreadStopped; + } + + /** + * Sets, if the the lamport time should be shown. It implicitly disables + * the vector time. + * + * @param showLamport true, if the lamport time should be shown + */ + public void showLamport(boolean showLamport) { + this.showLamport = showLamport; + if (isPaused) + paint(); + } + + /** + * Sets, if the vector time should be shown. It implicitly disables the + * lamport time. + * + * @param showVectorTime true, if the vector time should be shown + */ + public void showVectorTime(boolean showVectorTime) { + this.showVectorTime = showVectorTime; + if (isPaused) + paint(); + } + + /** + * Sets if the simulator graphics are anti aliased. + * + * @param isAntiAliased true, if the simulator is anti aliased + */ + public void isAntiAliased(boolean isAntiAliased) { + this.isAntiAliased = isAntiAliased; + this.isAntiAliasedChanged = true; + if (isPaused) + paint(); + } + + /** + * Sends a message. + * + * @param message the message + */ + public void sendMessage(VSMessage message) { + VSTask task = null; + VSAbstractEvent receiveEvent = null; + VSInternalProcess sendingProcess = (VSInternalProcess) + message.getSendingProcess(); + long deliverTime, outageTime, durationTime; + boolean recvOwn = prefs.getBoolean("sim.message.own.recv"); + + synchronized (processes) { + for (VSInternalProcess receiverProcess : processes) { + if (receiverProcess.equals(sendingProcess)) { + if (recvOwn) { + deliverTime = sendingProcess.getGlobalTime(); + receiveEvent = new VSMessageReceiveEvent(message); + task = new VSTask(deliverTime, receiverProcess, + receiveEvent, VSTask.GLOBAL); + taskManager.addTask(task); + } + + } else { + durationTime = sendingProcess.getDurationTime(); + + if (prefs.getBoolean("sim.message.sendingtime.mean")) { + durationTime += receiverProcess.getDurationTime(); + durationTime /= 2; + } + + deliverTime = sendingProcess.getGlobalTime() + + durationTime; + + if (prefs.getBoolean("sim.message.prob.mean")) + outageTime = sendingProcess.getARandomMessageOutageTime( + durationTime, receiverProcess); + else + outageTime = sendingProcess.getARandomMessageOutageTime( + durationTime, null); + + receiveEvent = new VSMessageReceiveEvent(message); + task = new VSTask(deliverTime, receiverProcess, + receiveEvent, VSTask.GLOBAL); + + /* Only add a 'receiving message' task if the message will + not get lost! */ + if (outageTime == -1) + taskManager.addTask(task); + + synchronized (messageLines) { + messageLines.add( + new VSMessageLine(receiverProcess, + sendingProcess.getGlobalTime(), + deliverTime, outageTime, + sendingProcess.getProcessNum(), + receiverProcess.getProcessNum(), + task)); + } + } + } + } + } + + /** + * Edits the process. + * + * @param processNum the process num + */ + public void editProcess(int processNum) { + synchronized (processes) { + VSInternalProcess process = processes.get(processNum); + /* May be null if another thread changed the processes arraylist + before this process actually called editProcess */ + if (process != null) + editProcess(process); + } + } + + /** + * Edits the process. + * + * @param process the process + */ + public void editProcess(VSInternalProcess process) { + if (process != null) { + process.updatePrefs(); + new VSEditorFrame(prefs, simulator.getSimulatorFrame(), + new VSProcessEditor(prefs, process)); + } + } + + /** + * Gets the processes array. + * + * @return the processes array + */ + public ArrayList<VSInternalProcess> getProcessesArray() { + ArrayList<VSInternalProcess> arr = new ArrayList<VSInternalProcess>(); + + synchronized (processes) { + for (VSInternalProcess process : processes) + arr.add(process); + } + + return arr; + } + + /** + * Gets the processes IDs. + * + * @return the processes IDs + */ + public Integer[] getProcessIDs() { + Integer pids[] = null; + + synchronized (processes) { + pids = new Integer[numProcesses]; + for (int i = 0; i < numProcesses; ++i) + pids[i] = Integer.valueOf(processes.get(i).getProcessID()); + } + + return pids; + } + + /** + * Gets the processes. + * + * @return the processes + */ + public ArrayList<VSInternalProcess> getProcesses() { + return processes; + } + + /** + * Updates from the prefs. Called by the VSSimulatorEditor if values + * have been saved. + */ + public void updateFromPrefs() { + untilTime = prefs.getInteger("sim.seconds") * 1000; + clockSpeed = prefs.getFloat("sim.clock.speed"); + + secondsSpaceing = (int) (untilTime / 15000); + if (secondsSpaceing == 0) + secondsSpaceing = 1; + + threadSleep = (int) (untilTime / 7500); + if (threadSleep == 0) + threadSleep = 1; + + recalcOnChange(); + } + + /** + * Removes a specific message line from the painting area. + * + * @param messageLine the message line to remove + */ + private void removeMessageLine(VSMessageLine messageLine) { + synchronized (messageLinesToRemove) { + messageLinesToRemove.add(messageLine); + } + } + + /** + * Removes a process from the simulator. + * + * @param process the process + */ + private void removeProcess(VSInternalProcess process) { + if (numProcesses == 1) { + simulator.getSimulatorFrame().removeSimulator(simulator); + + } else { + int index = 0; + synchronized (processes) { + index = processes.indexOf(process); + processes.remove(index); + + for (VSInternalProcess p : processes) + p.removedAProcessAtIndex(index); + + numProcesses = processes.size(); + } + + taskManager.removeTasksOf(process); + simulator.removedAProcessAtIndex(index); + recalcOnChange(); + + ArrayList<VSMessageLine> removeThose = + new ArrayList<VSMessageLine>(); + + synchronized (messageLines) { + for (VSMessageLine line : messageLines) + if (line.removedAProcessAtIndex(index)) + removeThose.add(line); + + for (VSMessageLine line : removeThose) { + VSTask deliverTask = line.getTask(); + + if (deliverTask != null) + taskManager.removeTask(deliverTask); + + messageLines.remove(line); + } + } + } + } + + /** + * Creates a process with the specified num. + * + * @param processNum the process num + * + * @return the new process + */ + private VSInternalProcess createProcess(int processNum) { + VSInternalProcess process = + new VSInternalProcess(prefs, processNum, this, loging); + loging.log(prefs.getString("lang.process.new") + "; " + process); + return process; + } + + /** + * Adds a new process to the simulator. + * + * @return The process which has been added + */ + private VSInternalProcess addProcess() { + VSInternalProcess newProcess = null; + //int foo = -1; + //System.out.println("ADD " + ++foo); + synchronized (processes) { + //System.out.println("ADD " + ++foo); + numProcesses = processes.size() + 1; + //System.out.println("ADD " + ++foo); + newProcess = createProcess(processes.size()); + //System.out.println("ADD " + ++foo); + //System.out.println("ADD " + ++foo); + } + + //System.out.println("ADD " + ++foo); + addProcess(newProcess); + //System.out.println("ADD " + ++foo); + return newProcess; + } + + /** + * Adds a the given process to the simulator. + * + * @newProcess The process to add + */ + private void addProcess(VSInternalProcess newProcess) { + //int foo = -1; + //System.out.println("ADD_ " + ++foo); + synchronized (processes) { + //System.out.println("ADD_ " + ++foo); + processes.add(newProcess); + + for (VSInternalProcess process : processes) + if (!process.equals(newProcess)) + process.addedAProcess(); + //System.out.println("ADD_ " + ++foo); + } + + //System.out.println("ADD_ " + ++foo); + recalcOnChange(); + //System.out.println("ADD_ " + ++foo); + simulator.addProcessAtIndex(processes.size()-1); + //System.out.println("ADD_ " + ++foo); + } + + /** + * Checks if the simulation is paused. + * + * @return true, if the simulation is paused + */ + boolean isPaused() { + return isPaused; + } + + /** + * Checks if the simulation is resetted. + * + * @return true, if the simulation is resetted + */ + boolean isResetted() { + return isResetted; + } + + /** + * Checks if the simulation has finished + * + * @return true, if the simulation has finished + */ + boolean hasFinished() { + return hasFinished; + } + + /* (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(processCounter)); + + synchronized (processes) { + objectOutputStream.writeObject(Integer.valueOf(numProcesses)); + for (VSInternalProcess process : processes) + process.serialize(serialize, objectOutputStream); + } + + taskManager.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: VSSimulatorVisualization"); + + /** For later backwards compatibility, to add more stuff */ + objectInputStream.readObject(); + + processCounter = ((Integer) objectInputStream.readObject()).intValue(); + + int num = ((Integer) objectInputStream.readObject()).intValue(); + loging.clear(); + + if (num > numProcesses) { + for (int i = numProcesses; i < num; ++i) + addProcess(); + } else { + int oldNum = numProcesses; + for (int i = num; i < oldNum; ++i) + removeProcess(getProcess(0)); + } + + for (int i = 0; i < num; ++i) + processes.get(i).deserialize(serialize, objectInputStream); + + taskManager.deserialize(serialize, objectInputStream); + + /** For later backwards compatibility, to add more stuff */ + objectInputStream.readObject(); + } +} diff --git a/src/main/java/utils/VS3Tupel.java b/src/main/java/utils/VS3Tupel.java new file mode 100644 index 0000000..ac7ffba --- /dev/null +++ b/src/main/java/utils/VS3Tupel.java @@ -0,0 +1,58 @@ +package utils; + +/** + * The class VS3Tupel, an object of this class represents a 3-Tupel of objects. + * Each object can have its own type. + * + * @author Paul C. Buetow + */ +public final class VS3Tupel<A,B,C> { + /** The a. */ + private A a; + + /** The b. */ + private B b; + + /** The c. */ + private C c; + + /** + * Instantiates a new tupel. + * + * @param a the a + * @param b the b + * @param c the c + */ + public VS3Tupel(A a, B b, C c) { + this.a = a; + this.b = b; + this.c = c; + } + + /** + * Gets the a. + * + * @return the a + */ + public A getA() { + return a; + } + + /** + * Gets the b. + * + * @return the b + */ + public B getB() { + return b; + } + + /** + * Gets the c. + * + * @return the c + */ + public C getC() { + return c; + } +} diff --git a/src/main/java/utils/VSAboutFrame.java b/src/main/java/utils/VSAboutFrame.java new file mode 100644 index 0000000..e07289f --- /dev/null +++ b/src/main/java/utils/VSAboutFrame.java @@ -0,0 +1,87 @@ +package utils; + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Component; +import java.awt.Container; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +import javax.swing.JButton; +import javax.swing.JPanel; +import javax.swing.JScrollPane; + +//import utils.*; +import prefs.VSPrefs; + +/** + * The class VSAboutFrame. This class is only for the about window which + * shows up if selected in the GUI. + * + * @author Paul C. Buetow + */ +public class VSAboutFrame extends VSFrame { + /** The prefs. */ + private VSPrefs prefs; + + /** + * Instantiates a new VSAboutFrame object. + * + * @param prefs the prefs + * @param relativeTo the component to open the about window relative to + */ + public VSAboutFrame(VSPrefs prefs, Component relativeTo) { + super(prefs.getString("lang.name") + " - " + + prefs.getString("lang.about"), relativeTo); + this.prefs = prefs; + + disposeWithParent(); + setContentPane(createContentPane()); + setSize(350, 250); + setResizable(false); + setVisible(true); + } + + /** + * Creates the content pane. + * + * @return the container + */ + public Container createContentPane() { + Container contentPane = getContentPane(); + + VSInfoArea infoArea = new VSInfoArea( + prefs.getString("lang.about.info")); + JPanel buttonPane = createButtonPanel(); + JScrollPane scrollPane = new JScrollPane(infoArea); + + contentPane.add(scrollPane, BorderLayout.CENTER); + contentPane.add(buttonPane, BorderLayout.SOUTH); + + return contentPane; + } + + /** + * Creates the button panel. + * + * @return the panel + */ + public JPanel createButtonPanel() { + JPanel buttonPane = new JPanel(); + buttonPane.setBackground(Color.WHITE); + + JButton closeButton = new JButton( + prefs.getString("lang.close")); + closeButton.setMnemonic(prefs.getInteger("keyevent.close")); + closeButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + String actionCommand = e.getActionCommand(); + if (actionCommand.equals(prefs.getString("lang.close"))) + dispose(); + } + }); + buttonPane.add(closeButton); + + return buttonPane; + } +} diff --git a/src/main/java/utils/VSClassLoader.java b/src/main/java/utils/VSClassLoader.java new file mode 100644 index 0000000..37f4027 --- /dev/null +++ b/src/main/java/utils/VSClassLoader.java @@ -0,0 +1,29 @@ +package utils; + +/** + * The class VSClassLoader. This class is used in order to create new objects + * by its classnames. + * + * @author Paul C. Buetow + */ +public class VSClassLoader extends ClassLoader { + /** + * Creates a new instance of the given classname. + * + * @param classname the classname + * + * @return the object + */ + public Object newInstance(String classname) { + Object object = null; + + try { + object = super.loadClass(classname, true).getDeclaredConstructor().newInstance(); + + } catch (Exception e) { + System.out.println(e + "; Classname " + classname); + } + + return object; + } +} diff --git a/src/main/java/utils/VSFrame.java b/src/main/java/utils/VSFrame.java new file mode 100644 index 0000000..818a72d --- /dev/null +++ b/src/main/java/utils/VSFrame.java @@ -0,0 +1,118 @@ +package utils; + +import java.awt.Component; +import java.awt.Dimension; +import java.awt.Point; +import java.awt.Toolkit; +import java.awt.Window; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; + +import javax.swing.JFrame; + +/** + * The class VSFrame. All frames of the simulator extend this VSFrame class. + * This class makes sure that all 'subwindows' get closed if its parent gets + * closed. And it also makes sure to open new windows relative to its parent. + * + * @author Paul C. Buetow + */ +public class VSFrame extends JFrame { + /** The serial version uid */ + private static final long serialVersionUID = 1L; + + /** The Constant X_LOCATION_OFFSET. */ + private final static int X_LOCATION_OFFSET = 40; + + /** The Constant Y_LOCATION_OFFSET. */ + private final static int Y_LOCATION_OFFSET = 80; + + /** The parent window/component. */ + private Component parent; + + /** True, if the current window will get disposed with its parent. */ + private boolean dispose; + + /** + * Instantiates a VSFrame object. + * + * @param title the title + * @param parent the parent + */ + public VSFrame(String title, Component parent) { + super(title); + init(parent); + } + + /** + * Instantiates a new VSFrame object. + * + * @param title the title + */ + public VSFrame(String title) { + super(title); + init(null); + } + + /** + * Inits the VSFrame. + * + * @param parent the parent + */ + private void init(Component parent) { + this.parent = parent; + this.dispose = false; + } + + /** + * Dispose with its parent. + */ + public void disposeWithParent() { + if (!dispose && parent != null && parent instanceof Window) { + Window window = (Window) parent; + window.addWindowListener(new WindowAdapter() { + public void windowClosed(WindowEvent we) { + VSFrame.this.dispose(); + } + }); + } + dispose = true; + } + + /** + * Sets the correct location of the window. + */ + private void setCorrectLocation() { + int x = 0, y = 0; + final Dimension screenSize = + Toolkit.getDefaultToolkit().getScreenSize(); + + if (parent == null) { + x = (int) (screenSize.width - getWidth()) / 2; + y = 50;//(int) (screenSize.height - getHeight()) / 2; + + } else { + final Point location = parent.getLocation(); + x = (int) location.getX() + X_LOCATION_OFFSET; + y = (int) location.getY() + Y_LOCATION_OFFSET; + } + + if (x + super.getWidth() >= screenSize.width) + x = screenSize.width - super.getWidth(); + else if (x < 0) + x = 0; + + if (y + super.getHeight() >= screenSize.height) + y = screenSize.height - super.getHeight(); + + super.setLocation(x, y); + } + + /* (non-Javadoc) + * @see java.awt.Window#setSize(int, int) + */ + public void setSize(int width, int height) { + super.setSize(width, height); + setCorrectLocation(); + } +} diff --git a/src/main/java/utils/VSInfoArea.java b/src/main/java/utils/VSInfoArea.java new file mode 100644 index 0000000..645afb1 --- /dev/null +++ b/src/main/java/utils/VSInfoArea.java @@ -0,0 +1,49 @@ +package utils; + +import java.awt.Color; + +import javax.swing.JTextPane; +import javax.swing.border.CompoundBorder; +import javax.swing.border.EmptyBorder; +import javax.swing.border.LineBorder; + +/** + * The class VSInfoArea, an object of this class is used for some information + * areas. E.g. in the VSAboutFrame class. + * + * @author Paul C. Buetow + */ +public class VSInfoArea extends JTextPane { + /** The serial version uid */ + private static final long serialVersionUID = 1L; + + /** + * Instantiates a new VSInfoArea. + */ + public VSInfoArea() { + init(); + } + + /** + * Instantiates a new VSInfoArea. + * + * @param text the text to display + */ + public VSInfoArea(String text) { + setText(text); + init(); + } + + /** + * Inits the info area. + */ + private void init() { + setOpaque(false); + setBorder(null); + setFocusable(false); + setBorder(new CompoundBorder( + new LineBorder(Color.BLACK), + new EmptyBorder(15, 15, 15, 15))); + setBackground(Color.WHITE); + } +} diff --git a/src/main/java/utils/VSPriorityQueue.java b/src/main/java/utils/VSPriorityQueue.java new file mode 100644 index 0000000..d706352 --- /dev/null +++ b/src/main/java/utils/VSPriorityQueue.java @@ -0,0 +1,32 @@ +package utils; + +import java.util.PriorityQueue; + +/** + * The class VSPriorityQueue. This class is the same like the standard + * VSPriorityQueue of the Java API. It only overrides the get(int) method. + * + * @author Paul C. Buetow + */ +public final class VSPriorityQueue<T> extends PriorityQueue<T> { + /** The serial version uid */ + private static final long serialVersionUID = 1L; + + /** + * Gets the specific element. If the index is out of bounds, it will return + * null. + * + * @param index the index + * + * @return the element, or null, if out of bounds + */ + public T get(int index) { + int i = 0; + + for (T t : this) + if (i++ == index) + return t; + + return null; + } +} diff --git a/src/main/java/utils/VSRandom.java b/src/main/java/utils/VSRandom.java new file mode 100644 index 0000000..6c1de90 --- /dev/null +++ b/src/main/java/utils/VSRandom.java @@ -0,0 +1,37 @@ +package utils; + +import java.util.Random; + +/** + * The class VSRandom. Some customization of the standard Random class of Java. + * + * @author Paul C. Buetow + */ +public final class VSRandom extends Random { + /** + * Instantiates a new VSrandom object. + * + * @param seedAdd the seed to add. + */ + public VSRandom(long seedAdd) { + super(seedAdd*System.currentTimeMillis()+seedAdd); + } + + /* (non-Javadoc) + * @see java.util.Random#nextInt() + */ + public int nextInt() { + return Math.abs(super.nextInt()); + } + + /** + * Next long. + * + * @param mod the mod + * + * @return the random long + */ + public long nextLong(long mod) { + return Math.abs((super.nextLong() + System.currentTimeMillis()) % mod); + } +} diff --git a/src/main/java/utils/VSTools.java b/src/main/java/utils/VSTools.java new file mode 100644 index 0000000..ceb5760 --- /dev/null +++ b/src/main/java/utils/VSTools.java @@ -0,0 +1,92 @@ +package utils; + +import java.util.Vector; + +/** + * The class VSTools. This class contains only static methods. Those methods + * are for general usage and don't fit into other classes. + * + * @author Paul C. Buetow + */ +public final class VSTools { + /** + * Gets the time string. + * + * @param time the time + * + * @return the time string + */ + public static String getTimeString(long time) { + String ret = ""+time; + + while (ret.length() < 6) + ret = "0" + ret; + + return ret + "ms"; + } + + /** + * Gets the string time. + * + * @param string the string + * + * @return the string time + */ + public static long getStringTime(String string) { + try { + /* Ignore the "ms" postfix */ + Long longValue = Long.valueOf( + string.substring(0, string.length()-2)); + return longValue.longValue(); + } catch (NumberFormatException e) { + } + + return 0; + } + + /** + * Gets the integer vector represented by a comma separated string. + * + * @param string the string + * + * @return the parsed vector + */ + public static Vector<Integer> parseIntegerVector(String string) + throws exceptions.VSParseIntegerVectorException { + Vector<Integer> vec = new Vector<Integer>(); + + int index = string.indexOf('['); + if (index == -1) + throw new exceptions.VSParseIntegerVectorException(); + + string = string.substring(index+1); + + index = string.indexOf(']'); + if (index == -1) + throw new exceptions.VSParseIntegerVectorException(); + + string = string.substring(0, index); + + try { + while ( (index = string.indexOf(',')) != -1 ) { + String substring = string.substring(0, index); + + /* Remove leading whitespaces */ + while (substring.charAt(0) == ' ') + substring = substring.substring(1); + + vec.add(Integer.parseInt(substring)); + string = string.substring(index+1); + } + + /* Remove leading whitespaces */ + while (string.charAt(0) == ' ') + string = string.substring(1); + vec.add(Integer.parseInt(string)); + + } catch (StringIndexOutOfBoundsException e) { + } catch (NumberFormatException e) { + } + return vec; + } +} diff --git a/src/main/resources/logback.xml b/src/main/resources/logback.xml new file mode 100644 index 0000000..fc9bd19 --- /dev/null +++ b/src/main/resources/logback.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<configuration> + <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender"> + <encoder> + <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern> + </encoder> + </appender> + + <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> + <file>logs/ds-sim.log</file> + <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> + <fileNamePattern>logs/ds-sim.%d{yyyy-MM-dd}.log</fileNamePattern> + <maxHistory>30</maxHistory> + </rollingPolicy> + <encoder> + <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern> + </encoder> + </appender> + + <root level="INFO"> + <appender-ref ref="CONSOLE" /> + <appender-ref ref="FILE" /> + </root> +</configuration>
\ No newline at end of file |
