summaryrefslogtreecommitdiff
path: root/sources/simulator/VSSimulationPanel.java
diff options
context:
space:
mode:
Diffstat (limited to 'sources/simulator/VSSimulationPanel.java')
-rw-r--r--sources/simulator/VSSimulationPanel.java619
1 files changed, 619 insertions, 0 deletions
diff --git a/sources/simulator/VSSimulationPanel.java b/sources/simulator/VSSimulationPanel.java
new file mode 100644
index 0000000..f0d3d75
--- /dev/null
+++ b/sources/simulator/VSSimulationPanel.java
@@ -0,0 +1,619 @@
+package simulator;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.awt.geom.*;
+import java.util.*;
+import javax.swing.*;
+
+import core.*;
+import editors.*;
+import prefs.*;
+import utils.*;
+import events.*;
+
+public class VSSimulationPanel extends JPanel implements Runnable, MouseMotionListener, MouseListener, HierarchyBoundsListener {
+ private VSProcess highlightedProcess;
+ private VSSimulation simulation;
+ private VSPrefs prefs;
+ private VSLogging logging;
+ private int numProcesses;
+ private int secondsSpaceing;
+ private int threadSleep;
+ private long untilTime;
+ private volatile boolean isPaused = false;
+ private volatile boolean isFinalized = false;
+ private volatile boolean isFinished = false;
+ private volatile boolean isResetted = false;
+ private volatile boolean showLamport = false;
+ private volatile long pauseTime;
+ private volatile long startTime;
+ private volatile long time;
+ private volatile long lastTime;
+ private VSTaskManager taskManager;
+ private LinkedList<VSMessageLine> messageLines;
+ private LinkedList<VSProcess> processes;
+
+ /* Static constats */
+ private static final int LINE_WIDTH = 5;
+ private static final int SEPLINE_WIDTH = 2;
+ private static final int XOFFSET = 50;
+ private static final int YOFFSET = 30;
+ private static final int YOUTER_SPACEING = 10;
+ private static final int YSEPLINE_SPACEING = 20;
+ private static final int TEXT_SPACEING = 10;
+
+ /* Constats, which have to get calculated once after start */
+ private Color processlineColor;
+ private Color processSecondlineColor;
+ private Color processSeplineColor;
+ private Color messageArrivedColor;
+ private Color messageSendingColor;
+ private Color messageLostColor;
+
+ private class VSMessageLine {
+ private VSProcess receiverProcess;
+ private Color color;
+ private long sendTime;
+ private long recvTime;
+ private int senderNum;
+ private int receiverNum;
+ private int offset1;
+ private int offset2;
+ private boolean isArrived;
+ private boolean isLost;
+ private double x1;
+ private double y1;
+ private double x2;
+ private double y2;
+ private double x;
+ private double y;
+ private long outageTime;
+ private long z;
+
+ public VSMessageLine(VSProcess receiverProcess, long sendTime, long recvTime, long outageTime, int senderNum , int receiverNum) {
+ this.receiverProcess = receiverProcess;
+ this.sendTime = sendTime;
+ this.recvTime = recvTime;
+ this.outageTime = outageTime;
+ this.senderNum = senderNum;
+ this.receiverNum = receiverNum;
+ this.isArrived = false;
+ this.isLost = false;
+
+ 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) + offset1;
+
+ recalcOnWindowChanged();
+ }
+
+ public void recalcOnWindowChanged() {
+ x1 = getTimeXPosition(sendTime);
+ y1 = getProcessYPosition(senderNum) + offset1;
+ x2 = getTimeXPosition(recvTime);
+ y2 = getProcessYPosition(receiverNum) + offset2;
+
+ if (isLost) {
+ x = getTimeXPosition(z);
+ y = y1 + ( ( (y2-y1) / (x2-x1)) * (x-x1));
+ }
+ }
+
+ 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) {
+ isArrived = true;
+ if (receiverProcess.isCrashed())
+ color = messageLostColor;
+ else
+ color = messageArrivedColor;
+ draw(g, globalTime);
+
+ } else if (outageTime >= 0 && outageTime <= globalTime){
+ 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);
+ }
+ }
+ }
+
+ public VSSimulationPanel(VSPrefs prefs, VSSimulation simulation, VSLogging logging) {
+ this.prefs = prefs;
+ this.simulation = simulation;
+ this.logging = logging;
+ this.taskManager = new VSTaskManager(prefs);
+ this.messageLines = new LinkedList<VSMessageLine>();
+ this.processes = new LinkedList<VSProcess>();
+
+ numProcesses = prefs.getInteger("sim.process.num");
+ untilTime = prefs.getInteger("sim.seconds") * 1000;
+ recalcOnWindowChanged();
+
+ secondsSpaceing = (int) untilTime / 15000;
+ if (secondsSpaceing == 0)
+ secondsSpaceing = 1;
+
+ threadSleep = (int) untilTime / 7500;
+ if (threadSleep == 0)
+ threadSleep = 1;
+
+ VSProcess.resetProcessCounter();
+ for (int i = 0; i < numProcesses; ++i)
+ createProcess(i);
+
+ addMouseListener(this);
+ addMouseMotionListener(this);
+ addHierarchyBoundsListener(this);
+ }
+
+ double xPaintSize;
+ double paintSize;
+ double yDistance;
+ double globalTimeXPosition;
+
+ int xoffset_plus_xpaintsize;
+ double xpaintsize_dividedby_untiltime;
+ int paintProcessesOffset;
+
+ int paintSecondlinesSeconds;
+ int paintSecondlinesLine[] = new int[4];
+ int paintSecondlinesYStringPos1;
+ int paintSecondlinesYStringPos2;
+ int paintGlobalTimeYPosition;
+
+ /* This method contains very ugly code. But this has to be in order to gain performance! */
+ private void recalcOnWindowChanged() {
+ processlineColor = prefs.getColor("process.line");
+ processSecondlineColor = prefs.getColor("process.secondline");
+ processSeplineColor = prefs.getColor("process.sepline");
+ messageArrivedColor = prefs.getColor("message.arrived");
+ messageSendingColor = prefs.getColor("message.sending");
+ messageLostColor = prefs.getColor("message.lost");
+
+ paintSize = simulation.getPaintSize();
+ xPaintSize = simulation.getWidth() - (3 * XOFFSET + simulation.getSplitSize());
+ yDistance = (simulation.getPaintSize() - 2 * (YOFFSET + YOUTER_SPACEING))/ numProcesses;
+ xpaintsize_dividedby_untiltime = xPaintSize / (double) untilTime;
+
+ for (VSMessageLine messageLine : messageLines)
+ messageLine.recalcOnWindowChanged();
+
+ /* 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);
+ }
+ }
+
+ public VSProcess createProcess(int i) {
+ VSProcess process = new VSProcess(prefs, this, logging, i+1);
+ processes.add(process);
+ logging.logg(prefs.getString("lang.process.new") + "; " + process);
+
+ return process;
+ }
+
+ private void updateSimulation(final long globalTime, final long lastGlobalTime) {
+ final long offset = globalTime - lastGlobalTime;
+ for (long l = 0; l < offset; ++l)
+ taskManager.runVSTasks(l, offset, lastGlobalTime);
+
+ for (VSProcess process : processes)
+ process.syncTime(globalTime);
+ }
+
+ public void paintComponent(Graphics g) {
+ super.paintComponent(g);
+
+ final long globalTime = time;
+ final Graphics2D g2d = (Graphics2D) g;
+
+ globalTimeXPosition = getTimeXPosition(globalTime);
+
+ paintSecondlines(g2d);
+ paintProcesses(g2d, globalTime);
+ paintGlobalTime(g2d, globalTime);
+
+ synchronized (messageLines) {
+ for (VSMessageLine line : messageLines)
+ line.draw(g2d, globalTime);
+ }
+
+ }
+
+ 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 };
+
+ for (VSProcess process : processes) {
+ final long localTime = process.getTime();
+
+ g.setColor(process.getColor());
+ g.fillPolygon(xPoints, yPoints, 5);
+ if (process.isCrashed()) {
+ final VSTask crashTask = process.getCrashTask();
+ final int crashPos = (int) getTimeXPosition(crashTask.getTaskTime());
+ final int xPointsCrashed[] = { crashPos, xoffset_plus_xpaintsize, xoffset_plus_xpaintsize, crashPos, crashPos };
+ g.setColor(process.getCrashedColor());
+ g.fillPolygon(xPointsCrashed, yPoints, 5);
+ }
+
+ 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) {
+ int last = -1;
+ final int distance = 20;
+ final VSLamport[] lamportStamps = process.getLamportArray();
+ for (VSLamport lamport : lamportStamps) {
+ int xPos_ = (int) getTimeXPosition(lamport.getTime());
+ if (last >= 0) {
+ int diff = xPos_ - last;
+ if (diff < distance)
+ xPos_ += distance - diff;
+ }
+ g.drawString(""+lamport.getLamportTime(), xPos_ + 2, yStart + 3 * TEXT_SPACEING);
+ last = xPos_;
+ }
+ }
+
+ for (int i = 0; i < 5; ++i)
+ yPoints[i] += paintProcessesOffset;
+ }
+ }
+
+ 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);
+ 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]);
+ }
+ }
+
+ 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);
+ }
+
+ private VSProcess 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)
+ return processes.get(i);
+ y += yOffset;
+ }
+
+ return null;
+ }
+
+ private double getTimeXPosition(long time) {
+ return XOFFSET + xpaintsize_dividedby_untiltime * time;
+ }
+
+ 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;
+ }
+
+ public long getTime() {
+ return time;
+ }
+
+ public long getUntilTime() {
+ return untilTime;
+ }
+
+ public long getStartTime() {
+ return startTime;
+ }
+
+ public VSTaskManager getTaskManager() {
+ return taskManager;
+ }
+
+ public int getNumProcesses() {
+ return numProcesses;
+ }
+
+ public void run() {
+ play();
+
+ while (true) {
+ while (!isPaused && !isFinalized) {
+ try {
+ Thread.sleep(threadSleep);
+ } catch (Exception e) {
+ System.out.println(e);
+ }
+
+ updateSimulation(time, lastTime);
+ repaint();
+
+ lastTime = time;
+ time = System.currentTimeMillis() - startTime;
+
+ if (time > untilTime)
+ time = untilTime;
+
+ if (time == untilTime) {
+ finish();
+ break;
+ }
+ }
+
+ if (isPaused) {
+ for (VSProcess p : processes)
+ p.pause();
+
+ pauseTime = System.currentTimeMillis();
+
+ logging.logg(prefs.getString("lang.simulation.paused"));
+ repaint();
+ }
+
+ updateSimulation(time, lastTime);
+ repaint();
+
+ while (!isFinalized && (isPaused || isFinished || isResetted)) {
+ try {
+ Thread.sleep(100);
+ repaint();
+ } catch (Exception e) {
+ System.out.println(e);
+ }
+ }
+
+ if (isFinalized)
+ break; /* Exit the thread */
+ }
+ }
+
+ public void play() {
+ logging.logg(prefs.getString("lang.simulation.started"));
+ final long currentTime = System.currentTimeMillis();
+
+ for (VSProcess p : processes)
+ p.play();
+
+ if (isResetted)
+ isResetted = false;
+
+ else if (isFinished)
+ isFinished = false;
+
+ if (isPaused) {
+ isPaused = false;
+ startTime += currentTime - pauseTime;
+ time = currentTime - startTime;
+
+ } else {
+ startTime = currentTime;
+ time = 0;
+ }
+
+ repaint();
+ }
+
+ public void finish() {
+ for (VSProcess p : processes)
+ p.finish();
+
+ simulation.finish();
+ isFinished = true;
+
+ logging.logg(prefs.getString("lang.simulation.finished"));
+ repaint();
+ }
+
+ public void pause() {
+ isPaused = true;
+ }
+
+ public void reset() {
+ if (!isResetted) {
+ logging.logg(prefs.getString("lang.simulation.resetted"));
+
+ isResetted = true;
+ isPaused = false;
+ isFinished = false;
+ startTime = System.currentTimeMillis();
+ time = 0;
+ lastTime = 0;
+
+ taskManager.reset();
+
+ for (VSProcess p : processes)
+ p.reset();
+
+ synchronized (messageLines) {
+ messageLines.clear();
+ }
+ repaint();
+ }
+ }
+
+ public void finalize() {
+ isFinalized = true;
+ }
+
+ public boolean isFinalized() {
+ return isFinalized;
+ }
+
+ public void showLamport(boolean showLamport) {
+ this.showLamport = showLamport;
+ repaint();
+ }
+
+ public void sendMessage(VSMessage message) {
+ VSTask task = null;
+ VSProcess sendingProcess = message.getSendingProcess();
+ long deliverTime, outageTime, durationTime;
+
+ for (VSProcess receiverProcess : processes) {
+ if (receiverProcess.equals(sendingProcess)) {
+ deliverTime = sendingProcess.getGlobalTime();
+ task = new VSTask(deliverTime, receiverProcess, message);
+ taskManager.addTask(task);
+
+ } else {
+ durationTime = sendingProcess.getDurationTime();
+ deliverTime = sendingProcess.getGlobalTime() + durationTime;
+ outageTime = sendingProcess.getARandomMessageOutageTime(durationTime);
+
+ /* Only add a 'receiving message' task if the message will not get lost! */
+ if (outageTime == -1) {
+ task = new VSTask(deliverTime, receiverProcess, message);
+ taskManager.addTask(task);
+ }
+
+ synchronized (messageLines) {
+ messageLines.add(new VSMessageLine(receiverProcess,
+ sendingProcess.getGlobalTime(), deliverTime, outageTime,
+ sendingProcess.getNum(), receiverProcess.getNum()));
+ }
+ }
+ }
+ }
+
+ public void mouseClicked(MouseEvent e) {
+ VSProcess process = getProcessAtYPos(e.getY());
+ if (process != null) {
+ process.updatePrefs();
+ new VSProcessEditor(prefs, simulation, process);
+ }
+ }
+
+ public void mouseEntered(MouseEvent e) { }
+
+ public void mouseExited(MouseEvent e) {
+ if (highlightedProcess != null) {
+ highlightedProcess.highlightOff();
+ highlightedProcess = null;
+ repaint();
+ }
+ }
+
+ public void mousePressed(MouseEvent e) { }
+
+ public void mouseReleased(MouseEvent e) { }
+
+ public void mouseDragged(MouseEvent e) { }
+
+ public void mouseMoved(MouseEvent e) {
+ VSProcess p = getProcessAtYPos(e.getY());
+
+ if (p == null) {
+ if (highlightedProcess != null) {
+ highlightedProcess.highlightOff();
+ highlightedProcess = null;
+ repaint();
+ }
+
+ return;
+ }
+
+ if (highlightedProcess != null) {
+ if (highlightedProcess.getProcessID() != p.getProcessID()) {
+ highlightedProcess.highlightOff();
+ highlightedProcess = p;
+ p.highlightOn();
+ repaint();
+ }
+ } else {
+ highlightedProcess = p;
+ p.highlightOn();
+ repaint();
+ }
+ }
+
+ public void ancestorMoved(HierarchyEvent e) { }
+
+ public void ancestorResized(HierarchyEvent e) {
+ recalcOnWindowChanged();
+ }
+}