diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..ba58a22
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,183 @@
+### Java ###
+# Compiled class file
+*.class
+
+# Log file
+*.log
+
+# BlueJ files
+*.ctxt
+
+# Mobile Tools for Java (J2ME)
+.mtj.tmp/
+
+# Package Files #
+*.jar
+*.war
+*.nar
+*.ear
+*.zip
+*.tar.gz
+*.rar
+
+# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
+hs_err_pid*
+
+### Maven ###
+target/
+pom.xml.tag
+pom.xml.releaseBackup
+pom.xml.versionsBackup
+pom.xml.next
+release.properties
+dependency-reduced-pom.xml
+buildNumber.properties
+.mvn/timing.properties
+.mvn/wrapper/maven-wrapper.jar
+
+### NetBeans ###
+nbproject/private/
+build/
+nbbuild/
+dist/
+nbdist/
+.nb-gradle/
+
+### Eclipse ###
+
+.metadata
+bin/
+tmp/
+*.tmp
+*.bak
+*.swp
+*~.nib
+local.properties
+.settings/
+.loadpath
+.recommenders
+
+# External tool builders
+.externalToolBuilders/
+
+# Locally stored "Eclipse launch configurations"
+*.launch
+
+# PyDev specific (Python IDE for Eclipse)
+*.pydevproject
+
+# CDT-specific (C/C++ Development Tooling)
+.cproject
+
+# CDT- autotools
+.autotools
+
+# Java annotation processor (APT)
+.factorypath
+
+# PDT-specific (PHP Development Tools)
+.buildpath
+
+# sbteclipse plugin
+.target
+
+# Tern plugin
+.tern-project
+
+# TeXlipse plugin
+.texlipse
+
+# STS (Spring Tool Suite)
+.springBeans
+
+# Code Recommenders
+.recommenders/
+
+# Annotation Processing
+.apt_generated/
+
+# Scala IDE specific (Scala & Java development for Eclipse)
+.cache-main
+.scala_dependencies
+.worksheet
+
+# Eclipse Core
+.project
+
+# JDT-specific (Eclipse Java Development Tools)
+.classpath
+
+# Annotation Processing
+.apt_generated
+
+.sts4-cache/
+
+### Intellij ###
+# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm
+
+# User-specific stuff
+.idea/**/workspace.xml
+.idea/**/tasks.xml
+.idea/**/usage.statistics.xml
+.idea/**/dictionaries
+.idea/**/shelf
+
+# Generated files
+.idea/**/contentModel.xml
+
+# Sensitive or high-churn files
+.idea/**/dataSources/
+.idea/**/dataSources.ids
+.idea/**/dataSources.local.xml
+.idea/**/sqlDataSources.xml
+.idea/**/dynamic.xml
+.idea/**/uiDesigner.xml
+.idea/**/dbnavigator.xml
+
+# Gradle
+.idea/**/gradle.xml
+.idea/**/libraries
+
+# Gradle and Maven with auto-import
+# When using Gradle or Maven with auto-import, you should exclude module files,
+# since they will be recreated, and may cause churn. Uncomment if using
+# auto-import.
+# .idea/modules.xml
+# .idea/*.iml
+# .idea/modules
+
+# CMake
+cmake-build-*/
+
+# Mongo Explorer plugin
+.idea/**/mongoSettings.xml
+
+# File-based project format
+*.iws
+
+# IntelliJ
+out/
+
+# mpeltonen/sbt-idea plugin
+.idea_modules/
+
+# JIRA plugin
+atlassian-ide-plugin.xml
+
+# Cursive Clojure plugin
+.idea/replstate.xml
+
+# Crashlytics plugin (for Android Studio and IntelliJ)
+com_crashlytics_export_strings.xml
+crashlytics.properties
+crashlytics-build.properties
+fabric.properties
+
+# Editor-based Rest Client
+.idea/httpRequests
+
+# Android studio 3.1+ serialized cache file
+.idea/caches/build_file_checksums.ser
+
+# Sonarlint plugin
+.idea/sonarlint
\ No newline at end of file
diff --git a/build.xml b/build.xml
new file mode 100644
index 0000000..89c8962
--- /dev/null
+++ b/build.xml
@@ -0,0 +1,73 @@
+
+
+
+
+
+
+
+
+
+
+ Builds, tests, and runs the project Middleware.
+
+
+
diff --git a/manifest.mf b/manifest.mf
new file mode 100644
index 0000000..328e8e5
--- /dev/null
+++ b/manifest.mf
@@ -0,0 +1,3 @@
+Manifest-Version: 1.0
+X-COMMENT: Main-Class will be added automatically by build
+
diff --git a/src/middleware/Main.java b/src/middleware/Main.java
new file mode 100644
index 0000000..0fdf3d5
--- /dev/null
+++ b/src/middleware/Main.java
@@ -0,0 +1,30 @@
+package middleware;
+
+import middleware.components.main.MainUI;
+
+/**
+ * Main
+ *
+ * @author JLScott1999
+ */
+public class Main
+{
+
+ /**
+ * @param args the command line arguments
+ */
+ public static void main(String[] args)
+ {
+ MainUI main = new MainUI();
+
+// UserAgent A = new UserAgent("A");
+// UserAgent B = new UserAgent("B");
+// Portal P = new Portal(10);
+// P.addAgent(A);
+// P.addAgent(B);
+// P.start();
+// UserAgentUI Aform = new UserAgentUI(A);
+// UserAgentUI Bform = new UserAgentUI(B);
+ }
+
+}
diff --git a/src/middleware/StressTest.java b/src/middleware/StressTest.java
new file mode 100644
index 0000000..e900510
--- /dev/null
+++ b/src/middleware/StressTest.java
@@ -0,0 +1,90 @@
+package middleware;
+
+import java.net.UnknownHostException;
+import java.time.Duration;
+import java.time.LocalDateTime;
+import middleware.agents.MsgListener;
+import middleware.agents.Portal;
+import middleware.agents.Router;
+import middleware.agents.UserAgent;
+
+/**
+ *
+ * @author JLScott1999
+ */
+public class StressTest
+{
+
+ public static void main(String[] args) throws UnknownHostException
+ {
+ Router r1 = new Router(10000, "1.0.0", 50);
+ Portal p1r1 = new Portal(10000, "1.1.0");
+ Portal p2r1 = new Portal(10000, "1.2.0");
+ UserAgent u1p1r1 = new UserAgent("1.1.1");
+ UserAgent u2p1r1 = new UserAgent("1.1.2");
+ UserAgent u1p2r1 = new UserAgent("1.2.1");
+ r1.addAgent(p1r1);
+ r1.addAgent(p2r1);
+ r1.start();
+ //p1r1.addAgent(p2r1);
+ p1r1.addAgent(u1p1r1);
+ p1r1.addAgent(u2p1r1);
+ p1r1.start();
+ p2r1.addAgent(u1p2r1);
+ p2r1.start();
+ u1p1r1.addListener(new MsgListener() {
+ @Override
+ public void UserAgentMsg(String sender, String msg)
+ {
+ LocalDateTime dateTimeMsg = LocalDateTime.parse(msg);
+ LocalDateTime dateTimeNow = LocalDateTime.now();
+ System.out.println(dateTimeMsg
+ + " "
+ + dateTimeNow
+ + " "
+ + Duration.between(dateTimeMsg, dateTimeNow).toMillis());
+ }
+ });
+
+ // 1 Portal 2 Useragents
+
+ int SENDMSGCOUNT = 1000;
+
+ new Thread(new Runnable() {
+ @Override
+ public void run()
+ {
+ for (int i = 0; i < SENDMSGCOUNT; i++)
+ {
+ u2p1r1.sendMsg(u2p1r1.getAddress(), "1.1.1", LocalDateTime.now().toString());
+ }
+ }
+ }).start();
+
+ for (int i = 0; i < SENDMSGCOUNT; i++)
+ {
+ u2p1r1.sendMsg(u2p1r1.getAddress(), "1.1.1", LocalDateTime.now().toString());
+ }
+
+
+ // 2 Portals 2 Useragents
+
+// new Thread(new Runnable() {
+// @Override
+// public void run()
+// {
+// for (int i = 0; i < SENDMSGCOUNT; i++)
+// {
+// u1p2r1.sendMsg(u1p2r1.getAddress(), "1.1.1", LocalDateTime.now().toString());
+// }
+// }
+// }).start();
+//
+// for (int i = 0; i < SENDMSGCOUNT; i++)
+// {
+// u1p2r1.sendMsg(u1p2r1.getAddress(), "1.1.1", LocalDateTime.now().toString());
+// }
+//
+ }
+
+}
diff --git a/src/middleware/StressTestSendMsgServer.java b/src/middleware/StressTestSendMsgServer.java
new file mode 100644
index 0000000..9ebc793
--- /dev/null
+++ b/src/middleware/StressTestSendMsgServer.java
@@ -0,0 +1,48 @@
+package middleware;
+
+import java.net.UnknownHostException;
+import java.time.LocalDateTime;
+import middleware.agents.Portal;
+import middleware.agents.Router;
+import middleware.agents.UserAgent;
+
+/**
+ *
+ * @author JLScott1999
+ */
+public class StressTestSendMsgServer
+{
+
+ public static void main(String[] args) throws UnknownHostException
+ {
+ Router r2 = new Router(10000, "2.0.0", 100);
+ Portal p1r2 = new Portal(10000, "2.1.0");
+ UserAgent u1p1r2 = new UserAgent("2.1.1");
+ r2.addAgent(p1r2);
+ r2.start();
+ //p1r1.addAgent(p2r1);
+ p1r2.addAgent(u1p1r2);
+ p1r2.start();
+
+ r2.connect("1.0.0", "127.0.0.1", 50);
+
+ int SENDMSGCOUNT = 1000;
+
+ new Thread(new Runnable() {
+ @Override
+ public void run()
+ {
+ for (int i = 0; i < SENDMSGCOUNT; i++)
+ {
+ u1p1r2.sendMsg(u1p1r2.getAddress(), "1.1.1", LocalDateTime.now().toString());
+ }
+ }
+ }).start();
+
+// for (int i = 0; i < SENDMSGCOUNT; i++)
+// {
+// u2p1r1.sendMsg(u2p1r1.getAddress(), "1.1.1", LocalDateTime.now().toString());
+// }
+ }
+
+}
diff --git a/src/middleware/agents/AgentAddress.java b/src/middleware/agents/AgentAddress.java
new file mode 100644
index 0000000..4d44402
--- /dev/null
+++ b/src/middleware/agents/AgentAddress.java
@@ -0,0 +1,141 @@
+package middleware.agents;
+
+import java.io.Serializable;
+import java.security.InvalidParameterException;
+
+/**
+ * Agent Address
+ * Addresses for metaAgents
+ *
+ * @author JLScott1999
+ */
+public final class AgentAddress implements Serializable
+{
+
+ private int[] address;
+
+ /**
+ * Creates an instance of AgentAddress
+ * @param sections no. of sections in address
+ * @param addressString address
+ */
+ public AgentAddress(int sections, String addressString)
+ {
+ address = new int[sections];
+ setAddress(addressString);
+ }
+
+ /**
+ * Creates a new instance of AgentAddress
+ * @param sections no. of sections in address
+ */
+ public AgentAddress(int sections)
+ {
+ this(sections, null);
+ }
+
+ /**
+ * Creates a new instance of AgentAddress
+ * Default of 3 sections
+ * @param addressString address string
+ */
+ public AgentAddress(String addressString)
+ {
+ this(3, addressString);
+ }
+
+ /**
+ * Creates instance of AgentAddress with a 3 section address
+ */
+ public AgentAddress()
+ {
+ this(3);
+ }
+
+ /**
+ * Sets valid address based off of given string
+ * @param addressString addressString
+ */
+ public void setAddress(String addressString)
+ {
+ if (addressString != null)
+ {
+ int i = 0;
+ int section = 0;
+ while (i < addressString.length())
+ {
+ int dot = addressString.indexOf('.', i);
+ if (dot != -1)
+ {
+ address[section++] = Integer.parseInt(addressString.substring(i, dot));
+ i = dot + 1;
+ }
+ else
+ {
+ address[section] = Integer.parseInt(addressString.substring(i, addressString.length()));
+ i = addressString.length();
+ }
+ }
+ }
+ }
+
+ /**
+ * Gets Address
+ * @return address
+ */
+ public String getAddress()
+ {
+ return toString();
+ }
+
+ /**
+ * Changes value of address at given section
+ * @param section specified section
+ * @param value new value
+ */
+ public void setSection(int section, int value)
+ {
+ if (inSectionRange(section))
+ {
+ address[section - 1] = value;
+ }
+ else
+ {
+ throw new InvalidParameterException();
+ }
+ }
+
+ private boolean inSectionRange(int section)
+ {
+ return (section > 0 && section <= address.length);
+ }
+
+ /**
+ *
+ * @param section
+ * @return
+ */
+ public int getSection(int section)
+ {
+ if (inSectionRange(section))
+ {
+ return address[section - 1];
+ }
+ else
+ {
+ throw new InvalidParameterException();
+ }
+ }
+
+ @Override
+ public String toString()
+ {
+ String result = "";
+ for (int i = 0; i < address.length; i++)
+ {
+ result += address[i] + ((address.length == i + 1 ? "" : "."));
+ }
+ return result;
+ }
+
+}
\ No newline at end of file
diff --git a/src/middleware/agents/MetaAgent.java b/src/middleware/agents/MetaAgent.java
new file mode 100644
index 0000000..de2b1a9
--- /dev/null
+++ b/src/middleware/agents/MetaAgent.java
@@ -0,0 +1,209 @@
+package middleware.agents;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.LinkedBlockingQueue;
+import middleware.message.MetaAgentMessage;
+import middleware.message.SystemErrorMessage;
+import middleware.message.wrapper.MetaAgentWrapper;
+import middleware.observer.Observer;
+import middleware.observer.Subject;
+
+/**
+ * MetaAgent
+ *
+ * @author JLScott1999
+ */
+public abstract class MetaAgent extends LinkedBlockingQueue implements Runnable, Subject
+{
+
+ private AgentAddress address;
+ private Thread thread;
+ private boolean running = true;
+ private ArrayList metaAgent = new ArrayList();
+ private List listOfObservers = new ArrayList<>();
+
+ /**
+ * Creates a MetaAgent with specified properties
+ * @param queueSize the size of the blocking queue
+ * @param addressString address of the MetaAgent
+ */
+ public MetaAgent(int queueSize, String addressString)
+ {
+ super(queueSize);
+ this.address = new AgentAddress(addressString);
+ }
+
+ /**
+ * Runs the MessageHandler once thread is started
+ */
+ @Override
+ public void run()
+ {
+ while (running)
+ {
+ try
+ {
+ msgHandler(super.take());
+ }
+ catch (InterruptedException ex)
+ {
+ System.out.println("Exiting");
+ }
+ }
+ }
+
+ /**
+ * Starts thread
+ */
+ public void start()
+ {
+ if (thread == null)
+ {
+ running = true;
+ thread = new Thread(this);
+ thread.start();
+ }
+ }
+
+ /**
+ * Stops thread
+ */
+ public void stop()
+ {
+ if (thread != null)
+ {
+ running = false;
+ thread.interrupt();
+ thread = null;
+ }
+ }
+
+ /**
+ * Gets MetaAgent's address
+ * @return MetaAgent's Address
+ */
+ public AgentAddress getAddress()
+ {
+ return address;
+ }
+
+ /**
+ * Sets MetaAgent's address
+ * @param addressString MetaAgent's Address
+ */
+ public void setAddress(String addressString)
+ {
+ this.address = new AgentAddress(addressString);
+ }
+
+ /**
+ * Attaches an observer to the MetaAgent
+ * @param observer observer to be attached (e.g. NodeListener)
+ */
+ @Override
+ public void attach(Observer observer) {
+ listOfObservers.add(observer);
+ }
+
+ /**
+ * Detaches an observer from the MetaAgent (if it is attached)
+ * @param observer observer to be detached
+ */
+ @Override
+ public void detach(Observer observer) {
+ if(listOfObservers.contains(observer)){
+ listOfObservers.remove(observer);
+ }
+ }
+
+ /**
+ * Updates attached observers with a message
+ * @param msg the message to be sent to the observers
+ * @return whether observers were successfully updated
+ */
+ @Override
+ public boolean updateObservers(Object msg) {
+ boolean result = false;
+ for (Observer o : listOfObservers){
+ result = o.update(msg);
+ }
+ return result;
+ }
+
+ /**
+ * Allows for communication between MetaAgents
+ * Adds a MetaAgent
+ * @param agent
+ */
+ public void addAgent(MetaAgent agent)
+ {
+ // TODO Generate random address
+ if (!metaAgent.contains(agent))
+ {
+ metaAgent.add(agent);
+ agent.addAgent(this);
+ }
+ }
+
+ /**
+ * Handles message objects passed to it
+ * @param data message
+ */
+ public void msgHandler(Object data)
+ {
+ if (data instanceof MetaAgentMessage)
+ {
+ if (getAddress().getSection(1) != ((MetaAgentMessage) data).getMessage().getRecipient().getSection(1))
+ {
+ boolean sent = false;
+ for (int i = 0; i < metaAgent.size() && !sent; i++)
+ {
+ if (metaAgent.get(i).getAddress().toString().equals(this.getAddress().getSection(1) + ".0.0"))
+ {
+ metaAgent.get(i).add(data);
+ sent = true;
+ }
+ }
+ if(!sent)
+ {
+ if (!((MetaAgentMessage) data).getMessage().getSender().getAddress().equals("0.0.0"))
+ {
+ add(MetaAgentWrapper.wrap(new SystemErrorMessage(((MetaAgentMessage) data).getMessage().getRecipient() + " Does not exist?", ((MetaAgentMessage) data).getMessage().getSender().getAddress()), 15));
+ }
+ }
+ }
+ else
+ {
+ boolean sent = false;
+ for (int i = 0; i < metaAgent.size() && !sent; i++)
+ {
+ if (metaAgent.get(i).getAddress().getSection(2) == ((MetaAgentMessage) data).getMessage().getRecipient().getSection(2) && metaAgent.get(i).getAddress().getSection(1) == ((MetaAgentMessage) data).getMessage().getRecipient().getSection(1))
+ {
+ metaAgent.get(i).add(data);
+ sent = true;
+ }
+ }
+ if(!sent)
+ {
+ for (int i = 0; i < metaAgent.size() && !sent; i++)
+ {
+ if (metaAgent.get(i).getAddress().getSection(1) == this.getAddress().getSection(1))
+ {
+ metaAgent.get(i).add(data);
+ sent = true;
+ }
+ }
+ }
+ if(!sent)
+ {
+ if (!((MetaAgentMessage) data).getMessage().getSender().getAddress().equals("0.0.0"))
+ {
+ add(MetaAgentWrapper.wrap(new SystemErrorMessage(((MetaAgentMessage) data).getMessage().getRecipient() + " Does not exist?", ((MetaAgentMessage) data).getMessage().getSender().getAddress()), 15));
+ }
+ }
+ }
+ }
+ }
+
+}
diff --git a/src/middleware/agents/MsgListener.java b/src/middleware/agents/MsgListener.java
new file mode 100644
index 0000000..57dacf7
--- /dev/null
+++ b/src/middleware/agents/MsgListener.java
@@ -0,0 +1,16 @@
+package middleware.agents;
+
+/**
+ *
+ * @author JLScott1999
+ */
+public interface MsgListener
+{
+ /**
+ *
+ * @param sender
+ * @param msg
+ */
+ void UserAgentMsg(String sender, String msg);
+
+}
diff --git a/src/middleware/agents/Portal.java b/src/middleware/agents/Portal.java
new file mode 100644
index 0000000..db9357c
--- /dev/null
+++ b/src/middleware/agents/Portal.java
@@ -0,0 +1,110 @@
+package middleware.agents;
+
+import java.util.HashMap;
+import middleware.message.MetaAgentMessage;
+import middleware.message.SystemErrorMessage;
+import middleware.message.UserMessage;
+import middleware.message.wrapper.MetaAgentWrapper;
+
+/**
+ * MetaAgent Portal, for allowing connection between UserAgents and portals
+ *
+ * @author JLScott1999
+ */
+public class Portal extends MetaAgent
+{
+
+ private HashMap routingTable = new HashMap();
+
+ /**
+ * Creates instance of Portal with specified properties
+ * @param queueSize size of blocking queue
+ * @param address address of MetaAgent
+ */
+ public Portal(int queueSize, String address)
+ {
+ super(queueSize, address);
+ }
+
+ /**
+ * Adds a message to the queue
+ * @param e message
+ * @return success
+ */
+ @Override
+ public boolean add(Object e)
+ {
+ if (e instanceof UserMessage)
+ {
+ return super.add(MetaAgentWrapper.wrap((UserMessage) e, 15));
+ }
+ else if (e instanceof MetaAgentMessage)
+ {
+ return super.add(e);
+ }
+ return false;
+ }
+
+ /**
+ * Message handler - handles messages passed to it
+ * @param data the passed message
+ */
+ @Override
+ public void msgHandler(Object data)
+ {
+ if (data instanceof MetaAgentMessage)
+ {
+ MetaAgentMessage MAM = (MetaAgentMessage) data;
+ try
+ {
+ routingTable.get(MAM.getMessage().getRecipient().getAddress()).recieveMsg(MetaAgentWrapper.unwrap((MetaAgentMessage) data));
+ super.updateObservers(data);
+ }
+ catch (Exception e)
+ {
+ if (MAM.timeToLive > 0)
+ {
+ MAM.decreaseTimeToLive();
+ MAM.increaseHops();
+ super.msgHandler(MAM);
+ }
+ else
+ {
+ if (!MAM.getMessage().getSender().getAddress().equals("0.0.0"))
+ {
+ super.msgHandler(MetaAgentWrapper.wrap(new SystemErrorMessage(MAM.getMessage().getRecipient().getAddress() + " Does not exist?", MAM.getMessage().getSender().getAddress()), 15));
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Called when requested user agent is not found
+ * @param agent message without valid recipient
+ */
+ private void NoUserAgentFound(MetaAgentMessage agent)
+ {
+ try
+ {
+ routingTable.get(agent.getMessage().getSender()).recieveMsg(new SystemErrorMessage(agent.getMessage().getRecipient() + " Does not exist?", agent.getMessage().getSender().getAddress()));
+ }
+ catch (Exception e2)
+ {
+ super.msgHandler(MetaAgentWrapper.wrap(new SystemErrorMessage(agent.getMessage().getRecipient() + " Does not exist?", agent.getMessage().getSender().getAddress()), Integer.MAX_VALUE));
+ }
+ }
+
+ /**
+ * Allows for communication between MetaAgents
+ * Adds a MetaAgent
+ * @param agent
+ */
+ public void addAgent(UserAgent agent)
+ {
+ // TODO Generate random address
+ routingTable.put(agent.getAddress(), agent);
+ agent.setMetaAgent(this);
+ }
+
+}
\ No newline at end of file
diff --git a/src/middleware/agents/Router.java b/src/middleware/agents/Router.java
new file mode 100644
index 0000000..373d203
--- /dev/null
+++ b/src/middleware/agents/Router.java
@@ -0,0 +1,123 @@
+package middleware.agents;
+
+import java.io.IOException;
+import java.net.Inet4Address;
+import java.net.UnknownHostException;
+import java.util.HashMap;
+import middleware.message.MetaAgentMessage;
+import middleware.message.SystemErrorMessage;
+import middleware.message.UserMessage;
+import middleware.message.wrapper.MetaAgentWrapper;
+import middleware.socket.Client;
+import middleware.socket.Server;
+
+/**
+ * MetaAgent for Routers allowing for communication between different routers
+ *
+ */
+public class Router extends MetaAgent {
+
+ int port;
+ Inet4Address ipAddress;
+ private Server listener;
+ private HashMap sender = new HashMap();
+
+ /**
+ * Creates a new instance of MetaAgent Router with given properties
+ * @param queueSize size of blocking queue
+ * @param address router address
+ * @param ipAddressIn ip address
+ * @param portIn port
+ * @throws java.net.UnknownHostException
+ */
+ public Router(int queueSize, String address, int portIn) throws UnknownHostException {
+ super(queueSize, address);
+ ipAddress = (Inet4Address) Inet4Address.getByName(address);
+ port = portIn;
+ listener = new Server(portIn, this);
+ try
+ {
+ listener.create();
+ listener.enableListening();
+ } catch (IOException ex)
+ {
+ ex.printStackTrace();
+ }
+ }
+
+ /**
+ * Adds a message to the queue
+ * @param e message
+ * @return success
+ */
+ @Override
+ public boolean add(Object e)
+ {
+ if (e instanceof UserMessage)
+ {
+ return super.add(MetaAgentWrapper.wrap((UserMessage) e, 15));
+ }
+ else if (e instanceof MetaAgentMessage)
+ {
+ return super.add(e);
+ }
+ return false;
+ }
+
+ /**
+ * Creates a connection using specified parameters
+ * @param addressString
+ * @param address
+ * @param port
+ */
+ public void connect(String addressString, String address, int port)
+ {
+ Client client = new Client(address, port);
+ System.out.println(address + " + " + port);
+ sender.put(addressString, client);
+ try
+ {
+ client.connect();
+ } catch (IOException ex)
+ {
+ ex.printStackTrace();
+ }
+
+ }
+
+ /**
+ * Handles message objects passed to it
+ * @param data message
+ */
+ @Override
+ public void msgHandler(Object data)
+ {
+ if (data instanceof MetaAgentMessage)
+ {
+ MetaAgentMessage MAM = (MetaAgentMessage) data;
+ try
+ {
+ sender.get(MAM.getMessage().getRecipient().getSection(1) + ".0.0").send((MetaAgentMessage) data);
+ super.updateObservers(data);
+ }
+ catch (Exception e)
+ {
+ if (MAM.timeToLive > 0)
+ {
+ MAM.decreaseTimeToLive();
+ MAM.increaseHops();
+ super.msgHandler(MAM);
+ }
+ else
+ {
+ if (!MAM.getMessage().getSender().getAddress().equals("0.0.0"))
+ {
+ super.msgHandler(MetaAgentWrapper.wrap(new SystemErrorMessage(MAM.getMessage().getRecipient().getAddress() + " Does not exist?", MAM.getMessage().getSender().getAddress()), 15));
+ }
+ }
+
+ }
+ }
+ }
+
+}
diff --git a/src/middleware/agents/UserAgent.java b/src/middleware/agents/UserAgent.java
new file mode 100644
index 0000000..2fe08ab
--- /dev/null
+++ b/src/middleware/agents/UserAgent.java
@@ -0,0 +1,76 @@
+package middleware.agents;
+
+import java.util.ArrayList;
+import middleware.message.Message;
+import middleware.message.UserMessage;
+
+/**
+ * Agent for a user/node/endpoint
+ * @author JLScott1999
+ */
+public class UserAgent
+{
+ private String address;
+ private MetaAgent metaAgent;
+ private ArrayList listeners = new ArrayList();
+
+ /**
+ * Creates an instance of UserAgent with a specified address
+ * @param address Specified address
+ */
+ public UserAgent(String address)
+ {
+ this.address = address;
+ }
+
+ /**
+ * Returns the UserAgent's address
+ * @return address
+ */
+ public String getAddress()
+ {
+ return address;
+ }
+
+ /**
+ * Used to wrap and send a message to a recipient
+ * @param sender the sender
+ * @param recipient the message recipient
+ * @param message the message content to be sent
+ */
+ public void sendMsg(String sender, String recipient, String message)
+ {
+ metaAgent.add(new UserMessage(message, recipient, sender, false, "???", "0"));
+ }
+
+ /**
+ * Set's the UserAgent's MetaAgent (e.g. the portal it belongs to)
+ * @param metaAgent metaAgent to be assigned
+ */
+ public void setMetaAgent(MetaAgent metaAgent)
+ {
+ this.metaAgent = metaAgent;
+ }
+
+ /**
+ * Used by msgHandler to receive message
+ * @param data message received
+ */
+ public void recieveMsg(Message data)
+ {
+ for (MsgListener listener : listeners)
+ {
+ listener.UserAgentMsg(data.getSender().getAddress().toString(), data.getMessage().toString());
+ }
+ }
+
+ /**
+ * Adds a message listener to the UserAgent
+ * @param listener Message Listener
+ */
+ public void addListener(MsgListener listener)
+ {
+ listeners.add(listener);
+ }
+
+}
\ No newline at end of file
diff --git a/src/middleware/agents/package-info.java b/src/middleware/agents/package-info.java
new file mode 100644
index 0000000..f9d7b8e
--- /dev/null
+++ b/src/middleware/agents/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * Contains classes for the Middleware agents
+ */
+package middleware.agents;
diff --git a/src/middleware/components/main/MainUI.java b/src/middleware/components/main/MainUI.java
new file mode 100644
index 0000000..6e67c3c
--- /dev/null
+++ b/src/middleware/components/main/MainUI.java
@@ -0,0 +1,51 @@
+package middleware.components.main;
+
+import java.awt.BorderLayout;
+import java.awt.Dimension;
+import javax.swing.JFrame;
+import javax.swing.JScrollPane;
+import middleware.components.main.nodelistener.NodeListener;
+import middleware.components.main.nodeview.NodeView;
+
+/**
+ * The Main GUI form
+ *
+ * @author Dan Lawrence
+ */
+public class MainUI extends JFrame {
+
+ NodeView nodeView;
+
+ NodeListener nodeListener;
+
+ /**
+ * Creates the Main UI
+ */
+ public MainUI() {
+ setUpComponent();
+ }
+
+ /**
+ * Sets up all GUI components for the main GUI
+ */
+ private void setUpComponent() {
+ nodeListener = new NodeListener();
+
+ nodeView = new NodeView(nodeListener);
+ add(nodeView, BorderLayout.WEST);
+
+ JScrollPane nodeListenerScroller = new JScrollPane(nodeListener);
+ nodeListenerScroller.setPreferredSize(new Dimension(880,200));
+
+ add(nodeListenerScroller,BorderLayout.EAST);
+
+ setTitle("Middleware");
+
+ setResizable(false);
+
+ setDefaultCloseOperation(3);
+ setVisible(true);
+
+ pack();
+ }
+}
diff --git a/src/middleware/components/main/nodelistener/NodeListener.java b/src/middleware/components/main/nodelistener/NodeListener.java
new file mode 100644
index 0000000..89a7b20
--- /dev/null
+++ b/src/middleware/components/main/nodelistener/NodeListener.java
@@ -0,0 +1,101 @@
+
+package middleware.components.main.nodelistener;
+
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import javax.swing.JTable;
+import javax.swing.table.DefaultTableModel;
+
+/**
+ * Used to display output from a NodeMonitor
+ *
+ * @author Dan Lawrence
+ */
+public class NodeListener extends JTable {
+ DefaultTableModel model;
+
+ /**
+ * Sets up GUI components for NodeListener
+ */
+ public NodeListener() {
+ setUpComponent();
+ }
+
+ private void setUpComponent() {
+ //TTL: Time to live
+ String[] headings = {"Time sent/received","Sender","Receiver","Message","TTL","Hops"};
+
+ model = new DefaultTableModel(headings,0) {
+ @Override
+ public boolean isCellEditable(int row, int column) {
+ return false;
+ }
+ };
+
+ setModel(model);
+
+ setFocusable(false);
+ setRowSelectionAllowed(false);
+
+ getColumnModel().getColumn(0).setPreferredWidth(130);
+ getColumnModel().getColumn(0).setMaxWidth(130);
+ getColumnModel().getColumn(0).setMinWidth(130);
+ getColumnModel().getColumn(0).setResizable(false);
+
+ getColumnModel().getColumn(1).setPreferredWidth(100);
+ getColumnModel().getColumn(1).setMaxWidth(100);
+ getColumnModel().getColumn(1).setMinWidth(100);
+ getColumnModel().getColumn(1).setResizable(false);
+
+ getColumnModel().getColumn(2).setPreferredWidth(100);
+ getColumnModel().getColumn(2).setMaxWidth(100);
+ getColumnModel().getColumn(2).setMinWidth(100);
+ getColumnModel().getColumn(2).setResizable(false);
+
+ getColumnModel().getColumn(3).setMinWidth(450);
+ getColumnModel().getColumn(3).setResizable(true);
+
+ getColumnModel().getColumn(4).setPreferredWidth(50);
+ getColumnModel().getColumn(4).setMaxWidth(50);
+ getColumnModel().getColumn(4).setMinWidth(50);
+ getColumnModel().getColumn(4).setResizable(false);
+
+ getColumnModel().getColumn(5).setPreferredWidth(50);
+ getColumnModel().getColumn(5).setMaxWidth(50);
+ getColumnModel().getColumn(5).setMinWidth(50);
+ getColumnModel().getColumn(5).setResizable(false);
+
+ setRowHeight(20);
+
+ setVisible(true);
+ setOpaque(true);
+ }
+
+ /**
+ * Adds a row to the NodeListener Table, using unwrapped message parameters
+ * @param message message content
+ * @param sender sender
+ * @param recipient recipient
+ * @param ttl Time To Live (TTL)
+ * @param hops message hops
+ */
+ public void addRow(String message, String sender, String recipient, int ttl, int hops) {
+ Object[] tableRow = new Object[6];
+
+ tableRow[0] = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss").format(Calendar.getInstance().getTime());
+ tableRow[1] = sender;
+ tableRow[2] = recipient;
+ tableRow[3] = message;
+ tableRow[4] = ttl;
+ tableRow[5] = hops;
+
+ model.addRow(tableRow);
+ }
+
+ /**
+ * Clears NodeListenerTable
+ */
+ public void clear() {
+ model.setRowCount(0);
+ }
+}
diff --git a/src/middleware/components/main/nodelistener/package-info.java b/src/middleware/components/main/nodelistener/package-info.java
new file mode 100644
index 0000000..6317e83
--- /dev/null
+++ b/src/middleware/components/main/nodelistener/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * Contains the classes for the NodeListener
+ */
+package middleware.components.main.nodelistener;
diff --git a/src/middleware/components/main/nodeview/NodeTree.java b/src/middleware/components/main/nodeview/NodeTree.java
new file mode 100644
index 0000000..b6f469f
--- /dev/null
+++ b/src/middleware/components/main/nodeview/NodeTree.java
@@ -0,0 +1,207 @@
+
+package middleware.components.main.nodeview;
+
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+import java.net.UnknownHostException;
+import java.util.HashMap;
+import javax.swing.JTree;
+import javax.swing.tree.DefaultMutableTreeNode;
+import javax.swing.tree.DefaultTreeModel;
+import middleware.agents.MetaAgent;
+import middleware.agents.Portal;
+import middleware.agents.Router;
+import middleware.agents.UserAgent;
+import middleware.components.main.nodelistener.NodeListener;
+import middleware.components.useragents.UserAgentUI;
+import middleware.nodemonitor.NodeMonitor;
+
+/**
+ * GUI for NodeTrees
+ *
+ * @author Dan Lawrence
+ */
+public class NodeTree extends JTree implements MouseListener {
+
+ DefaultTreeModel model;
+ DefaultMutableTreeNode rootNode;
+ NodeListener nodeListener;
+
+ NodeMonitor nm;
+ MetaAgent nmMetaAgent;
+
+ HashMap MetaAgentMap = new HashMap();
+ HashMap UserAgentMap = new HashMap();
+
+ int id = 1;
+ Router router = null;
+
+ /**
+ * Sets up a NodeTree GUI for given NodeListener
+ * @param nodeListenerIn NodeListener
+ */
+ public NodeTree(NodeListener nodeListenerIn) {
+ nodeListener = nodeListenerIn;
+
+ setUpComponent();
+ }
+
+ private void setUpComponent() {
+ rootNode = new DefaultMutableTreeNode("Agents");
+ model = new DefaultTreeModel(rootNode);
+
+ addPortal();
+
+ setModel(model);
+
+ setVisible(true);
+
+ this.addMouseListener(this);
+ }
+
+ /**
+ * Adds a Router to the nodetree
+ * @param ipAddress ip address of router
+ * @param port router port
+ * @return index of new router
+ * @throws UnknownHostException
+ */
+ public int addRouter(int id, String ipAddress, int port) throws UnknownHostException {
+ DefaultMutableTreeNode routerNode = new DefaultMutableTreeNode();
+ rootNode.add(routerNode);
+
+ if (router == null)
+ {
+ router = new Router(10, (rootNode.getIndex(routerNode) + id) + ".0.0", port);
+ router.start();
+ MetaAgentMap.put(router.getAddress().getAddress(), router);
+ }
+ else
+ {
+ router.connect(id + ".0.0", ipAddress, port);
+ }
+ this.id = id;
+ routerNode.setUserObject("Router (" + id + ".0.0)");
+ updateUI();
+
+ return rootNode.getIndex(routerNode) + 1;
+ }
+
+ /**
+ * Adds a new portal to the NodeTree
+ * @return index of the new portal
+ */
+ public int addPortal() {
+ if (getSelectionPath() == null)
+ return 0;
+
+ DefaultMutableTreeNode selectedNode =
+ (DefaultMutableTreeNode) getSelectionPath().getLastPathComponent();
+
+ String nodeName = (String) selectedNode.getUserObject();
+
+ if (selectedNode.isRoot() || !nodeName.contains("Router"))
+ return 0;
+
+ DefaultMutableTreeNode portalNode = new DefaultMutableTreeNode();
+ selectedNode.add(portalNode);
+
+ // Add Portals Here
+ Portal p = new Portal(10, id + "." + (selectedNode.getIndex(portalNode) + 1) + ".0");
+ p.start();
+ MetaAgentMap.get(String.valueOf(id + ".0.0")).addAgent(p);
+ MetaAgentMap.values().forEach((metaAgent) -> {
+ if (metaAgent instanceof Portal)
+ {
+ metaAgent.addAgent(p);
+ }
+ });
+ MetaAgentMap.put(p.getAddress().getAddress(), p);
+ portalNode.setUserObject("Portal (" + p.getAddress() + ")");
+
+ updateUI();
+
+ return rootNode.getIndex(portalNode) + 1;
+ }
+
+ /**
+ * Adds a new user agent to the NodeTree
+ * @return index of new UserAgent
+ */
+ public int addUserAgent() {
+ if (getSelectionPath() == null)
+ return 0;
+
+ DefaultMutableTreeNode selectedNode =
+ (DefaultMutableTreeNode) getSelectionPath().getLastPathComponent();
+
+ String nodeName = (String) selectedNode.getUserObject();
+
+ if (selectedNode.isRoot() || !nodeName.contains("Portal"))
+ return 0;
+
+ DefaultMutableTreeNode userAgentNode = new DefaultMutableTreeNode();
+ selectedNode.add(userAgentNode);
+
+ UserAgent userAgent = new UserAgent((id) + "."
+ + (selectedNode.getParent().getIndex(selectedNode) + 1) + "."
+ + (selectedNode.getIndex(userAgentNode) + 1));
+ ((Portal) MetaAgentMap.get(id + "."
+ + (selectedNode.getParent().getIndex(selectedNode)+ 1)
+ + ".0")).addAgent(userAgent);
+ UserAgentMap.put(userAgent.getAddress(), userAgent);
+
+ userAgentNode.setUserObject("User Agent (" + userAgent.getAddress() + ")" );
+
+ updateUI();
+
+ return rootNode.getIndex(userAgentNode) + 1;
+ }
+
+ @Override
+ public void mouseClicked(MouseEvent e) {
+ if (e.getClickCount()==2 && getSelectionPath() != null) {
+ DefaultMutableTreeNode selectedNode =
+ (DefaultMutableTreeNode) getSelectionPath().getLastPathComponent();
+
+ String nodeName = (String) selectedNode.getUserObject();
+
+ if (nodeName.contains("Router") || nodeName.contains("Portal")) {
+ if (nm != null && nmMetaAgent != null)
+ {
+ nmMetaAgent.detach(nm);
+ }
+
+ nodeListener.clear();
+ //Get Portal
+ MetaAgent metaAgent = MetaAgentMap.get(nodeName.substring(nodeName.indexOf("(") + 1, nodeName.length() - 1));
+ //Attach NodeMonitor
+ nm = new NodeMonitor(nodeListener);
+ metaAgent.attach(nm);
+ nmMetaAgent = metaAgent;
+ } else if (nodeName.contains("User Agent")) {
+ new UserAgentUI(UserAgentMap.get(nodeName.substring(nodeName.indexOf("(") + 1, nodeName.length()-1)));
+ }
+ }
+ }
+
+ @Override
+ public void mousePressed(MouseEvent e) {
+ //Useless.
+ }
+
+ @Override
+ public void mouseReleased(MouseEvent e) {
+ //Useless.
+ }
+
+ @Override
+ public void mouseEntered(MouseEvent e) {
+ //Useless.
+ }
+
+ @Override
+ public void mouseExited(MouseEvent e) {
+ //Useless.
+ }
+}
diff --git a/src/middleware/components/main/nodeview/NodeView.java b/src/middleware/components/main/nodeview/NodeView.java
new file mode 100644
index 0000000..a3e86a3
--- /dev/null
+++ b/src/middleware/components/main/nodeview/NodeView.java
@@ -0,0 +1,41 @@
+package middleware.components.main.nodeview;
+
+import java.awt.Dimension;
+import javax.swing.BoxLayout;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import middleware.components.main.nodelistener.NodeListener;
+import middleware.components.main.nodeview.controls.ControlPane;
+
+/**
+ * NodeView
+ * Used to display the NodeTree
+ *
+ * @author Dan Lawrence
+ */
+public class NodeView extends JPanel {
+
+ /**
+ * Creates an instance of NodeView, with an attached NodeListener
+ * @param nodeListenerIn nodelistener used to feed data to the view
+ */
+ public NodeView(NodeListener nodeListenerIn) {
+ setUpComponent(nodeListenerIn);
+ }
+
+ private void setUpComponent(NodeListener nodeListenerIn) {
+ setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));
+
+ NodeTree nodeTree = new NodeTree(nodeListenerIn);
+ JScrollPane nodeTreePane = new JScrollPane (nodeTree);
+ nodeTreePane.setPreferredSize(new Dimension(200,400));
+
+ add(nodeTreePane);
+
+ ControlPane controlPane = new ControlPane(nodeTree);
+
+ add(controlPane);
+
+ setVisible(true);
+ }
+}
diff --git a/src/middleware/components/main/nodeview/controls/ControlPane.java b/src/middleware/components/main/nodeview/controls/ControlPane.java
new file mode 100644
index 0000000..75b3ad6
--- /dev/null
+++ b/src/middleware/components/main/nodeview/controls/ControlPane.java
@@ -0,0 +1,45 @@
+package middleware.components.main.nodeview.controls;
+
+import java.awt.Dimension;
+import javax.swing.JPanel;
+import middleware.components.main.nodeview.NodeTree;
+
+/**
+ * Control Pane
+ * Handles GUI components for controls of the Node Tree
+ *
+ * @author Dan Lawrence
+ */
+public class ControlPane extends JPanel {
+
+ RouterButton routerButton;
+
+ PortalButton portalButton;
+
+ UserAgentButton userAgentButton;
+
+ /**
+ * Creates an instance of ControlPane, attached to a NodeTree
+ * @param nodeTreeIn nodetree which the controls control
+ */
+ public ControlPane(NodeTree nodeTreeIn) {
+ routerButton = new RouterButton(nodeTreeIn);
+
+ portalButton = new PortalButton(nodeTreeIn);
+
+ userAgentButton = new UserAgentButton(nodeTreeIn);
+ setUpComponent();
+ }
+
+ private void setUpComponent() {
+ add(routerButton);
+
+ add(portalButton);
+
+ add(userAgentButton);
+
+ setPreferredSize(new Dimension(200,80));
+
+ setVisible(true);
+ }
+}
diff --git a/src/middleware/components/main/nodeview/controls/PortalButton.java b/src/middleware/components/main/nodeview/controls/PortalButton.java
new file mode 100644
index 0000000..d52be16
--- /dev/null
+++ b/src/middleware/components/main/nodeview/controls/PortalButton.java
@@ -0,0 +1,47 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package middleware.components.main.nodeview.controls;
+
+import java.awt.Dimension;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import javax.swing.JButton;
+import middleware.components.main.nodeview.NodeTree;
+
+/**
+ * PortalButton
+ * Button used to create portals and add them to the NodeTree
+ */
+public class PortalButton extends JButton implements ActionListener {
+
+ NodeTree nodeTree;
+
+ /**
+ * Creates an instance of PortalButton and sets up its components
+ * @param nodeTreeIn attached nodeTree
+ */
+ public PortalButton(NodeTree nodeTreeIn) {
+ nodeTree = nodeTreeIn;
+
+ setUpComponent();
+ }
+
+ private void setUpComponent() {
+ setText("Add Portal");
+
+ setPreferredSize(new Dimension(190,20));
+
+ setVisible(true);
+
+ addActionListener(this);
+ }
+
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ if (e.getSource() == this)
+ nodeTree.addPortal();
+ }
+}
diff --git a/src/middleware/components/main/nodeview/controls/RouterButton.java b/src/middleware/components/main/nodeview/controls/RouterButton.java
new file mode 100644
index 0000000..c431e07
--- /dev/null
+++ b/src/middleware/components/main/nodeview/controls/RouterButton.java
@@ -0,0 +1,64 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package middleware.components.main.nodeview.controls;
+
+import java.awt.Dimension;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.net.UnknownHostException;
+import javax.swing.JButton;
+import javax.swing.JOptionPane;
+import middleware.components.main.nodeview.NodeTree;
+
+/**
+ * RouterButton
+ * Button used to create and add routers to a NodeTree
+ *
+ */
+public class RouterButton extends JButton implements ActionListener {
+
+ NodeTree nodeTree;
+
+ /**
+ * Creates and sets up button, attached to specified NodeTree
+ * @param nodeTreeIn NodeTree
+ */
+ public RouterButton(NodeTree nodeTreeIn) {
+ nodeTree = nodeTreeIn;
+
+ setUpComponent();
+ }
+
+ private void setUpComponent() {
+ setText("Add Router");
+
+ setPreferredSize(new Dimension(190,20));
+
+ setVisible(true);
+
+ addActionListener(this);
+ }
+
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ if (e.getSource() == this) {
+ String id = (String) JOptionPane.showInputDialog(null, "Router ID", "Set Router ID", JOptionPane.PLAIN_MESSAGE, null, null, "");
+ String ipAddress = (String) JOptionPane.showInputDialog(null, "IP Address", "Add Router", JOptionPane.PLAIN_MESSAGE, null, null, "");
+ String port = (String) JOptionPane.showInputDialog(null, "Port", "Add Router", JOptionPane.PLAIN_MESSAGE, null, null, "");
+
+ try
+ {
+ nodeTree.addRouter(Integer.parseInt(id), ipAddress, Integer.parseInt(port));
+ //nodeTree.addRouter(Integer.parseInt(id), ipAddress, Integer.parseInt(port));
+ }
+ catch (UnknownHostException | NumberFormatException ex)
+ {
+ ex.printStackTrace();
+ }
+ }
+ }
+
+}
diff --git a/src/middleware/components/main/nodeview/controls/UserAgentButton.java b/src/middleware/components/main/nodeview/controls/UserAgentButton.java
new file mode 100644
index 0000000..317d380
--- /dev/null
+++ b/src/middleware/components/main/nodeview/controls/UserAgentButton.java
@@ -0,0 +1,49 @@
+
+package middleware.components.main.nodeview.controls;
+
+import java.awt.Dimension;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import javax.swing.JButton;
+import middleware.components.main.nodeview.NodeTree;
+
+/**
+ * UserAgentButton
+ * Creates and adds user agents to a node tree
+ *
+ * @author Dan Lawrence
+ */
+public class UserAgentButton extends JButton implements ActionListener{
+
+ NodeTree nodeTree;
+
+ /**
+ * Creates button to add User Agents to a node tree
+ * @param nodeTreeIn
+ */
+ public UserAgentButton(NodeTree nodeTreeIn) {
+ nodeTree = nodeTreeIn;
+
+ setUpComponent();
+ }
+
+ private void setUpComponent() {
+ setText("Add User Agent");
+
+ setPreferredSize(new Dimension(190,20));
+
+ setVisible(true);
+
+ addActionListener(this);
+ }
+
+ /**
+ * When an action is performed, adds useragent to nodetree
+ * @param e
+ */
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ if (e.getSource() == this)
+ nodeTree.addUserAgent();
+ }
+}
diff --git a/src/middleware/components/main/nodeview/controls/package-info.java b/src/middleware/components/main/nodeview/controls/package-info.java
new file mode 100644
index 0000000..84d1ca7
--- /dev/null
+++ b/src/middleware/components/main/nodeview/controls/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * Contains the controls for the nodeview GUI
+ */
+package middleware.components.main.nodeview.controls;
diff --git a/src/middleware/components/main/nodeview/package-info.java b/src/middleware/components/main/nodeview/package-info.java
new file mode 100644
index 0000000..7554650
--- /dev/null
+++ b/src/middleware/components/main/nodeview/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * Contains the classes for the NodeView GUI
+ */
+package middleware.components.main.nodeview;
diff --git a/src/middleware/components/main/package-info.java b/src/middleware/components/main/package-info.java
new file mode 100644
index 0000000..1455b2b
--- /dev/null
+++ b/src/middleware/components/main/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * The main interface for the Middleware project
+ */
+package middleware.components.main;
diff --git a/src/middleware/components/useragents/UserAgentUI.java b/src/middleware/components/useragents/UserAgentUI.java
new file mode 100644
index 0000000..852db1c
--- /dev/null
+++ b/src/middleware/components/useragents/UserAgentUI.java
@@ -0,0 +1,68 @@
+
+package middleware.components.useragents;
+
+import java.awt.BorderLayout;
+import java.awt.Dimension;
+import javax.swing.JFrame;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import middleware.agents.MsgListener;
+import middleware.agents.UserAgent;
+import middleware.components.useragents.messagefeed.MessageFeed;
+import middleware.components.useragents.messagesending.MessageSender;
+
+/**
+ * The GUI for UserAgents
+ *
+ * @author Dan Lawrence
+ */
+public class UserAgentUI extends JFrame implements MsgListener
+{
+
+ private final MessageSender messageSender;
+ private final MessageFeed messageFeed;
+ private final UserAgent userAgent;
+
+ /**
+ * Sets up GUI for a UserAgent
+ * @param userAgent specified UserAgent
+ */
+ public UserAgentUI(UserAgent userAgent) {
+ messageFeed = new MessageFeed();
+ this.userAgent = userAgent;
+ messageSender = new MessageSender(userAgent, messageFeed);
+ userAgent.addListener(this);
+ setUpComponent();
+ }
+
+ private void setUpComponent() {
+ setTitle("User Agent - " + userAgent.getAddress().toUpperCase());
+
+ setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
+ setVisible(true);
+
+ JPanel padding1 = new JPanel();
+ padding1.setPreferredSize(new Dimension(10,0));
+
+ JPanel padding2 = new JPanel();
+ padding2.setPreferredSize(new Dimension(10,0));
+
+ add(padding1, BorderLayout.WEST);
+ add(padding2, BorderLayout.EAST);
+
+ JScrollPane messageFeedScroller = new JScrollPane(messageFeed);
+ messageFeedScroller.setPreferredSize(new Dimension(780,200));
+
+ add(messageFeedScroller, BorderLayout.CENTER);
+ add(messageSender, BorderLayout.SOUTH);
+
+ pack();
+ setMinimumSize(getSize());
+ }
+
+ @Override
+ public void UserAgentMsg(String sender, String msg)
+ {
+ messageFeed.addRow(msg, sender.toUpperCase(), userAgent.getAddress().toUpperCase());
+ }
+}
diff --git a/src/middleware/components/useragents/messagefeed/MessageFeed.java b/src/middleware/components/useragents/messagefeed/MessageFeed.java
new file mode 100644
index 0000000..6763c53
--- /dev/null
+++ b/src/middleware/components/useragents/messagefeed/MessageFeed.java
@@ -0,0 +1,83 @@
+package middleware.components.useragents.messagefeed;
+
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import javax.swing.JTable;
+import javax.swing.table.DefaultTableModel;
+
+/**
+ * MessageFeed for UserAgents
+ *
+ * @author Dan Lawrence
+ */
+public class MessageFeed extends JTable {
+
+ DefaultTableModel model;
+
+ /**
+ * Sets up GUI for MessageFeed
+ */
+ public MessageFeed() {
+ setUpComponent();
+ }
+
+ private void setUpComponent() {
+ String[] headings = {"Time sent/received","Sender","Receiver","Message"};
+
+ model = new DefaultTableModel(headings,0) {
+ @Override
+ public boolean isCellEditable(int row, int column) {
+ return false;
+ }
+ };
+
+ setModel(model);
+
+ setFocusable(false);
+ setRowSelectionAllowed(false);
+
+ getColumnModel().getColumn(0).setPreferredWidth(130);
+ getColumnModel().getColumn(0).setMaxWidth(130);
+ getColumnModel().getColumn(0).setMinWidth(130);
+ getColumnModel().getColumn(0).setResizable(false);
+ getColumnModel().getColumn(0).setHeaderValue("Time sent/received");
+
+ getColumnModel().getColumn(1).setPreferredWidth(100);
+ getColumnModel().getColumn(1).setMaxWidth(100);
+ getColumnModel().getColumn(1).setMinWidth(100);
+ getColumnModel().getColumn(1).setResizable(false);
+ getColumnModel().getColumn(1).setHeaderValue("Sender");
+
+ getColumnModel().getColumn(2).setPreferredWidth(100);
+ getColumnModel().getColumn(2).setMaxWidth(100);
+ getColumnModel().getColumn(2).setMinWidth(100);
+ getColumnModel().getColumn(2).setResizable(false);
+ getColumnModel().getColumn(2).setHeaderValue("Receiver");
+
+ getColumnModel().getColumn(3).setMinWidth(450);
+ getColumnModel().getColumn(3).setResizable(true);
+ getColumnModel().getColumn(3).setHeaderValue("Message");
+
+ setRowHeight(20);
+
+ setVisible(true);
+ setOpaque(true);
+ }
+
+ /**
+ * Adds a row to the table containing specified data
+ * @param message message content
+ * @param sender sender agent address
+ * @param recipient recipient agent address
+ */
+ public void addRow(String message, String sender, String recipient) {
+ Object[] tableRow = new Object[4];
+
+ tableRow[0] = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss").format(Calendar.getInstance().getTime());
+ tableRow[1] = sender;
+ tableRow[2] = recipient;
+ tableRow[3] = message;
+
+ model.addRow(tableRow);
+ }
+}
diff --git a/src/middleware/components/useragents/messagefeed/package-info.java b/src/middleware/components/useragents/messagefeed/package-info.java
new file mode 100644
index 0000000..449c65b
--- /dev/null
+++ b/src/middleware/components/useragents/messagefeed/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * Contains the MessageFeed for the UserAgents GUI
+ */
+package middleware.components.useragents.messagefeed;
diff --git a/src/middleware/components/useragents/messagesending/MessageBox.java b/src/middleware/components/useragents/messagesending/MessageBox.java
new file mode 100644
index 0000000..9995bf9
--- /dev/null
+++ b/src/middleware/components/useragents/messagesending/MessageBox.java
@@ -0,0 +1,43 @@
+
+package middleware.components.useragents.messagesending;
+
+import java.awt.Dimension;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import javax.swing.JTextField;
+
+/**
+ * MessageBox. A text field used to type a string message, with the intend to
+ * send that message to another user.
+ *
+ * @author Dan Lawrence
+ */
+public class MessageBox extends JTextField implements ActionListener {
+
+ RecipientBox recipientBox;
+
+ SendButton sendButton;
+
+ /**
+ * Constructor.
+ */
+ public MessageBox(RecipientBox recipientBoxIn) {
+ recipientBox = recipientBoxIn;
+
+ setUpComponent();
+ }
+
+ private void setUpComponent() {
+ setPreferredSize(new Dimension(500,20));
+ setVisible(true);
+ setOpaque(true);
+
+ addActionListener(this);
+ }
+
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ if (!getText().equals("") && !recipientBox.getText().equals(""))
+ sendButton.sendMessage();
+ }
+}
diff --git a/src/middleware/components/useragents/messagesending/MessageSender.java b/src/middleware/components/useragents/messagesending/MessageSender.java
new file mode 100644
index 0000000..e6a80aa
--- /dev/null
+++ b/src/middleware/components/useragents/messagesending/MessageSender.java
@@ -0,0 +1,37 @@
+
+package middleware.components.useragents.messagesending;
+
+import javax.swing.JPanel;
+import middleware.agents.UserAgent;
+import middleware.components.useragents.messagefeed.MessageFeed;
+
+/**
+ * MessageSender.
+ *
+ * @author Dan Lawrence
+ */
+public class MessageSender extends JPanel {
+
+ final RecipientBox recipientBox;
+
+ final MessageBox messageBox;
+
+ final SendButton sendButton;
+
+ public MessageSender(UserAgent userAgent, MessageFeed messageFeedIn) {
+ recipientBox = new RecipientBox();
+ messageBox = new MessageBox(recipientBox);
+ sendButton = new SendButton(userAgent, recipientBox,messageBox,messageFeedIn);
+
+ setUpComponent();
+ }
+
+ private void setUpComponent() {
+ setVisible(true);
+
+ add(recipientBox);
+ add(messageBox);
+ add(sendButton);
+ }
+
+}
diff --git a/src/middleware/components/useragents/messagesending/RecipientBox.java b/src/middleware/components/useragents/messagesending/RecipientBox.java
new file mode 100644
index 0000000..be1a066
--- /dev/null
+++ b/src/middleware/components/useragents/messagesending/RecipientBox.java
@@ -0,0 +1,23 @@
+
+package middleware.components.useragents.messagesending;
+
+import java.awt.Dimension;
+import javax.swing.JTextField;
+
+/**
+ * RecipientBox.
+ *
+ * @author Dan Lawrence
+ */
+public class RecipientBox extends JTextField {
+
+ public RecipientBox() {
+ setUpComponent();
+ }
+
+ private void setUpComponent() {
+ setPreferredSize(new Dimension(170,20));
+ setVisible(true);
+ setOpaque(true);
+ }
+}
diff --git a/src/middleware/components/useragents/messagesending/SendButton.java b/src/middleware/components/useragents/messagesending/SendButton.java
new file mode 100644
index 0000000..0954483
--- /dev/null
+++ b/src/middleware/components/useragents/messagesending/SendButton.java
@@ -0,0 +1,74 @@
+
+package middleware.components.useragents.messagesending;
+
+import java.awt.Dimension;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import javax.swing.JButton;
+import middleware.agents.UserAgent;
+import middleware.components.useragents.messagefeed.MessageFeed;
+
+/**
+ * SendButton.
+ *
+ * @author Dan Lawrence
+ */
+public class SendButton extends JButton implements ActionListener
+{
+
+ final RecipientBox recipientBox;
+
+ final MessageBox messageBox;
+
+ final MessageFeed messageFeed;
+
+ private final UserAgent userAgent;
+
+ /**
+ *
+ * @param userAgent
+ * @param recipientBoxIn
+ * @param messageBoxIn
+ * @param messageFeedIn
+ */
+ public SendButton(UserAgent userAgent, RecipientBox recipientBoxIn, MessageBox messageBoxIn, MessageFeed messageFeedIn) {
+ this.userAgent = userAgent;
+ recipientBox = recipientBoxIn;
+ messageBox = messageBoxIn;
+ messageFeed = messageFeedIn;
+
+ setUpComponent();
+ }
+
+ private void setUpComponent() {
+ messageBox.sendButton = this;
+
+ setPreferredSize(new Dimension(100, 20));
+ setVisible(true);
+ setOpaque(true);
+ setText("Send");
+
+ addActionListener(this);
+ }
+
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ if ((e.getSource() == this) && !messageBox.getText().equals("") && !recipientBox.getText().equals("")) {
+ sendMessage();
+ }
+ }
+
+ void sendMessage() {
+ String sender = userAgent.getAddress();
+ String recipient = recipientBox.getText();
+ String message = messageBox.getText();
+
+ userAgent.sendMsg(sender, recipient, message);
+
+ messageFeed.addRow(message,sender,recipient);
+
+ recipientBox.setText("");
+ messageBox.setText("");
+ }
+
+}
diff --git a/src/middleware/components/useragents/messagesending/package-info.java b/src/middleware/components/useragents/messagesending/package-info.java
new file mode 100644
index 0000000..16a901b
--- /dev/null
+++ b/src/middleware/components/useragents/messagesending/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * Contains the MessageSending GUI classes for UserAgents GUI
+ */
+package middleware.components.useragents.messagesending;
diff --git a/src/middleware/components/useragents/package-info.java b/src/middleware/components/useragents/package-info.java
new file mode 100644
index 0000000..c3c29a4
--- /dev/null
+++ b/src/middleware/components/useragents/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * Contains the GUI for the UserAgents
+ */
+package middleware.components.useragents;
diff --git a/src/middleware/message/Message.java b/src/middleware/message/Message.java
new file mode 100644
index 0000000..bc1b802
--- /dev/null
+++ b/src/middleware/message/Message.java
@@ -0,0 +1,49 @@
+package middleware.message;
+
+import java.io.Serializable;
+import middleware.agents.AgentAddress;
+
+/**
+ * Message - sent between nodes
+ * Containing information
+ */
+public abstract class Message implements Serializable
+{
+ private final Object message; //These can be objects
+ private final AgentAddress recipient;
+
+ /**
+ * Creates an instance of Message
+ * @param m Message Content
+ * @param r Recipient
+ */
+ public Message(Object m, String r)
+ {
+ message = m;
+ recipient = new AgentAddress(r);
+ }
+
+ /**
+ * Gets message content
+ * @return message content
+ */
+ public Object getMessage()
+ {
+ return message;
+ }
+
+ /**
+ * Gets message recipient
+ * @return recipient
+ */
+ public AgentAddress getRecipient()
+ {
+ return recipient;
+ }
+
+ /**
+ * Gets sender
+ * @return sender
+ */
+ public abstract AgentAddress getSender();
+}
diff --git a/src/middleware/message/MetaAgentMessage.java b/src/middleware/message/MetaAgentMessage.java
new file mode 100644
index 0000000..762a762
--- /dev/null
+++ b/src/middleware/message/MetaAgentMessage.java
@@ -0,0 +1,77 @@
+package middleware.message;
+
+import java.io.Serializable;
+
+/**
+ * Type of message used for communications between MetaAgents
+ */
+public class MetaAgentMessage implements Serializable
+{
+ private final Message message;
+
+ /**
+ * The maximum amount of hops a message can take before it is stopped
+ */
+ public int timeToLive;
+
+ /**
+ * The number of hops a message has taken
+ */
+ public int hops;
+
+ /**
+ * Creates an instance of MetaAgentMessage
+ * Wraps an already created message
+ * @param um message
+ * @param ttl time to live
+ */
+ public MetaAgentMessage(Message um, int ttl)
+ {
+ hops = 0;
+ message = um;
+ timeToLive = ttl;
+ }
+
+ /**
+ * Gets message
+ * @return message
+ */
+ public Message getMessage()
+ {
+ return message;
+ }
+
+ /**
+ * Gets message's TTL
+ * @return TimeToLive
+ */
+ public int getTimeToLive()
+ {
+ return timeToLive;
+ }
+
+ /**
+ * Gets no. of hops MetaAgentMessage has taken
+ * @return hops
+ */
+ public int getHops()
+ {
+ return hops;
+ }
+
+ /**
+ * Decrements TTL
+ */
+ public void decreaseTimeToLive()
+ {
+ timeToLive -= 1;
+ }
+
+ /**
+ * Increments TTL
+ */
+ public void increaseHops()
+ {
+ hops += 1;
+ }
+}
diff --git a/src/middleware/message/SystemErrorMessage.java b/src/middleware/message/SystemErrorMessage.java
new file mode 100644
index 0000000..c0100bf
--- /dev/null
+++ b/src/middleware/message/SystemErrorMessage.java
@@ -0,0 +1,17 @@
+package middleware.message;
+
+/**
+ * A type of message for system error communication
+ */
+public class SystemErrorMessage extends SystemMessage
+{
+ /**
+ * Creates an instance of SystemErrorMessage
+ * @param message message content
+ * @param recipient recipient
+ */
+ public SystemErrorMessage(String message, String recipient)
+ {
+ super(message, recipient);
+ }
+}
diff --git a/src/middleware/message/SystemMessage.java b/src/middleware/message/SystemMessage.java
new file mode 100644
index 0000000..cd6b2b2
--- /dev/null
+++ b/src/middleware/message/SystemMessage.java
@@ -0,0 +1,32 @@
+package middleware.message;
+
+import middleware.agents.AgentAddress;
+
+/**
+ * A type of message for system communication
+ */
+public class SystemMessage extends Message
+{
+
+ private final static AgentAddress SYSTEMADDRESS = new AgentAddress("0.0.0");
+
+ /**
+ * Creates an instance of System message
+ * @param m message content
+ * @param r recipient
+ */
+ public SystemMessage(Object m, String r)
+ {
+ super(m, r);
+ }
+
+ /**
+ * Gets sender
+ * @return always "System"
+ */
+ @Override
+ public AgentAddress getSender()
+ {
+ return SYSTEMADDRESS;
+ }
+}
\ No newline at end of file
diff --git a/src/middleware/message/UserMessage.java b/src/middleware/message/UserMessage.java
new file mode 100644
index 0000000..c022e60
--- /dev/null
+++ b/src/middleware/message/UserMessage.java
@@ -0,0 +1,70 @@
+package middleware.message;
+
+import middleware.agents.AgentAddress;
+
+/**
+ * User message
+ * A type of message used between Portals (MetaAgent) and UserAgents
+ */
+public class UserMessage extends Message
+{
+ private final AgentAddress sender; //Can be object
+ private final boolean needsResponse;
+ private final String response; //Can be object
+ private final String messageID;
+
+ /**
+ * Constructs an instance of UserMessage with specified properties
+ * @param m message content
+ * @param r recipient
+ * @param s sender
+ * @param n needs response?
+ * @param res response content
+ * @param id message ID
+ */
+ public UserMessage(Object m, String r, String s, boolean n, String res, String id)
+ {
+ super(m,r);
+ sender = new AgentAddress(s);
+ needsResponse = n;
+ response = res;
+ messageID = id;
+ }
+
+ /**
+ * Gets a UserMessage's sender
+ * @return
+ */
+ @Override
+ public AgentAddress getSender()
+ {
+ return sender;
+ }
+
+ /**
+ * Gets whether UserMessage requires response
+ * @return boolean, if needs response
+ */
+ public boolean getNeedsResponse()
+ {
+ return needsResponse;
+ }
+
+ /**
+ * Gets the response for a UserMessage
+ * @return Response
+ */
+ public String getResponse()
+ {
+ return response;
+ }
+
+ /**
+ * Gets the message ID
+ * @return message ID
+ */
+ public String getMessageID()
+ {
+ return messageID;
+ }
+}
diff --git a/src/middleware/message/package-info.java b/src/middleware/message/package-info.java
new file mode 100644
index 0000000..adecb59
--- /dev/null
+++ b/src/middleware/message/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * Contains the message classes used for communication in the middleware
+ */
+package middleware.message;
diff --git a/src/middleware/message/wrapper/MetaAgentWrapper.java b/src/middleware/message/wrapper/MetaAgentWrapper.java
new file mode 100644
index 0000000..626040a
--- /dev/null
+++ b/src/middleware/message/wrapper/MetaAgentWrapper.java
@@ -0,0 +1,31 @@
+package middleware.message.wrapper;
+
+import middleware.message.Message;
+import middleware.message.MetaAgentMessage;
+
+/**
+ * Wraps given data into a MetaAgentMessage
+ */
+public class MetaAgentWrapper
+{
+ /**
+ * Creates a new MetaAgentMessage from given properties
+ * @param m message content
+ * @param ttl time to live (TTL)
+ * @return wrapped MetaAgentMessage
+ */
+ public static MetaAgentMessage wrap(Message m, int ttl)
+ {
+ return new MetaAgentMessage(m, ttl);
+ }
+
+ /**
+ * Unwraps a given message
+ * @param m MetaAgentMessage to be unwrapped
+ * @return message content
+ */
+ public static Message unwrap(MetaAgentMessage m)
+ {
+ return m.getMessage();
+ }
+}
diff --git a/src/middleware/message/wrapper/UserAgentWrapper.java b/src/middleware/message/wrapper/UserAgentWrapper.java
new file mode 100644
index 0000000..f9bc08c
--- /dev/null
+++ b/src/middleware/message/wrapper/UserAgentWrapper.java
@@ -0,0 +1,34 @@
+package middleware.message.wrapper;
+
+import middleware.message.UserMessage;
+
+/**
+ * Wraps given parameters into a UserMessage
+ */
+public class UserAgentWrapper
+{
+ /**
+ * Creates a new UserMessage with given properties
+ * @param m message content
+ * @param r recipient
+ * @param sender sender
+ * @param n requires response?
+ * @param res response content
+ * @param id message id
+ * @return Created UserMessage
+ */
+ public static UserMessage wrap(Object m, String r, String sender, boolean n, String res, String id)
+ {
+ return new UserMessage(m, r, sender, n, res, id);
+ }
+
+ /**
+ * Unwraps a specified user message
+ * @param m user message
+ * @return message content
+ */
+ public static Object unwrap(UserMessage m)
+ {
+ return m.getMessage();
+ }
+}
diff --git a/src/middleware/message/wrapper/package-info.java b/src/middleware/message/wrapper/package-info.java
new file mode 100644
index 0000000..d314411
--- /dev/null
+++ b/src/middleware/message/wrapper/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * The main interface for the Middleware project
+ */
+package middleware.message.wrapper;
diff --git a/src/middleware/nodemonitor/NodeMonitor.java b/src/middleware/nodemonitor/NodeMonitor.java
new file mode 100644
index 0000000..89ce668
--- /dev/null
+++ b/src/middleware/nodemonitor/NodeMonitor.java
@@ -0,0 +1,43 @@
+package middleware.nodemonitor;
+
+import middleware.components.main.nodelistener.NodeListener;
+import middleware.message.MetaAgentMessage;
+import middleware.observer.Observer;
+
+/**
+ * NodeMonitor created to read messages received by a node (e.g. meta agent, agent) and add them to the GUI
+ *
+ * @author Dylan Currey
+ * @since 12/12/18
+ */
+public class NodeMonitor implements Observer{
+
+
+ private NodeListener nodeListener;
+
+ /**
+ * Creates an instance, using a passed GUI component
+ * @param nodeListener a GUI component, to be updated by NodeMonitor
+ */
+ public NodeMonitor(NodeListener nodeListener)
+ {
+ this.nodeListener = nodeListener;
+ }
+
+ /**
+ * Parses and updates GUI from received message
+ * @param msg the message object received by the attached subject
+ * @return whether operation was successful
+ */
+ @Override
+ public boolean update(Object msg) {
+ if(msg instanceof MetaAgentMessage)
+ {
+ MetaAgentMessage MAM = (MetaAgentMessage) msg;
+ nodeListener.addRow(MAM.getMessage().getMessage().toString(), MAM.getMessage().getSender().getAddress(), MAM.getMessage().getRecipient().getAddress(), MAM.getTimeToLive(), MAM.getHops());
+ return true;
+ }
+ return false;
+ }
+
+}
diff --git a/src/middleware/nodemonitor/package-info.java b/src/middleware/nodemonitor/package-info.java
new file mode 100644
index 0000000..b48c999
--- /dev/null
+++ b/src/middleware/nodemonitor/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * Contains the NodeMonitor classes which can be attached to MetaAgents
+ */
+package middleware.nodemonitor;
diff --git a/src/middleware/observer/Observer.java b/src/middleware/observer/Observer.java
new file mode 100644
index 0000000..edb08c6
--- /dev/null
+++ b/src/middleware/observer/Observer.java
@@ -0,0 +1,19 @@
+package middleware.observer;
+
+/**
+ * An Observer interface created to facilitate the implementation of the Observer design pattern between UserAgents and NodeMonitors.
+ *
+ * @author Dylan Currey
+ * @since 12/12/18
+ */
+public interface Observer {
+
+ /**
+ * Updates the Observer with the specified command
+ * @param msg
+ * @return
+ */
+ public boolean update(Object msg);
+
+}
+
diff --git a/src/middleware/observer/Subject.java b/src/middleware/observer/Subject.java
new file mode 100644
index 0000000..b57846d
--- /dev/null
+++ b/src/middleware/observer/Subject.java
@@ -0,0 +1,31 @@
+package middleware.observer;
+
+/**
+ * A Subject interface created to facilitate the implementation of the Observer design pattern between UserAgents and NodeMonitors
+ *
+ * @author Dylan Currey
+ * @since 12/12/18
+ */
+public interface Subject
+{
+
+ /**
+ * Attaches observers to the subject.
+ * @param observer the Observer object to be attached.
+ */
+ public void attach(Observer observer);
+
+ /**
+ * Detaches observers from the subject
+ * @param observer the Observer object to be detached
+ */
+ public void detach (Observer observer);
+
+ /**
+ * Updates all observers in listOfObservers with a command.
+ * @param msg
+ * @return
+ */
+ public boolean updateObservers(Object msg);
+
+}
\ No newline at end of file
diff --git a/src/middleware/observer/package-info.java b/src/middleware/observer/package-info.java
new file mode 100644
index 0000000..8c8f4ef
--- /dev/null
+++ b/src/middleware/observer/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * Contains classes for implementing the Observer pattern
+ */
+package middleware.observer;
diff --git a/src/middleware/package-info.java b/src/middleware/package-info.java
new file mode 100644
index 0000000..645a094
--- /dev/null
+++ b/src/middleware/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * The main interface for the Middleware project
+ */
+package middleware;
diff --git a/src/middleware/socket/Client.java b/src/middleware/socket/Client.java
new file mode 100644
index 0000000..0c68302
--- /dev/null
+++ b/src/middleware/socket/Client.java
@@ -0,0 +1,81 @@
+package middleware.socket;
+
+import java.io.IOException;
+import java.io.ObjectOutputStream;
+import java.io.PrintWriter;
+import java.net.Socket;
+import middleware.message.MetaAgentMessage;
+
+/**
+ * Client
+ * Acts as client in client-server relationship
+ */
+public class Client
+{
+ //Socket variables (for connection)
+ private Socket socket;
+ private String address;
+ private int port;
+
+ //Socket input and output variables
+ private PrintWriter writer;
+ private ObjectOutputStream objOut;
+
+ /**
+ * Creates an instance of Client
+ * @param a address
+ * @param p port
+ */
+ public Client(String a, int p)
+ {
+ address = a;
+ port = p;
+ }
+
+ /**
+ * Creates a connection with a socket and output stream
+ * @throws IOException
+ */
+ public void connect() throws IOException
+ {
+ //Create new socket
+ socket = new Socket(address, port);
+
+ //Declare the output stream
+ //writer = new PrintWriter(socket.getOutputStream());
+ objOut = new ObjectOutputStream(socket.getOutputStream());
+ }
+
+ /**
+ * Sends a String to a socket, may be used when communicating with other languages
+ * @param s string to be sent
+ */
+ public void sendString(String s)
+ {
+ //TODO maybe?
+ }
+
+ /**
+ * Sends serialisable objects (e.g. messages, in this case) to a socket
+ * @param message message, serialisable to be sent
+ * @throws IOException
+ */
+ public void send(MetaAgentMessage message) throws IOException
+ {
+ //Write the object/message to the stream
+ objOut.writeObject((MetaAgentMessage) message);
+ //Flush the stream, is nice to have
+ objOut.flush();
+ }
+
+ /**
+ * Closes all connections
+ * @throws IOException
+ */
+ public void close() throws IOException
+ {
+ //Close all connections and writers
+ socket.close();
+ writer.close();
+ }
+}
diff --git a/src/middleware/socket/ClientInstance.java b/src/middleware/socket/ClientInstance.java
new file mode 100644
index 0000000..f1aabff
--- /dev/null
+++ b/src/middleware/socket/ClientInstance.java
@@ -0,0 +1,53 @@
+package middleware.socket;
+
+import java.io.IOException;
+import java.util.Scanner;
+import middleware.message.Message;
+import middleware.message.MetaAgentMessage;
+import middleware.message.UserMessage;
+
+/**
+ * Runs an instance of Client
+ */
+public class ClientInstance
+{
+ /**
+ *
+ * @param args
+ * @throws IOException
+ */
+ public static void main(String[] args) throws IOException
+ {
+
+
+ //Input message stuff
+ System.out.println("Client");
+
+ Scanner sc = new Scanner(System.in);
+ System.out.print("Please input the server IP: ");
+ String ip = sc.nextLine();
+ System.out.print("Please input the port: ");
+ int port = sc.nextInt();
+
+ Client client = new Client(ip, port);
+ client.connect();
+
+ sc.nextLine();
+
+
+ String message, target;
+ for(;;)
+ {
+ System.out.print("Please enter target address: ");
+ target = sc.nextLine();
+ System.out.print("Please enter message: ");
+ message = sc.nextLine();
+
+ //Meta agent stuff
+ MetaAgentMessage metaAgentMessage = new MetaAgentMessage(new UserMessage(message, target, "3", false, "", "MID"), 1000);
+
+ client.send(metaAgentMessage);
+ }
+
+ }
+}
diff --git a/src/middleware/socket/Server.java b/src/middleware/socket/Server.java
new file mode 100644
index 0000000..68070fa
--- /dev/null
+++ b/src/middleware/socket/Server.java
@@ -0,0 +1,102 @@
+package middleware.socket;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import middleware.agents.Router;
+
+/**
+ * Server acts as server in Client-Server Communications
+ */
+public class Server
+{
+ private ServerSocket serverSocket;
+ private Socket socket;
+ private int port;
+ private InetAddress address;
+
+ private Router router;
+
+ private boolean listening;
+
+
+
+ /**
+ * Creates an instance of Server with given properties
+ * @param p port
+ */
+ public Server(int p, Router r)
+ {
+ //address = a;
+ port = p;
+ router = r;
+
+ }
+
+ /**
+ * Creates a new server socket on Server's port
+ * @throws IOException
+ */
+ public void create() throws IOException
+ {
+ //serverSocket = new ServerSocket(port, 50, address);
+ serverSocket = new ServerSocket(port);
+ }
+
+ /**
+ * Accepts input from socket
+ * @throws IOException
+ */
+ private void listen() throws IOException
+ {
+ final ExecutorService clientProcessingPool = Executors.newFixedThreadPool(10);
+
+ Runnable serverTask = new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ try
+ {
+ for (;;)
+ {
+ socket = serverSocket.accept();
+ new ServerThread(socket, router).start();
+ System.out.println("Connected: " + socket.toString());
+ }
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+ };
+
+ Thread serverThread = new Thread(serverTask);
+ serverThread.start();
+ }
+
+ /**
+ * Server starts listening to socket input
+ * @throws IOException
+ */
+ public void enableListening() throws IOException
+ {
+ if (!listening)
+ {
+ listening = true;
+ listen();
+ }
+ }
+
+ /**
+ * Stops Server listening to socket
+ */
+ public void disableListening()
+ {
+ listening = false;
+ }
+}
diff --git a/src/middleware/socket/ServerInstance.java b/src/middleware/socket/ServerInstance.java
new file mode 100644
index 0000000..fa8a60a
--- /dev/null
+++ b/src/middleware/socket/ServerInstance.java
@@ -0,0 +1,26 @@
+package middleware.socket;
+
+import java.io.IOException;
+import java.util.Scanner;
+
+/**
+ * Runs an instance of Server
+ */
+public class ServerInstance
+{
+ /**
+ *
+ * @param args
+ * @throws IOException
+ */
+ public static void main(String[] args) throws IOException
+ {
+ System.out.println("Server");
+ Scanner sc = new Scanner(System.in);
+ System.out.print("Please input a port: ");
+ int port = sc.nextInt();
+ Server server = new Server(port, null);
+ server.create();
+ server.enableListening();
+ }
+}
diff --git a/src/middleware/socket/ServerThread.java b/src/middleware/socket/ServerThread.java
new file mode 100644
index 0000000..57d8405
--- /dev/null
+++ b/src/middleware/socket/ServerThread.java
@@ -0,0 +1,76 @@
+package middleware.socket;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.net.Socket;
+import middleware.agents.Router;
+import middleware.message.MetaAgentMessage;
+
+/**
+ * A type of thread for running Server objects
+ */
+public class ServerThread extends Thread
+{
+ private Socket socket;
+ private Router router;
+
+ /**
+ * Creates an instance of ServerThread with given property
+ * @param client client socket
+ */
+ public ServerThread (Socket client, Router r)
+ {
+ socket = client;
+ router = r;
+ }
+
+ /**
+ * Closes connection
+ * @throws IOException
+ */
+ public void close() throws IOException
+ {
+ socket.close();
+ }
+
+ /**
+ * Runs thread
+ */
+ @Override
+ public void run()
+ {
+ ObjectInputStream objIn = null;
+
+ try
+ {
+ objIn = new ObjectInputStream(socket.getInputStream());
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+
+ //Object input;
+ MetaAgentMessage input;
+ for(;;)
+ {
+ try
+ {
+ input = (MetaAgentMessage) objIn.readObject();
+ //out.flush();
+ System.out.println("Object is of type: " + input.getClass().getSimpleName());
+ System.out.println(input);
+
+ if (router != null)
+ router.add(input);
+ //INPUT IS THE MESSAGE HERE
+ //SHOULD STICK AT THE readLine CODE UNTIL A LINE IS DETECTED
+ //CAN USE RETURN TO BREAK OUT OF LOOP IF NEEDED
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+ }
+}
diff --git a/src/middleware/socket/package-info.java b/src/middleware/socket/package-info.java
new file mode 100644
index 0000000..7b2d539
--- /dev/null
+++ b/src/middleware/socket/package-info.java
@@ -0,0 +1,4 @@
+/**
+ *
+ */
+package middleware.socket;