From 40e2af6a93f2da5e43e7a12ca66d2079ab430140 Mon Sep 17 00:00:00 2001 From: Isaac Parenteau Date: Mon, 18 Oct 2021 19:26:42 -0500 Subject: [PATCH] Added old project initial commit --- .gitignore | 6 + Jenkinsfile | 186 ++++++++ pom.xml | 39 ++ .../locusworks/lsproject/driver/Program.java | 56 +++ .../lsproject/gui/CostViewerWindow.java | 118 +++++ .../lsproject/gui/DebugConsole.java | 53 +++ .../lsproject/gui/RouterViewerWindow.java | 411 ++++++++++++++++++ .../lsproject/gui/RoutingTableWindow.java | 197 +++++++++ .../lsproject/gui/StartupWindow.java | 182 ++++++++ .../lsproject/gui/helper/ImageHelper.java | 32 ++ .../lsproject/gui/helper/RouterPath.java | 72 +++ .../lsproject/object/Connection.java | 71 +++ .../lsproject/object/DijkstraEngine.java | 261 +++++++++++ .../locusworks/lsproject/object/Network.java | 129 ++++++ .../net/locusworks/lsproject/object/Path.java | 42 ++ .../locusworks/lsproject/object/Router.java | 149 +++++++ .../lsproject/object/RoutingTable.java | 34 ++ .../object/helper/DijkstraCallback.java | 14 + .../locusworks/lsproject/util/Utility.java | 72 +++ src/main/resources/assets/router.png | Bin 0 -> 9007 bytes src/main/resources/assets/router_ico.png | Bin 0 -> 3891 bytes src/test/java/object/ConnectionTest.java | 49 +++ src/test/java/object/NetworkTest.java | 90 ++++ src/test/java/object/PathTest.java | 73 ++++ src/test/java/object/RouterTest.java | 78 ++++ 25 files changed, 2414 insertions(+) create mode 100644 .gitignore create mode 100644 Jenkinsfile create mode 100644 pom.xml create mode 100644 src/main/java/net/locusworks/lsproject/driver/Program.java create mode 100644 src/main/java/net/locusworks/lsproject/gui/CostViewerWindow.java create mode 100644 src/main/java/net/locusworks/lsproject/gui/DebugConsole.java create mode 100644 src/main/java/net/locusworks/lsproject/gui/RouterViewerWindow.java create mode 100644 src/main/java/net/locusworks/lsproject/gui/RoutingTableWindow.java create mode 100644 src/main/java/net/locusworks/lsproject/gui/StartupWindow.java create mode 100644 src/main/java/net/locusworks/lsproject/gui/helper/ImageHelper.java create mode 100644 src/main/java/net/locusworks/lsproject/gui/helper/RouterPath.java create mode 100644 src/main/java/net/locusworks/lsproject/object/Connection.java create mode 100644 src/main/java/net/locusworks/lsproject/object/DijkstraEngine.java create mode 100644 src/main/java/net/locusworks/lsproject/object/Network.java create mode 100644 src/main/java/net/locusworks/lsproject/object/Path.java create mode 100644 src/main/java/net/locusworks/lsproject/object/Router.java create mode 100644 src/main/java/net/locusworks/lsproject/object/RoutingTable.java create mode 100644 src/main/java/net/locusworks/lsproject/object/helper/DijkstraCallback.java create mode 100644 src/main/java/net/locusworks/lsproject/util/Utility.java create mode 100644 src/main/resources/assets/router.png create mode 100644 src/main/resources/assets/router_ico.png create mode 100644 src/test/java/object/ConnectionTest.java create mode 100644 src/test/java/object/NetworkTest.java create mode 100644 src/test/java/object/PathTest.java create mode 100644 src/test/java/object/RouterTest.java 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 0000000000000000000000000000000000000000..d78a865bbc485ed9964d16053c88b31507e2d163 GIT binary patch literal 9007 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 BJgNWy literal 0 HcmV?d00001 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")); + + } + +}