summaryrefslogtreecommitdiff
path: root/src/main
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2025-06-06 08:02:52 +0300
committerPaul Buetow <paul@buetow.org>2025-06-06 08:02:52 +0300
commit1d99762c7965d351510cfb5e08eac25e48d96038 (patch)
treef469493e911878ab9055ccf0494211bf9015922d /src/main
parent4d35597bd92607c4d194686e20b125044506c79a (diff)
Modernize project structure, update Maven config, move sources, add logging config, update README and .gitignore
Diffstat (limited to 'src/main')
-rw-r--r--src/main/java/core/VSAbstractProcess.java738
-rw-r--r--src/main/java/core/VSInternalProcess.java435
-rw-r--r--src/main/java/core/VSMessage.java182
-rw-r--r--src/main/java/core/VSMessageStub.java30
-rw-r--r--src/main/java/core/VSTask.java503
-rw-r--r--src/main/java/core/VSTaskManager.java562
-rw-r--r--src/main/java/core/time/VSLamportTime.java50
-rw-r--r--src/main/java/core/time/VSTime.java22
-rw-r--r--src/main/java/core/time/VSVectorTime.java96
-rw-r--r--src/main/java/events/VSAbstractEvent.java243
-rw-r--r--src/main/java/events/VSCopyableEvent.java16
-rw-r--r--src/main/java/events/VSRegisteredEvents.java346
-rw-r--r--src/main/java/events/implementations/VSProcessCrashEvent.java43
-rw-r--r--src/main/java/events/implementations/VSProcessRecoverEvent.java44
-rw-r--r--src/main/java/events/internal/VSAbstractInternalEvent.java58
-rw-r--r--src/main/java/events/internal/VSMessageReceiveEvent.java84
-rw-r--r--src/main/java/events/internal/VSProtocolEvent.java175
-rw-r--r--src/main/java/events/internal/VSProtocolScheduleEvent.java126
-rw-r--r--src/main/java/exceptions/VSEventNotCopyableException.java16
-rw-r--r--src/main/java/exceptions/VSNegativeNumberException.java12
-rw-r--r--src/main/java/exceptions/VSParseIntegerVectorException.java13
-rw-r--r--src/main/java/prefs/VSDefaultPrefs.java275
-rw-r--r--src/main/java/prefs/VSPrefs.java1163
-rw-r--r--src/main/java/prefs/VSPrefsRestriction.java137
-rw-r--r--src/main/java/prefs/VSSerializablePrefs.java37
-rw-r--r--src/main/java/prefs/editors/VSAbstractBetterEditor.java101
-rw-r--r--src/main/java/prefs/editors/VSAbstractEditor.java1056
-rw-r--r--src/main/java/prefs/editors/VSColorChooser.java61
-rw-r--r--src/main/java/prefs/editors/VSEditorFrame.java98
-rw-r--r--src/main/java/prefs/editors/VSEditorTable.java290
-rw-r--r--src/main/java/prefs/editors/VSProcessEditor.java107
-rw-r--r--src/main/java/prefs/editors/VSSimulatorEditor.java120
-rw-r--r--src/main/java/protocols/VSAbstractProtocol.java450
-rw-r--r--src/main/java/protocols/implementations/README10
-rw-r--r--src/main/java/protocols/implementations/VSBasicMulticastProtocol.java86
-rw-r--r--src/main/java/protocols/implementations/VSBerkelyTimeProtocol.java204
-rw-r--r--src/main/java/protocols/implementations/VSBroadcastProtocol.java103
-rw-r--r--src/main/java/protocols/implementations/VSDummyProtocol.java100
-rw-r--r--src/main/java/protocols/implementations/VSExternalTimeSyncProtocol.java118
-rw-r--r--src/main/java/protocols/implementations/VSInternalTimeSyncProtocol.java123
-rw-r--r--src/main/java/protocols/implementations/VSOnePhaseCommitProtocol.java148
-rw-r--r--src/main/java/protocols/implementations/VSPingPongProtocol.java110
-rw-r--r--src/main/java/protocols/implementations/VSReliableMulticastProtocol.java143
-rw-r--r--src/main/java/protocols/implementations/VSTwoPhaseCommitProtocol.java196
-rw-r--r--src/main/java/serialize/VSNotSerializable.java11
-rw-r--r--src/main/java/serialize/VSSerializable.java34
-rw-r--r--src/main/java/serialize/VSSerialize.java278
-rw-r--r--src/main/java/simulator/VSCreateTask.java179
-rw-r--r--src/main/java/simulator/VSLogging.java201
-rw-r--r--src/main/java/simulator/VSMain.java70
-rw-r--r--src/main/java/simulator/VSMenuItemStates.java109
-rw-r--r--src/main/java/simulator/VSSimulator.java1536
-rw-r--r--src/main/java/simulator/VSSimulatorFrame.java628
-rw-r--r--src/main/java/simulator/VSSimulatorVisualization.java1814
-rw-r--r--src/main/java/utils/VS3Tupel.java58
-rw-r--r--src/main/java/utils/VSAboutFrame.java87
-rw-r--r--src/main/java/utils/VSClassLoader.java29
-rw-r--r--src/main/java/utils/VSFrame.java118
-rw-r--r--src/main/java/utils/VSInfoArea.java49
-rw-r--r--src/main/java/utils/VSPriorityQueue.java32
-rw-r--r--src/main/java/utils/VSRandom.java37
-rw-r--r--src/main/java/utils/VSTools.java92
-rw-r--r--src/main/resources/logback.xml24
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