diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..c8dd1e2
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,6 @@
+/target
+/dist
+.classpath
+.project
+my file.lsa
+.settings
diff --git a/Jenkinsfile b/Jenkinsfile
new file mode 100644
index 0000000..88908bd
--- /dev/null
+++ b/Jenkinsfile
@@ -0,0 +1,186 @@
+#!groovy
+
+// Required Jenkins plugins:
+// https://wiki.jenkins-ci.org/display/JENKINS/Timestamper
+// https://wiki.jenkins-ci.org/display/JENKINS/Static+Code+Analysis+Plug-ins
+// https://wiki.jenkins-ci.org/display/JENKINS/Checkstyle+Plugin ?
+// https://wiki.jenkins-ci.org/display/JENKINS/FindBugs+Plugin
+// https://wiki.jenkins-ci.org/display/JENKINS/PMD+Plugin ?
+// https://wiki.jenkins-ci.org/display/JENKINS/DRY+Plugin ?
+// https://wiki.jenkins-ci.org/display/JENKINS/Task+Scanner+Plugin
+// https://wiki.jenkins-ci.org/display/JENKINS/Javadoc+Plugin
+// https://wiki.jenkins-ci.org/display/JENKINS/JaCoCo+Plugin ?
+
+
+init()
+
+def branch_name
+def branch_name_base
+def build_number
+def build_url
+def git_commit
+def job_name
+def tag
+def version
+def build_type
+def display_name
+
+def init() {
+
+ // Keep the 5 most recent builds
+ properties([[$class: 'BuildDiscarderProperty', strategy: [$class: 'LogRotator', numToKeepStr: '5']]])
+
+ build_number = env.BUILD_NUMBER
+ build_url = env.BUILD_URL
+ job_name = "${env.JOB_NAME}"
+ branch_name = env.BRANCH_NAME
+ branch_name_docker = branch_name.replaceAll(/\//,'.')
+ persist = "/var/lib/jenkins/PERSIST/${branch_name_docker}"
+
+ // execute the branch type specific pipeline code
+ try {
+
+ if (branch_name.indexOf('release/')==0) build_type='release'
+ if (branch_name.indexOf('feature/')==0) build_type='feature'
+ if (branch_name.indexOf('develop')==0) build_type='develop'
+ if (branch_name.indexOf('hotfix')==0) build_type='hotfix'
+ if (branch_name.indexOf('bugfix')==0) build_type='bugfix'
+ if (branch_name.indexOf('master')==0) build_type='master'
+
+ // common pipeline elements
+ node('master') {
+ Initialize()
+ SetVersion(build_type)
+ print_vars() // after SetVersion - all variables now defined
+ set_result('INPROGRESS')
+ Build() // builds database via flyway migration
+ }
+
+ if (branch_name.indexOf('develop')==0) {
+ node('master') {
+ Deploy();
+ }
+ } else if (branch_name.indexOf('release/')==0) {
+ node('master') {
+ Deploy();
+ }
+ }
+
+ node('master') {
+ set_result('SUCCESS')
+ }
+
+ } catch (err) {
+ node() {
+ set_result('FAILURE')
+ }
+ throw err
+ }
+}
+
+def Build() {
+ stage ('build') {
+ mvn "install -DskipTests=true -Dbuild.revision=${git_commit}"
+ step([$class: 'ArtifactArchiver', artifacts: '**/target/*.jar', fingerprint: true])
+ }
+}
+
+def Initialize() {
+ stage ('initialize') {
+
+ // get new code
+ checkout scm
+
+ git_commit = getSha1()
+ }
+}
+
+def Deploy() {
+ stage ('deploy') {
+ mvn "deploy -DskipTests=true -Dbuild.number=${build_number} -Dbuild.revision=${git_commit}"
+ }
+}
+
+def getSha1() {
+ sha1 = sh(script: 'git rev-parse HEAD', returnStdout: true).trim()
+ echo "sha1 is ${sha1}"
+ return sha1
+}
+
+def mvn(args) {
+ withMaven(
+ maven: 'maven-3.6.1',
+ globalMavenSettingsConfig: 'locusworks-settings'
+ ) {
+
+ sh "mvn ${args}"
+
+ }
+}
+
+def mvn_initial(args) {
+ mvn(args)
+}
+
+def set_result(status) {
+ if ( status == 'SUCCESS' ) {
+ currentBuild.result = status
+ notify_bitbucket('SUCCESSFUL')
+ } else if ( status == 'FAILURE' ) {
+ currentBuild.result = status
+ notify_bitbucket('FAILED')
+ } else if ( status == 'INPROGRESS' ) {
+ notify_bitbucket('INPROGRESS')
+ } else {
+ error ("unknown status")
+ }
+
+ // save in persistence file for access the status page
+ // make sure the directory exists first
+ sh "mkdir -p $persist && echo $status > $persist/build.result"
+}
+
+def notify_bitbucket(state) {
+}
+
+def print_vars() {
+ echo "build_number = ${build_number}"
+ echo "build_url = ${build_url}"
+ echo "job_name = ${job_name}"
+ echo "branch_name = ${branch_name}"
+ echo "branch_name_base = ${branch_name_base}"
+ echo "build_type = ${build_type}"
+ echo "display_name = ${currentBuild.displayName}"
+ echo "version = ${version}"
+ echo "git_commit = ${git_commit}"
+
+}
+
+def SetVersion( v ) {
+ stage ('set version') {
+ echo "set version ${v}"
+ branch_name_base = (branch_name =~ /([^\/]+$)/)[0][0]
+ if ( v == 'release' ) {
+ // for release branches, where the branch is named "release/1.2.3",
+ // derive the version and display name derive from the numeric suffix and append the build number
+ // 3.2.1.100
+ version = branch_name_base + "." + build_number + "-RELEASE";
+ //version = branch_name.substring('release/'.length()) + "." + build_number
+ currentBuild.displayName = version
+ } else if (v == 'develop') {
+ version = branch_name_base + "." + build_number + "-SNAPSHOT";
+ currentBuild.displayName = version
+ } else {
+ // for all other branches the version number is 0 with an appended build number
+ // and for the display name use the jenkins default #n and add the branch name
+ // #101 - feature/user/foo
+ //version = '0.' + build_number
+ version = branch_name_base + "." + build_number
+ currentBuild.displayName = "#" + build_number + " - " + branch_name_base
+ }
+ display_name = currentBuild.displayName
+ mvn_initial "versions:set -DnewVersion=${version}"
+ }
+}
+
+return this
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..2696897
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,39 @@
+
+ 4.0.0
+ net.locusworks
+ lsproject
+ 0.0.1-SNAPSHOT
+ Link State Project
+ Demonstrates Dijkstra's algorithm
+
+
+ 1.8
+ 1.8
+
+
+
+
+
+ maven-compiler-plugin
+
+ 1.8
+ 1.8
+
+
+
+
+
+
+
+
+ junit
+ junit
+ 4.13.2
+ test
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/java/net/locusworks/lsproject/driver/Program.java b/src/main/java/net/locusworks/lsproject/driver/Program.java
new file mode 100644
index 0000000..384d40f
--- /dev/null
+++ b/src/main/java/net/locusworks/lsproject/driver/Program.java
@@ -0,0 +1,56 @@
+package net.locusworks.lsproject.driver;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintStream;
+
+import net.locusworks.lsproject.gui.DebugConsole;
+import net.locusworks.lsproject.gui.StartupWindow;
+
+/**
+ * Contains the main (start-up) function.
+ */
+public class Program {
+ private static DebugConsole console;
+
+ /**
+ * Entry point of the program.
+ */
+ public static void main(String[] args) {
+ console = new DebugConsole();
+
+ setupStreams();
+
+ new StartupWindow();
+ }
+
+ /**
+ * Set the typical output streams to a window. This means that output sent through System.out
+ * and System.err are sent instead to a designated console window.
+ */
+ public static void setupStreams() {
+ PrintStream errorStream = new PrintStream(new OutputStream() {
+ @Override
+ public void write(int c) throws IOException {
+ write(new byte[] { Byte.parseByte(Integer.toString(c)) });
+ }
+
+ public void write(byte[] b) {
+ console.writeError(new String(b));
+ }
+ });
+
+ PrintStream outputStream = new PrintStream(new OutputStream() {
+ @Override
+ public void write(int c) throws IOException {
+ write(new byte[] { Byte.parseByte(Integer.toString(c)) });
+ }
+
+ public void write(byte[] b) {
+ console.writeString(new String(b));;
+ }
+ });
+
+ //System.setErr(errorStream);
+ System.setOut(outputStream);
+ }
+}
diff --git a/src/main/java/net/locusworks/lsproject/gui/CostViewerWindow.java b/src/main/java/net/locusworks/lsproject/gui/CostViewerWindow.java
new file mode 100644
index 0000000..aa4bcca
--- /dev/null
+++ b/src/main/java/net/locusworks/lsproject/gui/CostViewerWindow.java
@@ -0,0 +1,118 @@
+package net.locusworks.lsproject.gui;
+
+import java.awt.BorderLayout;
+import java.awt.Dimension;
+import java.awt.GridLayout;
+
+import javax.swing.JFrame;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTable;
+import javax.swing.event.TableModelEvent;
+import javax.swing.event.TableModelListener;
+import javax.swing.table.TableModel;
+
+import net.locusworks.lsproject.driver.Program;
+import net.locusworks.lsproject.object.Network;
+import net.locusworks.lsproject.object.Router;
+
+
+public class CostViewerWindow extends JPanel implements TableModelListener{
+ /**
+ *
+ */
+ private static final long serialVersionUID = 8571350255455457432L;
+ private boolean DEBUG = false;
+ private Router router = null;
+
+
+ public CostViewerWindow(Router _router){
+ super(new BorderLayout());
+
+ router = _router;
+
+ String[] columnNames = {"Connection",
+ "Cost"};
+
+ int numberOfConnections = router.getConnections().size();
+
+ Object data[][]= new Object[numberOfConnections][2];
+
+ for (int i = 0; i < numberOfConnections; i++){
+
+ String tempFirstParticipant = router.getConnections()
+ .get(i).getFirstParticipantAddress();
+
+ String tempSecondParticipant = router.getConnections()
+ .get(i).getSecondParticipantAddress();
+
+ if(tempFirstParticipant.equals(router.getIpAddress())){
+ data[i][0] = tempSecondParticipant;
+ }
+ else{
+ data[i][0] = tempFirstParticipant;
+ }
+ data[i][1] = router.getConnections().get(i).getCost();
+ }
+
+ final JTable table = new JTable(data, columnNames);
+ table.setPreferredScrollableViewportSize(new Dimension(300, 70));
+ table.setFillsViewportHeight(true);
+ table.getModel().addTableModelListener(this);
+
+ JScrollPane scrollPane = new JScrollPane(table);
+ add(scrollPane);
+
+ }
+
+ public void createGUI(){
+
+ JFrame frame = new JFrame("Cost Viewer For Router " + router.getIpAddress());
+ CostViewerWindow newContentPane = new CostViewerWindow(router);
+ newContentPane.setOpaque(true);
+ frame.setContentPane(newContentPane);
+ frame.pack();
+ frame.setLocationRelativeTo(null);
+ frame.setVisible(true);
+ }
+
+ @Override
+ public void tableChanged(TableModelEvent e) {
+ if (e.getColumn() == 0) {
+ return;
+ }
+
+ int row = e.getFirstRow();
+ int column = e.getColumn();
+ TableModel model = (TableModel)e.getSource();
+ Object data = model.getValueAt(row, column);
+
+ final String otherRouterIp = model.getValueAt(row, 0).toString();
+
+ final int oldCost = router.getConnectionByParticipant(router.getIpAddress(), otherRouterIp).getCost();
+ int newCost = oldCost;
+ try {
+ newCost = Integer.parseInt(data.toString());
+
+ if (newCost < 1 || newCost > 10){
+ System.out.println("Cost Has To Be Between 0 - 10");
+
+ newCost = oldCost;
+
+ return;
+ }
+
+ router.getConnectionByParticipant(
+ router.getIpAddress(), otherRouterIp).setCost(newCost);
+ Router otherRouter = Network.getInstance().getRouterByIp(otherRouterIp);
+ otherRouter.getConnectionByParticipant(
+ router.getIpAddress(), otherRouterIp).setCost(newCost);
+ }
+ catch (NumberFormatException ex) {
+ System.out.println("Invalid cost.");
+ }
+ }
+
+}
+
+
diff --git a/src/main/java/net/locusworks/lsproject/gui/DebugConsole.java b/src/main/java/net/locusworks/lsproject/gui/DebugConsole.java
new file mode 100644
index 0000000..10f2e6e
--- /dev/null
+++ b/src/main/java/net/locusworks/lsproject/gui/DebugConsole.java
@@ -0,0 +1,53 @@
+package net.locusworks.lsproject.gui;
+
+import javax.swing.JFrame;
+import javax.swing.JScrollPane;
+import javax.swing.JTextArea;
+
+import net.locusworks.lsproject.gui.helper.ImageHelper;
+
+/**
+ * The DebugConsole displays normal debug messages from stdout.
+ */
+public class DebugConsole extends JFrame {
+ private static final long serialVersionUID = -4430646440883436819L;
+ private JTextArea textArea;
+
+ public DebugConsole() {
+ super("Debug Console");
+
+ textArea = new JTextArea();
+ setSize(400, 300);
+ textArea.setSize(400, 300);
+ textArea.setEditable(false);
+ textArea.setLineWrap(true);
+
+ JScrollPane pane = new JScrollPane(textArea);
+ pane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
+ pane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
+
+ setIconImage(ImageHelper.getImageFromResource("assets/router_ico.png"));
+
+ add(pane);
+
+ setVisible(true);
+ }
+
+ /**
+ * Write a normal string to the console.
+ * @param s String to write.
+ */
+ public void writeString(String s) {
+ textArea.append(s);
+ textArea.setCaretPosition(textArea.getText().length());
+ }
+
+ /**
+ * Write an error string to the console.
+ * @param s String to write.
+ */
+ public void writeError(String s) {
+ textArea.append(s);
+ textArea.setCaretPosition(textArea.getText().length());
+ }
+}
diff --git a/src/main/java/net/locusworks/lsproject/gui/RouterViewerWindow.java b/src/main/java/net/locusworks/lsproject/gui/RouterViewerWindow.java
new file mode 100644
index 0000000..b8be99e
--- /dev/null
+++ b/src/main/java/net/locusworks/lsproject/gui/RouterViewerWindow.java
@@ -0,0 +1,411 @@
+package net.locusworks.lsproject.gui;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.io.IOException;
+import java.util.Hashtable;
+import java.util.Random;
+import javax.swing.*;
+
+import net.locusworks.lsproject.gui.helper.ImageHelper;
+import net.locusworks.lsproject.gui.helper.RouterPath;
+import net.locusworks.lsproject.object.Connection;
+import net.locusworks.lsproject.object.Router;
+import net.locusworks.lsproject.object.Network;
+import net.locusworks.lsproject.util.Utility;
+
+
+/**
+ * Display a network.
+ */
+public class RouterViewerWindow extends JFrame implements MouseListener,
+ MouseMotionListener,
+ KeyListener {
+ // Makes compiler happy.
+ private static final long serialVersionUID = 5141131466102432149L;
+
+ private JPanel surface;
+ private Image routerImage;
+ private int imageWidth;
+ private int imageHeight;
+
+ private String highlightedRouter;
+
+ private Image offscreenImage;
+ private Graphics buffer;
+
+ private boolean[] keys;
+
+ private Hashtable routingTables = new Hashtable();
+
+ // This is a hack for a weird java-related bug where it does not draw pictures on the first paint.
+ private boolean firstPaint = true;
+
+ /**
+ * Construct a new RouterViewerWindow object.
+ */
+ public RouterViewerWindow() {
+ super("Network Viewer - " + Network.getInstance().getName());
+
+ initialize();
+ }
+
+ /**
+ * Initialize the GUI components of this class.
+ */
+ private void initialize() {
+ routerImage = ImageHelper.getImageFromResource("assets/router.png");
+ imageWidth = 129;
+ imageHeight = 71;
+
+ setIconImage(ImageHelper.getImageFromResource("assets/router_ico.png"));
+
+ surface = new JPanel(true);
+ surface.setSize(800, 600);
+ surface.setBackground(Color.GRAY);
+
+ setContentPane(surface);
+
+ addMouseListener(this);
+ addMouseMotionListener(this);
+ addKeyListener(this);
+
+ setSize(800, 600);
+
+ setResizable(false);
+ setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ setLocationRelativeTo(null);
+ setVisible(true);
+
+ // Track key states. Initialize all to false (not pressed).
+ keys = new boolean[525];
+ for (int i = 0; i < keys.length; i++) {
+ keys[i] = false;
+ }
+
+ // Create the buffer.
+ offscreenImage = surface.createImage(getWidth(), getHeight());
+ buffer = offscreenImage.getGraphics();
+
+ // Repaint the window every once in a while.
+ new Thread() {
+ public void run() {
+ while (isVisible()) {
+ try {
+ Thread.sleep(500);
+ }
+ catch (InterruptedException e) {
+ e.printStackTrace();
+ return;
+ }
+
+ repaint();
+ }
+ }
+ }.start();
+ }
+
+ /**
+ * Paint the routers to the screen.
+ */
+ @Override
+ public void paint(Graphics g) {
+ buffer.setColor(Color.GRAY);
+ buffer.fillRect(0, 0, getWidth(), getHeight());
+
+ buffer.setColor(Color.BLACK);
+
+ // Draw connections.
+ for (Router r : Network.getInstance().getRouters()) {
+ for (Connection connection : r.getConnections()) {
+ Router r1 = Network.getInstance().getRouterByIp(connection.getFirstParticipantAddress());
+ Router r2 = Network.getInstance().getRouterByIp(connection.getSecondParticipantAddress());
+
+ buffer.drawLine(r1.getPosition().x, r1.getPosition().y,
+ r2.getPosition().x, r2.getPosition().y);
+
+ buffer.drawString(Integer.toString(connection.getCost()),
+ (r1.getPosition().x + r2.getPosition().x) / 2,
+ (r1.getPosition().y + r2.getPosition().y - 10) / 2);
+ }
+ }
+
+ for (Router r : Network.getInstance().getRouters()) {
+ Point position = r.getPosition();
+
+ buffer.setColor(Color.BLACK);
+
+ // Draw router IP addresses.
+ buffer.drawString(r.getIpAddress(), position.x - (imageWidth / 2) + 5,
+ position.y - (imageHeight / 2) - 10);
+
+ buffer.drawImage(routerImage, position.x - (imageWidth / 2),
+ position.y - (imageHeight / 2), imageWidth, imageHeight, null);
+
+ // Highlight a different color if shift is pressed down.
+ if (keys[KeyEvent.VK_SHIFT]) {
+ buffer.setColor(Color.RED);
+ }
+
+ if (highlightedRouter != null && !highlightedRouter.equals("")) {
+ if (r.getIpAddress().equals(highlightedRouter)) {
+ buffer.drawRect(position.x - (imageWidth / 2), position.y - (imageHeight / 2),
+ imageWidth, imageHeight);
+ }
+ }
+ }
+
+ illuminatePath(buffer);
+
+ // Draw the buffer image to the screen.
+ g.drawImage(offscreenImage, 0, 0, getWidth(), getHeight(), Color.GRAY, null);
+
+ // Hack to attempt to get the first image to draw.
+ if (firstPaint) {
+ firstPaint = false;
+ repaint();
+ }
+ }
+
+ /**
+ * Highlight the path between a start and end router, if necessary.
+ * @param g Graphics device.
+ */
+ public void illuminatePath(Graphics g) {
+ // Draw highlighted router boxes.
+ if (RouterPath.firstRouter != null) {
+ final Point position = RouterPath.firstRouter.getPosition();
+ buffer.setColor(new Color(0, 255, 255));
+ buffer.drawRect(position.x - (imageWidth / 2), position.y - (imageHeight / 2),
+ imageWidth, imageHeight);
+ }
+
+ if (RouterPath.secondRouter != null) {
+ final Point position = RouterPath.secondRouter.getPosition();
+ buffer.setColor(new Color(0, 255, 255));
+ buffer.drawRect(position.x - (imageWidth / 2), position.y - (imageHeight / 2),
+ imageWidth, imageHeight);
+ }
+
+ if (RouterPath.highlightedPath != null) {
+ Router lastRouter = RouterPath.firstRouter;
+ while (RouterPath.highlightedPath.hasNext()) {
+ final Router next = RouterPath.highlightedPath.getNext();
+
+ final Point start = lastRouter.getPosition();
+ final Point end = next.getPosition();
+ buffer.drawLine(start.x, start.y, end.x, end.y);
+
+ lastRouter = next;
+ }
+
+ RouterPath.highlightedPath.reset();
+ }
+ }
+
+ /**
+ * Overridden to prevent the frame from erasing the background.
+ */
+ @Override public void update(Graphics g) {
+ paint(g);
+ }
+
+ /**
+ * Spawn a new routing table window.
+ * @param r Router to display.
+ */
+ public void spawnRoutingTable(Router r) {
+ if (routingTables.contains(r.getIpAddress())) {
+ RoutingTableWindow window = routingTables.get(r.getIpAddress());
+ window.dispose();
+ routingTables.remove(r.getIpAddress());
+ }
+
+ routingTables.put(r.getIpAddress(), new RoutingTableWindow(r));
+ }
+
+ public void spawnCostViwerWindow(Router r){
+ CostViewerWindow window = new CostViewerWindow(r);
+ window.createGUI();
+ }
+
+ /**
+ * Force each router to perform the algorithm.
+ */
+ public void updateAllRouters() {
+ for (Router router : Network.getInstance().getRouters()) {
+ router.getRoutingTable().execute(router, null);
+ }
+ }
+
+ /*
+ * Event handlers.
+ */
+ /**
+ * Check if the mouse is over a router on the screen.
+ */
+ private Router mouseIsOverRouter(MouseEvent e) {
+ for (Router r : Network.getInstance().getRouters()) {
+ if (Math.abs(r.getPosition().x - e.getPoint().x) < imageWidth / 2 &&
+ Math.abs(r.getPosition().y - e.getPoint().y) < imageHeight / 2) {
+
+ return r;
+ }
+ }
+
+ return null;
+ }
+
+ @Override public void mouseClicked(MouseEvent e) {}
+ @Override public void mouseEntered(MouseEvent e) {}
+ @Override public void mouseExited(MouseEvent e) {}
+ @Override public void mouseReleased(MouseEvent e) {}
+
+ /**
+ * Check if the mouse was pressed down. This will highlight or unhighlight routers.
+ */
+ @Override public void mousePressed(MouseEvent e) {
+ // Collision detection.
+ Router r = null;
+ if ((r = mouseIsOverRouter(e)) != null) {
+ // The mouse is over a router.
+ if (highlightedRouter != null && !highlightedRouter.equals(r.getIpAddress())) {
+ // The selected router is not currently highlighted.
+ if (keys[KeyEvent.VK_SHIFT]) {
+ // Shift is pressed down. User is trying to make a connection.
+ Random rand = new Random();
+ Connection connection = new Connection(
+ highlightedRouter, r.getIpAddress(), rand.nextInt(5) + 1);
+
+ if (r.getConnectionByParticipant(highlightedRouter, r.getIpAddress()) != null) {
+ // Connection exists.
+ return;
+ }
+
+ r.addConnection(connection);
+ Network.getInstance().getRouterByIp(highlightedRouter).addConnection(connection);
+
+ System.out.println("Added connection between " + highlightedRouter + " and " +
+ r.getIpAddress() + ". Cost: " + connection.getCost() + ".");
+
+ repaint();
+
+ return;
+ }
+ }
+
+ if (keys[KeyEvent.VK_CONTROL]) {
+ // CTRL is pressed down -- select routers for highlighting.
+ RouterPath.highlightOne(r);
+
+ repaint();
+
+ return;
+ }
+
+ highlightedRouter = r.getIpAddress();
+
+ repaint();
+
+ return;
+ }
+
+ if (keys[KeyEvent.VK_SHIFT] || keys[KeyEvent.VK_CONTROL]) {
+ // Do not create a router if shift or control are held down.
+ e.consume();
+ return;
+ }
+
+ // If the program reaches this point, it will create a new router.
+
+ int routerId = Network.getInstance().getRouters().size();
+ String routerName = new String(new char[] { (char)(routerId + 65) });
+ while (Network.getInstance().getRouterByIp(routerName) != null) {
+ routerId++;
+ }
+
+ Network.getInstance().addRouter(new Router(routerName, e.getPoint()));
+ highlightedRouter = routerName;
+
+ System.out.println("Added new router: " + routerName);
+
+ repaint();
+ }
+
+ /**
+ * Handle an event when the mouse is dragged.
+ */
+ @Override public void mouseDragged(MouseEvent e) {
+ // Check if a mouse is trying to drag a router across the screen.
+ if (highlightedRouter != null && !highlightedRouter.equals("")
+ && !keys[KeyEvent.VK_SHIFT] && !keys[KeyEvent.VK_CONTROL]) {
+ Router r = Network.getInstance().getRouterByIp(highlightedRouter);
+ if (r == null) {
+ return;
+ }
+
+ Point offset = new Point();
+ offset.x = r.getPosition().x + (e.getPoint().x - r.getPosition().x);
+ offset.y = r.getPosition().y + (e.getPoint().y - r.getPosition().y);
+
+ r.setPosition(offset);
+
+ repaint();
+ }
+ }
+
+ @Override public void mouseMoved(MouseEvent e) {}
+ @Override public void keyTyped(KeyEvent e) {}
+
+ @Override public void keyPressed(KeyEvent e) {
+ keys[e.getKeyCode()] = true;
+
+ if (highlightedRouter != null &&
+ !highlightedRouter.equals("") &&
+ keys[KeyEvent.VK_DELETE]) {
+ Network.getInstance().removeRouterByIp(highlightedRouter);
+
+ try {
+ highlightedRouter = Network.getInstance().getRouters().get(0).toString();
+ }
+ catch (Exception ex) {}
+
+ RouterPath.clear();
+
+ updateAllRouters();
+ }
+
+ else if (keys[KeyEvent.VK_S] && ((e.getModifiers() & KeyEvent.VK_CONTROL) == 0)) {
+ try {
+ Utility.saveNetwork();
+
+ System.out.println("Network saved to " + Network.getInstance().getName() + Utility.FILE_EXTENSION);
+ }
+ catch (IOException ex) {
+ System.err.println("Couldn't save network. Details:");
+ ex.printStackTrace();
+ }
+ }
+
+ // Spawn routing table.
+ else if (e.getKeyCode() == KeyEvent.VK_R) {
+ spawnRoutingTable(Network.getInstance().getRouterByIp(highlightedRouter));
+ }
+
+ if (e.getKeyCode() == KeyEvent.VK_C){
+ SwingUtilities.invokeLater(new Runnable(){
+ public void run(){
+ spawnCostViwerWindow(Network.getInstance().getRouterByIp(highlightedRouter));
+ }
+ });
+ }
+
+ repaint();
+ }
+
+ @Override public void keyReleased(KeyEvent e) {
+ keys[e.getKeyCode()] = false;
+
+ repaint();
+ }
+}
diff --git a/src/main/java/net/locusworks/lsproject/gui/RoutingTableWindow.java b/src/main/java/net/locusworks/lsproject/gui/RoutingTableWindow.java
new file mode 100644
index 0000000..7cc2896
--- /dev/null
+++ b/src/main/java/net/locusworks/lsproject/gui/RoutingTableWindow.java
@@ -0,0 +1,197 @@
+package net.locusworks.lsproject.gui;
+
+import java.awt.BorderLayout;
+import java.awt.event.*;
+import java.util.ArrayList;
+import javax.swing.JFrame;
+import javax.swing.JScrollPane;
+import javax.swing.JTable;
+import javax.swing.table.AbstractTableModel;
+
+import net.locusworks.lsproject.driver.Program;
+import net.locusworks.lsproject.object.Network;
+import net.locusworks.lsproject.object.Router;
+import net.locusworks.lsproject.object.helper.DijkstraCallback;
+
+/**
+ *
+ */
+public class RoutingTableWindow extends JFrame implements WindowListener {
+ private static final long serialVersionUID = 1768859322938299953L;
+
+ private Router router = null;
+ private JTable table = null;
+ private RoutingTableModel tableModel = new RoutingTableModel();
+ private String set = "";
+
+ /**
+ * Display a new routing table window.
+ * @param _router
+ */
+ public RoutingTableWindow(Router _router) {
+ super("Routing table - " + _router.getIpAddress());
+
+ router = _router;
+
+ initializeComponents();
+
+ setVisible(true);
+ }
+
+ /**
+ * Initialize the GUI components used by this window.
+ */
+ private void initializeComponents() {
+ setLayout(new BorderLayout());
+
+ table = new JTable(tableModel);
+ JScrollPane scrollPane = new JScrollPane(table);
+
+ add(table.getTableHeader(), BorderLayout.PAGE_START);
+ add(scrollPane, BorderLayout.CENTER);
+
+ setSize(425, 200);
+
+ router.getRoutingTable().registerCallback(tableModel);
+
+ router.getRoutingTable().execute(router, null);
+ }
+
+ /**
+ * Allow access to which router this window is displaying.
+ * @return Router object.
+ */
+ public Router getRouter() {
+ return router;
+ }
+
+ /**
+ * Model used for displaying the routing table.
+ */
+ @SuppressWarnings("serial")
+ private class RoutingTableModel extends AbstractTableModel implements DijkstraCallback {
+ private ArrayList columnNames = new ArrayList();
+ private Object[][] data;
+ private int currentRow = 0;
+
+ public RoutingTableModel() {
+ }
+
+ /*
+ * Handle callback.
+ */
+
+ @Override public void reset() {
+ set = router.getIpAddress();
+ columnNames.clear();
+ currentRow = 0;
+
+ columnNames.add("N'");
+ columnNames.add(router.toString());
+ for (Router r : Network.getInstance().getRouters()) {
+ if (r != router) {
+ columnNames.add(r.getIpAddress());
+ }
+ }
+
+ fireTableStructureChanged();
+
+ data = new Object[Network.getInstance().getRouters().size()][columnNames.size()];
+
+ for (int i = 0; i < data.length; i++) {
+ for (int j =0; j < data[i].length; j++) {
+ data[i][j] = "";
+ fireTableCellUpdated(i, j);
+ }
+ }
+
+ setValueAt(set, 0, 0);
+
+ fireTableDataChanged();
+
+ System.out.println("Routing table " + router + " reset.");
+ }
+
+ @Override public void predecessorAdded(Router key, Router value) {
+ if (key == router) return;
+ final int columnIndex = getColumnByName(value.getIpAddress());
+
+ setValueAt(key.getIpAddress() + "," + getValueAt(currentRow, columnIndex), currentRow, columnIndex);
+ }
+
+ @Override public void settledRouterAdded(Router r) {
+ if (set.contains(r.getIpAddress())) return;
+
+ currentRow++;
+
+ set += (set.length() > 0 ? "," : "") + r.getIpAddress();
+
+ final int rowIndex = set.split("\\,").length - 1;
+
+ setValueAt(set, rowIndex, 0);
+ }
+
+ @Override public void shortestDistanceUpdated(Router router, int cost) {
+ final int column = getColumnByName(router.getIpAddress());
+
+ setValueAt(cost, currentRow, column);
+ }
+
+ /*
+ * Override AbstractTableModel functions.
+ */
+
+ @Override public String getColumnName(int columnNumber) {
+ return columnNames.get(columnNumber);
+ }
+
+ public int getColumnByName(String columnName) {
+ for (int i = 0; i < columnNames.size(); i++) {
+ if (columnNames.get(i).equals(columnName)) {
+ return i;
+ }
+ }
+
+ return -1;
+ }
+
+ public int getRowByFirstCellName(String cellName) {
+ for (int i = 1; i < getRowCount(); i++) {
+ if (columnNames.get(i).endsWith(cellName)) {
+ return i;
+ }
+ }
+
+ return -1;
+ }
+
+ @Override public int getColumnCount() {
+ return columnNames.size();
+ }
+
+ @Override public int getRowCount() {
+ return data.length;
+ }
+
+ @Override public Object getValueAt(int rowIndex, int columnIndex) {
+ return data[rowIndex][columnIndex];
+ }
+
+ @Override public void setValueAt(Object value, int rowIndex, int columnIndex) {
+ data[rowIndex][columnIndex] = value;
+
+ super.fireTableCellUpdated(rowIndex, columnIndex);
+ }
+ }
+
+ @Override public void windowClosing(WindowEvent e) {
+ router.getRoutingTable().unregisterCallback(tableModel);
+ }
+
+ @Override public void windowActivated(WindowEvent arg0) {}
+ @Override public void windowClosed(WindowEvent arg0) {}
+ @Override public void windowDeactivated(WindowEvent arg0) {}
+ @Override public void windowDeiconified(WindowEvent arg0) {}
+ @Override public void windowIconified(WindowEvent arg0) {}
+ @Override public void windowOpened(WindowEvent arg0) {}
+}
diff --git a/src/main/java/net/locusworks/lsproject/gui/StartupWindow.java b/src/main/java/net/locusworks/lsproject/gui/StartupWindow.java
new file mode 100644
index 0000000..76bcae1
--- /dev/null
+++ b/src/main/java/net/locusworks/lsproject/gui/StartupWindow.java
@@ -0,0 +1,182 @@
+package net.locusworks.lsproject.gui;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+
+import javax.swing.*;
+import javax.swing.filechooser.FileFilter;
+
+import net.locusworks.lsproject.driver.Program;
+import net.locusworks.lsproject.gui.helper.ImageHelper;
+import net.locusworks.lsproject.object.Network;
+import net.locusworks.lsproject.util.Utility;
+
+
+/**
+ * The first window that the user will see. Prompts user to create a new network, load a network, or exit.
+ */
+@SuppressWarnings("serial")
+public class StartupWindow extends JFrame {
+ // Declare class members.
+ private JButton newNetworkButton;
+ private JButton loadNetworkButton;
+ private JButton exitButton;
+
+ /**
+ * Construct a new startup window.
+ */
+ public StartupWindow() {
+ super("LS Network Project");
+
+ initializeGui();
+ }
+
+ /**
+ * Set up the GUI for this window.
+ */
+ private void initializeGui() {
+ // Initialize class members (GUI objects)
+ newNetworkButton = new JButton("New Network");
+ loadNetworkButton = new JButton("Load Network");
+ exitButton = new JButton("Exit");
+
+ // Layout setup.
+ setLayout(new GridBagLayout());
+
+ // Component layout setup.
+ GridBagConstraints c = new GridBagConstraints();
+
+ c.gridx = 0;
+ c.gridy = 0;
+ c.fill = GridBagConstraints.HORIZONTAL;
+ c.insets = new Insets(10, 20, 5, 20);
+ add(newNetworkButton, c);
+
+ c.gridy = 1;
+ c.insets = new Insets(5, 20, 5, 20);
+ add(loadNetworkButton, c);
+
+ c.gridy = 2;
+ c.insets = new Insets(5, 20, 10, 20);
+ add(exitButton, c);
+
+ // Event handler setup.
+ newNetworkButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ newNetworkButton_onClick();
+ }
+ });
+
+ loadNetworkButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ loadNetworkButton_onClick();
+ }
+ });
+
+ exitButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ exitButton_onClick();
+ }
+ });
+
+ // Load window icon.
+ setIconImage(ImageHelper.getImageFromResource("assets/router_ico.png"));
+
+ // Typical window setup.
+ pack();
+
+ setLocationRelativeTo(null);
+ setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ setVisible(true);
+ }
+
+ /**
+ * Handle event when the newNetworkButton is clicked.
+ * Opens a new RouterViewerWindow GUI and closes this window.
+ */
+ private void newNetworkButton_onClick() {
+ setVisible(false);
+
+ dispose();
+
+ String networkName = "";
+ while (networkName.equals("")) {
+ networkName = JOptionPane.showInputDialog("Please enter your network's name:");
+ if (networkName == null) {
+ // Canceled.
+ System.exit(0);
+ }
+ }
+
+ Network.createInstance(networkName);
+
+ new RouterViewerWindow();
+ }
+
+ /**
+ * Handle event when the loadNetworkButton is clicked.
+ * Opens a file dialog, loads a network, opens a new RouterViewerWindow GUI and closes this window.
+ */
+ private void loadNetworkButton_onClick() {
+ JFileChooser fileChooser = new JFileChooser(".");
+ fileChooser.addChoosableFileFilter(new FileFilter() {
+ @Override public boolean accept(File f) {
+ if (f.isDirectory())
+ return true;
+
+ final String ext = Utility.getExtension(f);
+ if (ext == null) {
+ return false;
+ }
+
+ return !ext.equalsIgnoreCase(Utility.FILE_EXTENSION);
+ }
+
+ @Override public String getDescription() {
+ return "*" + Utility.FILE_EXTENSION + " - Serialized network object file.";
+ }
+
+ });
+
+ final int userAction = fileChooser.showOpenDialog(this);
+ if (userAction == JFileChooser.CANCEL_OPTION) {
+ // Canceled.
+ return;
+ }
+
+ File f = fileChooser.getSelectedFile();
+
+ try {
+ Utility.loadNetwork(f);
+ }
+ catch (IOException e) {
+ e.printStackTrace();
+
+ JOptionPane.showMessageDialog(this,
+ "An error occured while trying to load the network file:\n" + e.getMessage(),
+ "Error loading file!",
+ JOptionPane.ERROR_MESSAGE);
+
+ return;
+ }
+
+ setVisible(false);
+
+ dispose();
+
+ new RouterViewerWindow();
+ }
+
+ /**
+ * Handle event when exitButton is clicked.
+ * Closes the program.
+ */
+ private void exitButton_onClick() {
+ System.exit(0);
+ }
+}
diff --git a/src/main/java/net/locusworks/lsproject/gui/helper/ImageHelper.java b/src/main/java/net/locusworks/lsproject/gui/helper/ImageHelper.java
new file mode 100644
index 0000000..f378cc1
--- /dev/null
+++ b/src/main/java/net/locusworks/lsproject/gui/helper/ImageHelper.java
@@ -0,0 +1,32 @@
+package net.locusworks.lsproject.gui.helper;
+
+import java.awt.Image;
+import java.awt.Toolkit;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import javax.swing.JOptionPane;
+
+
+public class ImageHelper {
+
+ public static Image getImageFromResource(String imageName) {
+ try(ByteArrayOutputStream baos = new ByteArrayOutputStream(); InputStream is = ImageHelper.class.getClassLoader().getResourceAsStream(imageName)) {
+ byte[] buff = new byte[1024];
+ int read = 0;
+ while((read = is.read(buff)) > -1) {
+ baos.write(buff, 0, read);
+ }
+ // Load window icon.
+ return Toolkit.getDefaultToolkit().createImage(baos.toByteArray());
+ } catch (IOException ex) {
+ JOptionPane.showMessageDialog(null,
+ "An error occured while trying to load the assets file:\n" + ex.getMessage(),
+ "Error loading file!",
+ JOptionPane.ERROR_MESSAGE);
+ }
+ return null;
+ }
+
+}
diff --git a/src/main/java/net/locusworks/lsproject/gui/helper/RouterPath.java b/src/main/java/net/locusworks/lsproject/gui/helper/RouterPath.java
new file mode 100644
index 0000000..dd38ab9
--- /dev/null
+++ b/src/main/java/net/locusworks/lsproject/gui/helper/RouterPath.java
@@ -0,0 +1,72 @@
+package net.locusworks.lsproject.gui.helper;
+
+import net.locusworks.lsproject.object.DijkstraEngine;
+import net.locusworks.lsproject.object.Path;
+import net.locusworks.lsproject.object.Router;
+
+/**
+ * The RouterPath class's job is to keep track of two separate routers for the purpose of
+ * showing the quickest path from the source (firstRouter) to the destination (secondRouter).
+ */
+public class RouterPath {
+ public static Router firstRouter = null;
+ public static Router secondRouter = null;
+
+ public static Path highlightedPath = null;
+
+ /**
+ * Null out the routers.
+ */
+ public static void clear() {
+ firstRouter = null;
+ secondRouter = null;
+ highlightedPath = null;
+
+ System.out.println("Cleared highlights.");
+ }
+
+ /**
+ * Highlights a router. If one is highlighted, it highlights the other one.
+ * If both are highlighted, it nulls the second and highlights the first.
+ * @param r Router to highlight.
+ */
+ public static void highlightOne(Router r) {
+ if (firstRouter == null) {
+ firstRouter = r;
+ System.out.println("Highlighted source router: " + r.getIpAddress());
+ }
+ else if (secondRouter == null) {
+ secondRouter = r;
+ System.out.println("Highlighted destination router: " + r.getIpAddress());
+
+ highlightedPath = findShortestPath(firstRouter, secondRouter);
+ if (highlightedPath == null) {
+ System.out.println("No connection from " +
+ firstRouter.getIpAddress() + " to " + secondRouter.getIpAddress());
+
+ clear();
+ }
+ else {
+ System.out.println("Path: total cost: " + highlightedPath.getTotalCost());
+ }
+ }
+ else {
+ clear();
+ }
+
+ if (firstRouter == secondRouter && firstRouter != null) {
+ clear();
+ }
+ }
+
+ /**
+ * Find the shortest path from the first router (A) to the target router (B).
+ * @see DijkstraEngine.findShortestPath
+ * @param _firstRouter Starting router.
+ * @param _secondRouter Target router.
+ * @return Sequence from the source router to the destination router.
+ */
+ public static Path findShortestPath(Router _firstRouter, Router _secondRouter) {
+ return new DijkstraEngine().findShortestPath(_firstRouter, _secondRouter);
+ }
+}
diff --git a/src/main/java/net/locusworks/lsproject/object/Connection.java b/src/main/java/net/locusworks/lsproject/object/Connection.java
new file mode 100644
index 0000000..c5761f3
--- /dev/null
+++ b/src/main/java/net/locusworks/lsproject/object/Connection.java
@@ -0,0 +1,71 @@
+package net.locusworks.lsproject.object;
+
+import java.io.Serializable;
+
+/**
+ * A Connection represents a single wire (i.e. the connection between two routers).
+ */
+public class Connection implements Serializable {
+ private static final long serialVersionUID = -1883775251010127340L;
+
+ private int cost;
+ private String ipAddress1;
+ private String ipAddress2;
+
+ /**
+ * Construct a Connection object.
+ * @param _ipAddress1 Address of one router on the connection.
+ * @param _ipAddress2 Address of the other router on the connection.
+ * @param _cost Cost of the wire.
+ */
+ public Connection(String _ipAddress1, String _ipAddress2, int _cost) {
+ ipAddress1 = _ipAddress1;
+ ipAddress2 = _ipAddress2;
+ cost = _cost;
+ }
+
+ /**
+ * Synchronized (thread-safe) method for obtaining the cost of this connection.
+ * @return Cost (type integer) of the wire.
+ */
+ public synchronized int getCost() {
+ return cost;
+ }
+
+ /**
+ * Synchronized (thread-safe) method for setting a new cost for this connection.
+ * @param _cost Cost (type integer) of the wire.
+ */
+ public synchronized void setCost(int _cost) {
+ cost = _cost;
+ }
+
+ /**
+ * A single connection has at most two participants. This retrieves IP Address 1
+ * (not ordered in any way; this is simply the first parameter of the Connection constructor).
+ * @return IP address of participant #1 of this connection.
+ */
+ public String getFirstParticipantAddress() {
+ return ipAddress1;
+ }
+
+ /**
+ * A single connection has at most two participants. This retrieves IP Address 2
+ * (not ordered in any way; this is simply the second parameter of the Connection constructor).
+ * @return IP address of participant #2 of this connection.
+ */
+ public String getSecondParticipantAddress() {
+ return ipAddress2;
+ }
+
+ /**
+ * If the participants of this connections ever need to be modified, they can be done so through
+ * this method.
+ * @param _ipAddress1 IP Address of the first participant.
+ * @param _ipAddress2 IP Address of the second participant.
+ */
+ public void setParticipants(String _ipAddress1, String _ipAddress2) {
+ ipAddress1 = _ipAddress1;
+ ipAddress2 = _ipAddress2;
+ }
+}
diff --git a/src/main/java/net/locusworks/lsproject/object/DijkstraEngine.java b/src/main/java/net/locusworks/lsproject/object/DijkstraEngine.java
new file mode 100644
index 0000000..58c2756
--- /dev/null
+++ b/src/main/java/net/locusworks/lsproject/object/DijkstraEngine.java
@@ -0,0 +1,261 @@
+package net.locusworks.lsproject.object;
+
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.PriorityQueue;
+import java.util.Set;
+
+import net.locusworks.lsproject.object.helper.DijkstraCallback;
+
+
+/**
+ * Keeper and executor of the Dijkstra algorithm.
+ */
+public class DijkstraEngine {
+ public static final int infinity = 100000;
+
+ private ArrayList routers = new ArrayList();
+ private ArrayList callbacks = new ArrayList();
+
+ /**
+ * Create a comparator to sort which routers take priority.
+ */
+ private final Comparator shortertDistanceComparator = new Comparator(){
+ public int compare(Router firstRouter, Router secondRouter){
+
+ int results = getShortestDistance(firstRouter) - getShortestDistance(secondRouter);
+
+ return results;
+ }
+ };
+
+ private final PriorityQueue unsettledNodes = new PriorityQueue(
+ 1, shortertDistanceComparator);
+
+ private final Set settledNodes = new HashSet();
+ private final Map shortestDistances = new HashMap();
+ private final Map predecessors = new HashMap();
+
+ /**
+ * Default constructor.
+ */
+ public DijkstraEngine() {
+ }
+
+ /**
+ * Add a callback that will be called when an event happens.
+ * @param dc Callback class to call.
+ */
+ public void registerCallback(DijkstraCallback dc) {
+ if (!callbacks.contains(dc)) {
+ callbacks.add(dc);
+ }
+ }
+
+ /**
+ * Remove a callback from the list.
+ * @param dc Callback to remove.
+ */
+ public void unregisterCallback(DijkstraCallback dc) {
+ callbacks.remove(dc);
+ }
+
+ /**
+ * Get the nodes that have their paths determined.
+ * @return Set of settled nodes.
+ */
+ public Set getSettledNodes() {
+ return settledNodes;
+ }
+
+ /**
+ * Get a list of routers which have values associated to them telling what the
+ * shortest distances are from the start router to the key router.
+ * @return Map of router->integers.
+ */
+ public Map getShortestDistances() {
+ return shortestDistances;
+ }
+
+ /**
+ * Get a list of predecessors.
+ * @return Router->Router mapping.
+ */
+ public Map getPredecessors() {
+ return predecessors;
+ }
+
+ /**
+ * Private method which adds a router and the shortest possible distance from
+ * the start router to the given router.
+ * @param _router Router to add.
+ * @param cost Cost to get to that router.
+ */
+ private void setShortestDistance(Router _router, int cost) {
+ for (DijkstraCallback dc : callbacks) {
+ dc.shortestDistanceUpdated(_router, cost);
+ }
+
+ unsettledNodes.remove(_router);
+ shortestDistances.put(_router, cost);
+ unsettledNodes.add(_router);
+ }
+
+ /**
+ *
+ * @param _startRouter
+ */
+ private void initialize(Router _startRouter){
+ for (DijkstraCallback dc : callbacks) {
+ dc.reset();
+ }
+
+ settledNodes.clear();
+ unsettledNodes.clear();
+
+ shortestDistances.clear();
+ predecessors.clear();
+
+ setShortestDistance(_startRouter, 0);
+ unsettledNodes.add(_startRouter);
+ }
+
+ private boolean isSettled(Router _router){
+ return settledNodes.contains(_router);
+ }
+
+ private void relaxNeighbors(Router _router){
+ for (Router r : Network.getInstance().getNeighboringRouters(_router)){
+ if (isSettled(r)) continue;
+ if (r == null) continue;
+
+ Connection tempConnection = _router.getConnectionByParticipant(_router.getIpAddress(), r.getIpAddress());
+ if (tempConnection == null) continue;
+
+ int shortDistance = getShortestDistance(_router) + tempConnection.getCost();
+
+ if (shortDistance < getShortestDistance(r)){
+ setShortestDistance(r, shortDistance);
+ setPredecessor(_router, r);
+ }
+ }
+ }
+
+ private void setPredecessor(Router a, Router b){
+ for (DijkstraCallback dc : callbacks) {
+ dc.predecessorAdded(a, b);
+ }
+
+ predecessors.put(a, b);
+ }
+
+ public int getShortestDistance(Router _router){
+ Integer d = shortestDistances.get(_router);
+ return (d == null) ? infinity : d;
+ }
+
+ public Router getPredecessor(Router r){
+ return predecessors.get(r);
+ }
+
+ public void execute(Router startRouter, Router endRouter) {
+ initialize(startRouter);
+
+ Router r = null;
+
+ while ((r = unsettledNodes.poll()) != null){
+ if (r == endRouter) break;
+
+ settledNodes.add(r);
+ for (DijkstraCallback dc : callbacks) {
+ dc.settledRouterAdded(r);
+ }
+
+ relaxNeighbors(r);
+ }
+ }
+
+ /**
+ * Find the shortest path between one router and another, returning the path that one must
+ * take to get from the start to the end.
+ *
+ * Note that this function must run the algorithm multiple times to find how it gets from start to end.
+ * Therefore, in a very large network, this may take a while to execute. On modern computers, this is
+ * not much of a concern. Still, a more efficient algorithm should be used to find start->end along the
+ * quickest path in a more serious system.
+ * @param startRouter Router to start from.
+ * @param endRouter Router to end at.
+ * @return The path (Path object) from the start to the end. If start is not connected to end,
+ * this will return null.
+ */
+ public Path findShortestPath(Router startRouter, Router endRouter){
+ // Get the array of network routers.
+ routers.clear();
+
+ // Run the algorithm once to get the shortest path from start to end..
+ execute(startRouter, endRouter);
+
+ if (shortestDistances.get(endRouter) == null) {
+ // In this situation, startRouter is not connected to endRouter.
+ return null;
+ }
+
+ // We now know how much it will cost to get from start to end.
+ final int totalCost = shortestDistances.get(endRouter);
+
+ // Leading cost will track how much it costs each step from start to end (additively).
+ int leadingCost = 0;
+
+ Router currentRouter = startRouter;
+ Router lastRouter = currentRouter;
+
+ // Loop until we reach the last router.
+ while (!currentRouter.getIpAddress().equals(endRouter.getIpAddress())) {
+ final ArrayList neighbors = (ArrayList)Network.getInstance().getNeighboringRouters(currentRouter);
+ // No need to check last router.
+ neighbors.remove(lastRouter);
+
+ // Search through the current router's neighbors, attempting to find the shortest path from A to B.
+ for (Router r : neighbors) {
+ execute(r, endRouter);
+
+ final Connection c = currentRouter.getConnectionByParticipant(
+ currentRouter.getIpAddress(), r.getIpAddress());
+
+ // Obtain cost from the current router to the target router.
+ final int newCost = shortestDistances.get(endRouter);
+
+ // Test if this router's jump cost is the same as the total cost, taking into
+ // consideration how much it cost to get from previous connections to the current router.
+ if ((totalCost - newCost - leadingCost) == c.getCost()) {
+ // We've found our router -- add it to the path.
+ routers.add(Network.getInstance().getRouterByIp(r.getIpAddress()));
+
+ leadingCost += c.getCost();
+
+ currentRouter = r;
+
+ break;
+ }
+ }
+
+ lastRouter = currentRouter;
+ }
+
+ if (!routers.contains(endRouter))
+ routers.add(endRouter);
+
+ // Convert the array list to a raw array of routers.
+ Router[] list = new Router[routers.size()];
+ for (int i = 0; i < routers.size(); i++) {
+ list[i] = routers.get(i);
+ }
+
+ return new Path(list, totalCost);
+ }
+}
+
+
diff --git a/src/main/java/net/locusworks/lsproject/object/Network.java b/src/main/java/net/locusworks/lsproject/object/Network.java
new file mode 100644
index 0000000..8375aab
--- /dev/null
+++ b/src/main/java/net/locusworks/lsproject/object/Network.java
@@ -0,0 +1,129 @@
+package net.locusworks.lsproject.object;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Network class is capable of performing LS calculations and has the router information
+ *
+ *
+ */
+public class Network implements Serializable {
+ // Makes compiler happy.
+ private static final long serialVersionUID = -3073110726594813517L;
+
+ private String name = null;
+ private ArrayList routers = new ArrayList();
+
+ private static Network instance;
+
+
+ /**
+ * Create a new Network.
+ * @param _name Name of the network.
+ */
+ private Network(String _name) {
+ setName(_name);
+ }
+
+ /**
+ * Obtain the network's name.
+ * @return String containing the network's name.
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Set a new name for the network, which is used as the file name for the network.
+ * @param _name Name of the network.
+ */
+ public void setName(String _name) {
+ name = _name;
+ }
+
+ /**
+ * Add a router to the network.
+ * @param r Router to add.
+ */
+ public synchronized void addRouter(Router r) {
+ routers.add(r);
+ }
+
+ /**
+ * Get the routers in this network.
+ * @return Array list of routers.
+ */
+ public synchronized ArrayList getRouters() {
+ return routers;
+ }
+
+ /**
+ * Get a router by it's IP address.
+ * @param ip IP address to search for.
+ * @return The router that is being searched for. Returns null if the router doesn't exist.
+ */
+ public synchronized Router getRouterByIp(String ip) {
+ for (Router r : routers) {
+ if (r.getIpAddress().equals(ip)) {
+ return r;
+ }
+ }
+
+ return null;
+ }
+
+ public synchronized List getNeighboringRouters(Router _router){
+ List neighboringRouters = new ArrayList(_router.getConnections().size());
+
+ final String sourceAddr = _router.getIpAddress();
+ for (Connection connection : _router.getConnections()){
+ if (!connection.getFirstParticipantAddress().equals(sourceAddr)){
+ neighboringRouters.add(getRouterByIp(connection.getFirstParticipantAddress()));
+ }
+ else{
+ neighboringRouters.add(getRouterByIp(connection.getSecondParticipantAddress()));
+ }
+ }
+
+ return neighboringRouters;
+ }
+
+ /**
+ * Remove a router from the network.
+ * @param ip IP address of the router.
+ */
+ public synchronized void removeRouterByIp(String ip) {
+ for (int i = 0; i < routers.size(); i++) {
+ if (routers.get(i).getIpAddress().equals(ip)) {
+ for (Connection c : routers.get(i).getConnections()) {
+ final String otherRouterAddr = (!c.getFirstParticipantAddress().equals(ip) ?
+ c.getFirstParticipantAddress() : c.getSecondParticipantAddress());
+
+ Router r = getRouterByIp(otherRouterAddr);
+ r.removeConnectionByParticipant(ip, otherRouterAddr);
+ }
+
+ routers.remove(i);
+
+ break;
+ }
+ }
+ }
+
+ public static void createInstance(String networkName) {
+ instance = new Network(networkName);
+ }
+
+ public static Network getInstance() {
+ if (instance == null) instance = new Network("network");
+ return instance;
+ }
+
+ public static void createInstance(Network readObject) {
+ instance = readObject;
+
+ }
+
+}
diff --git a/src/main/java/net/locusworks/lsproject/object/Path.java b/src/main/java/net/locusworks/lsproject/object/Path.java
new file mode 100644
index 0000000..0c72d3a
--- /dev/null
+++ b/src/main/java/net/locusworks/lsproject/object/Path.java
@@ -0,0 +1,42 @@
+package net.locusworks.lsproject.object;
+
+
+public class Path{
+
+ private Router[] routers;
+ private int totalCost;
+ private int element = 0;
+
+ public Path(Router[] _routers, int cost){
+
+ totalCost = cost;
+ routers = _routers;
+ }
+
+ public int getTotalCost(){
+ return totalCost;
+ }
+
+ public boolean hasNext(){
+ return (element < routers.length);
+ }
+
+ public void reset() {
+ element = 0;
+ }
+
+ public Router getNext(){
+ if (! hasNext())
+ return null;
+
+ Router r = routers[element];
+ element++;
+ return r;
+ }
+
+ public Router getDestinationRouter(){
+ return routers[routers.length - 1];
+
+ }
+
+}
diff --git a/src/main/java/net/locusworks/lsproject/object/Router.java b/src/main/java/net/locusworks/lsproject/object/Router.java
new file mode 100644
index 0000000..2440bab
--- /dev/null
+++ b/src/main/java/net/locusworks/lsproject/object/Router.java
@@ -0,0 +1,149 @@
+package net.locusworks.lsproject.object;
+import java.awt.Point;
+import java.io.Serializable;
+import java.util.ArrayList;
+
+/**
+ * A Router is a single entity within the network that is capable of holding one or more connections
+ * with various routers across the network. A router is uniquely identified on the network by it's
+ * IP address.
+ */
+public class Router implements Serializable {
+ private static final long serialVersionUID = 8998728841964957750L;
+
+ private ArrayList connections;
+ private String ipAddress;
+ private Point position;
+
+ private RoutingTable routingTable;
+
+ /**
+ * Create a new router.
+ * @param _ipAddress IP address (should be unique) of the router.
+ * @param _position Position of the router on the Network.
+ */
+ public Router(String _ipAddress, Point _position) {
+ ipAddress = _ipAddress;
+ position = _position;
+ connections = new ArrayList();
+ routingTable = new RoutingTable(this);
+ }
+
+ /**
+ * Return the routing table that this router calcultes.
+ * @return
+ */
+ public RoutingTable getRoutingTable() {
+ return routingTable;
+ }
+
+ /**
+ * Get the IP address of this router.
+ * @return String containing the IP address of the router.
+ */
+ public String getIpAddress() {
+ return ipAddress;
+ }
+
+ /**
+ * Set a new IP address for this router.
+ * @param _ipAddress New address for the router.
+ */
+ public void setIpAddress(String _ipAddress) {
+ ipAddress = _ipAddress;
+ }
+
+ /**
+ * Get the position of the router.
+ * @return Position of the router in a Point object.
+ */
+ public Point getPosition() {
+ return position;
+ }
+
+ /**
+ * Set a new position for the router.
+ * @param _position Position to set.
+ */
+ public void setPosition(Point _position) {
+ position = _position;
+ }
+
+ /**
+ * Synchronized (thread-safe) method for adding a connection to this router.
+ * @param _newConnection Add a new connection to this router's list of connections.
+ */
+ public synchronized void addConnection(Connection _newConnection) {
+ connections.add(_newConnection);
+
+ // Re-calculate connections.
+ routingTable.execute(this, null);
+ }
+
+ /**
+ * Search through the list of connections and obtain a connection based on the participants.
+ * NOTE: The order does not matter! It will return true regardless of which is the "first" or "second"
+ * participant, assuming such a connection exists.
+ * @param _ipAddress1 One participant's address.
+ * @param _ipAddress2 Another participant's address.
+ * @return Connection object if found, or null if not found.
+ */
+ public synchronized Connection getConnectionByParticipant(String _ipAddress1, String _ipAddress2) {
+ for (Connection connection : connections) {
+ if ((connection .getFirstParticipantAddress() .equals(_ipAddress1) &&
+ connection .getSecondParticipantAddress().equals(_ipAddress2)) ||
+ (connection .getSecondParticipantAddress().equals(_ipAddress1) &&
+ connection .getFirstParticipantAddress() .equals(_ipAddress2))) {
+ // Connection found.
+ return connection;
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Get the string-form of Router, which is it's IP address.
+ */
+ @Override public String toString() {
+ return getIpAddress();
+ };
+
+ /**
+ * Remove a connection from the list of connections.
+ * @param _ipAddress1 First participant.
+ * @param _ipAddress2 Second participant.
+ */
+ public synchronized void removeConnectionByParticipant(String _ipAddress1, String _ipAddress2) {
+ connections.remove(getConnectionByParticipant(_ipAddress1, _ipAddress2));
+
+ routingTable.execute(this, null);
+ }
+
+ /**
+ * Get the Router's list of connections. Useful if the router is deleted and connections
+ * need to be severed.
+ * @return Array list of Connection objects.
+ */
+ public synchronized ArrayList getConnections() {
+ return connections;
+ }
+
+ /**
+ * Clears the Router's list of connections.
+ */
+ public synchronized void clearConnections(){
+ connections.clear();
+ }
+
+ /**
+ * Simple method for adding connection.
+ * @param router1
+ * @param router2
+ * @param connection
+ */
+ public static void addConnection(Router router1, Router router2, Connection connection) {
+ router1.addConnection(connection);
+ router2.addConnection(connection);
+ }
+}
diff --git a/src/main/java/net/locusworks/lsproject/object/RoutingTable.java b/src/main/java/net/locusworks/lsproject/object/RoutingTable.java
new file mode 100644
index 0000000..9556fd0
--- /dev/null
+++ b/src/main/java/net/locusworks/lsproject/object/RoutingTable.java
@@ -0,0 +1,34 @@
+package net.locusworks.lsproject.object;
+
+import java.io.Serializable;
+
+/**
+ *
+ */
+public class RoutingTable extends DijkstraEngine implements Serializable {
+ private static final long serialVersionUID = 848488383828283L;
+ private Router parentRouter;
+
+ /**
+ *
+ * @param _parentRouter
+ */
+ public RoutingTable(Router _parentRouter){
+ parentRouter = _parentRouter;
+ }
+
+ /**
+ * Provide access to this table's parent router.
+ * @return Parent router which this routing table is for.
+ */
+ public Router getRouter() {
+ return parentRouter;
+ }
+
+ /**
+ * Perform Dijkstra's algorithm. Should be called every time the router is changed.
+ */
+ public void recalculate() {
+ execute(parentRouter, null);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/net/locusworks/lsproject/object/helper/DijkstraCallback.java b/src/main/java/net/locusworks/lsproject/object/helper/DijkstraCallback.java
new file mode 100644
index 0000000..0b833f0
--- /dev/null
+++ b/src/main/java/net/locusworks/lsproject/object/helper/DijkstraCallback.java
@@ -0,0 +1,14 @@
+package net.locusworks.lsproject.object.helper;
+
+import net.locusworks.lsproject.object.Router;
+
+/**
+ * A callback can be set to the DijkstraEngine if one needs live updates to
+ * the algorithm.
+ */
+public interface DijkstraCallback {
+ public void reset();
+ public void settledRouterAdded(Router router);
+ public void predecessorAdded(Router key, Router value);
+ public void shortestDistanceUpdated(Router router, int cost);
+}
diff --git a/src/main/java/net/locusworks/lsproject/util/Utility.java b/src/main/java/net/locusworks/lsproject/util/Utility.java
new file mode 100644
index 0000000..e210e04
--- /dev/null
+++ b/src/main/java/net/locusworks/lsproject/util/Utility.java
@@ -0,0 +1,72 @@
+package net.locusworks.lsproject.util;
+
+import java.io.*;
+
+import net.locusworks.lsproject.object.Network;
+
+
+public final class Utility {
+ public static final String FILE_EXTENSION = ".lsa";
+
+ /**
+ * Save a network to disk. It uses it's name + the file extension FILE_EXTENSION.
+ * @param network Network to save.
+ * @throws IOException Thrown if an IO error occurs during write.
+ */
+ public static void saveNetwork() throws IOException {
+ FileOutputStream out = new FileOutputStream(Network.getInstance().getName() + FILE_EXTENSION);
+ ObjectOutputStream objectOut = new ObjectOutputStream(out);
+
+ objectOut.writeObject(Network.getInstance());
+
+ objectOut.flush();
+ objectOut.close();
+ out.close();
+
+ System.out.println("Wrote network " + Network.getInstance().getName() + " to file.");
+ }
+
+ /**
+ * Load an existing network object file from disk.
+ * @param networkFile File to load.
+ * @return Network object.
+ * @throws IOException Thrown if an IO error occurs during read.
+ */
+ public static void loadNetwork(File networkFile) throws IOException {
+ if (!networkFile.getName().endsWith(FILE_EXTENSION)) {
+ throw new IOException("Invalid network object file.");
+ }
+
+ FileInputStream in = new FileInputStream(networkFile);
+ ObjectInputStream objectIn = new ObjectInputStream(in);
+
+ try {
+ Network.createInstance((Network)objectIn.readObject());
+ }
+ catch (ClassNotFoundException e) {
+ throw new IOException("Target file is corrupted.");
+ }
+ finally {
+ objectIn.close();
+ in.close();
+ }
+
+ System.out.println("Loaded network " + Network.getInstance().getName() + ".");
+ }
+
+ /**
+ * Utility function for getting a file's extension.
+ * @param f File to look at.
+ * @return Extension of the file.
+ */
+ public static String getExtension(File f) {
+ String ext = null;
+ String s = f.getName();
+ int i = s.lastIndexOf('.');
+
+ if (i > 0 && i < s.length() - 1) {
+ ext = s.substring(i+1).toLowerCase();
+ }
+ return ext;
+ }
+}
diff --git a/src/main/resources/assets/router.png b/src/main/resources/assets/router.png
new file mode 100644
index 0000000..d78a865
Binary files /dev/null and b/src/main/resources/assets/router.png differ
diff --git a/src/main/resources/assets/router_ico.png b/src/main/resources/assets/router_ico.png
new file mode 100644
index 0000000..7d6a0a9
Binary files /dev/null and b/src/main/resources/assets/router_ico.png differ
diff --git a/src/test/java/object/ConnectionTest.java b/src/test/java/object/ConnectionTest.java
new file mode 100644
index 0000000..63966a2
--- /dev/null
+++ b/src/test/java/object/ConnectionTest.java
@@ -0,0 +1,49 @@
+package object;
+
+import static org.junit.Assert.*;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import net.locusworks.lsproject.object.Connection;
+
+public class ConnectionTest {
+
+ private Connection testConnection;
+
+ @Before
+ public void setUpBeforeTest(){
+
+ testConnection = new Connection("1", "2", 4);
+
+
+ }
+ @Test
+ public void testGetCost() {
+ assertEquals(4, testConnection.getCost());
+ }
+
+ @Test
+ public void testSetCost() {
+ testConnection.setCost(21);
+ assertEquals(21, testConnection.getCost());
+ }
+
+ @Test
+ public void testGetFirstParticipantAddress() {
+ assertEquals("1", testConnection.getFirstParticipantAddress());
+ }
+
+ @Test
+ public void testGetSecondParticipantAddress() {
+ assertEquals("2", testConnection.getSecondParticipantAddress());
+ }
+
+ @Test
+ public void testSetParticipants() {
+ testConnection.setParticipants("100", "200");
+ assertEquals("100", testConnection.getFirstParticipantAddress());
+ assertEquals("200", testConnection.getSecondParticipantAddress());
+ }
+
+}
diff --git a/src/test/java/object/NetworkTest.java b/src/test/java/object/NetworkTest.java
new file mode 100644
index 0000000..ca2f761
--- /dev/null
+++ b/src/test/java/object/NetworkTest.java
@@ -0,0 +1,90 @@
+package object;
+
+import java.awt.Point;
+import java.util.ArrayList;
+
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import net.locusworks.lsproject.driver.Program;
+import net.locusworks.lsproject.object.Connection;
+import net.locusworks.lsproject.object.DijkstraEngine;
+import net.locusworks.lsproject.object.Network;
+import net.locusworks.lsproject.object.Path;
+import net.locusworks.lsproject.object.Router;
+
+public class NetworkTest {
+ @BeforeClass
+ public static void setUpBeforeClass() {
+ Network.createInstance("Johnny");
+ }
+
+ @Before
+ public void setUpBeforeTest(){
+ Router router1 = new Router("192.168.1.0", new Point(0,1));
+ Router router2 = new Router("192.168.1.1", new Point(0,2));
+ Router router3 = new Router("192.168.1.2", new Point(0,3));
+ Router router4 = new Router("192.168.1.3", new Point(0,4));
+ Router router5 = new Router("192.168.1.4", new Point(0,5));
+
+
+ Connection connection1 = new Connection(router1.getIpAddress(),
+ router2.getIpAddress(), 1);
+
+ Connection connection2 = new Connection(router1.getIpAddress(),
+ router3.getIpAddress(), 3);
+
+ Connection connection3 = new Connection(router1.getIpAddress(),
+ router4.getIpAddress(), 6);
+
+ Connection connection4 = new Connection(router2.getIpAddress(),
+ router3.getIpAddress(), 5);
+
+ Connection connection5 = new Connection(router2.getIpAddress(),
+ router4.getIpAddress(), 2);
+
+ Connection connection6 = new Connection(router3.getIpAddress(),
+ router5.getIpAddress(), 2);
+
+ Connection connection7 = new Connection(router4.getIpAddress(),
+ router5.getIpAddress(), 1);
+
+ Router.addConnection(router1, router2, connection1);
+ Router.addConnection(router1, router3, connection2);
+ Router.addConnection(router1, router4, connection3);
+ Router.addConnection(router2, router3, connection4);
+ Router.addConnection(router2, router4, connection5);
+ Router.addConnection(router3, router5, connection6);
+ Router.addConnection(router4, router5, connection7);
+
+ Network.getInstance().addRouter(router1);
+ Network.getInstance().addRouter(router2);
+ Network.getInstance().addRouter(router3);
+ Network.getInstance().addRouter(router4);
+ Network.getInstance().addRouter(router5);
+ }
+
+
+
+ @Test
+ public void testFindShortestPath(){
+ DijkstraEngine engine = new DijkstraEngine();
+
+ System.out.println(Network.getInstance().getRouters().size());
+
+ Path path = engine.findShortestPath(Network.getInstance().getRouterByIp("192.168.1.0"),
+ Network.getInstance().getRouterByIp("192.168.1.4"));
+
+ int i = 1;
+ ArrayList routerz = new ArrayList();
+ while (path.hasNext()) {
+ Router r = path.getNext();
+ routerz.add(r);
+ System.out.println("Step " + i++ + ": " + r.getIpAddress());
+ }
+ System.out.println("Total cost: " + path.getTotalCost());
+
+ }
+
+}
diff --git a/src/test/java/object/PathTest.java b/src/test/java/object/PathTest.java
new file mode 100644
index 0000000..fcbddf2
--- /dev/null
+++ b/src/test/java/object/PathTest.java
@@ -0,0 +1,73 @@
+package object;
+
+import static org.junit.Assert.*;
+import org.junit.Before;
+import java.awt.Point;
+
+import org.junit.Test;
+
+import net.locusworks.lsproject.object.Connection;
+import net.locusworks.lsproject.object.Path;
+import net.locusworks.lsproject.object.Router;
+
+public class PathTest {
+ private Path path;
+ private Path path2;
+ private final int expectedTotalCost = 9;
+
+ @Before
+ public void setUpBeforeClass(){
+ Router[] routers = new Router[10];
+
+ for(int i = 0; i < 10; i++){
+ Router router = new Router("192.168.1."+ i, new Point(0, 0));
+ routers[i] = router;
+ }
+
+ for(int i = 0; i < 9; i++){
+ Connection connection = new Connection("192.168.1."+i, "192.168.1."+(i+1),
+ 1);
+ routers[i].addConnection(connection);
+ routers[i+1].addConnection(connection);
+ }
+
+ path = new Path(routers, expectedTotalCost);
+ path2 = new Path(routers, expectedTotalCost);
+
+ }
+ @Test
+ public void testPath() {
+
+ for(int i = 0; i < 8; i++){
+ if(path.hasNext() == false|| path2.hasNext() == false){
+ fail("Has Next failed at " + i + ". Should Never be False but was False");
+ }
+ assertEquals(path.getNext(), path2.getNext());
+ }
+ }
+
+
+ @Test
+ public void testGetTotalCost() {
+ assertEquals(expectedTotalCost, path.getTotalCost());
+ }
+
+ @Test
+ public void testGetNext(){
+ for(int i = 0; i < 9; i++){
+ if(path.getNext() == null){
+ fail("getNext reached null. Should never reach it");
+ }
+ }
+ }
+
+ @Test
+ public void testHasNext(){
+ for (int i = 0; i < 9; i++){
+ path.getNext();
+ if(path.hasNext() == false){
+ fail("hasNext reached the end of the elements");
+ }
+ }
+ }
+}
diff --git a/src/test/java/object/RouterTest.java b/src/test/java/object/RouterTest.java
new file mode 100644
index 0000000..4cc3a23
--- /dev/null
+++ b/src/test/java/object/RouterTest.java
@@ -0,0 +1,78 @@
+package object;
+
+import static org.junit.Assert.*;
+
+import java.awt.Point;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import net.locusworks.lsproject.object.Connection;
+import net.locusworks.lsproject.object.Router;
+
+public class RouterTest {
+ private Router router = null;
+
+
+ @Before
+ public void setUpBeforeTest(){
+
+ router = new Router("192.168.1.0", new Point(0, 0));
+
+
+ }
+
+ @Test
+ public void testGetIpAddress() {
+ if (! router.getIpAddress().equals("192.168.1.0")){
+ fail("ip Address does not match");
+ }
+ }
+
+ @Test
+ public void testSetIpAddress() {
+ router.setIpAddress("192.168.1.2");
+ if(! router.getIpAddress().equals("192.168.1.2")){
+ fail("Ip address did not set correctly");
+ }
+
+ }
+
+ @Test
+ public void testAddConnection() {
+ Connection testConnection = new Connection("192.168.1.3", "192.168.1.4", 3);
+ router.addConnection(testConnection);
+
+ String connection1 = router.getConnections().get(0).getFirstParticipantAddress();
+ String connection2 = router.getConnections().get(0).getSecondParticipantAddress();
+
+ assertEquals("192.168.1.3", connection1);
+ assertEquals("192.168.1.4", connection2);
+
+ }
+
+ @Test
+ public void testGetConnectionByParticipant() {
+
+ for(int i = 0; i < 10; i++){
+ router.addConnection(new Connection(Integer.toString(i), Integer.toString(i+1), 1));
+ }
+
+
+ for (int i = 0; i < 10; i++){
+ Connection testConnection = router.getConnectionByParticipant(
+ Integer.toString(i), Integer.toString(i+1));
+ assertEquals(Integer.toString(i), testConnection.getFirstParticipantAddress());
+ assertEquals(Integer.toString(i+1), testConnection.getSecondParticipantAddress());
+ }
+
+ Connection testCase = new Connection ("a", "A", 1);
+
+ router.clearConnections();
+
+ router.addConnection(testCase);
+ assertNull(router.getConnectionByParticipant("a", "a"));
+
+ }
+
+}