add a traffic engineering use case and samples of NetworkGraph classes as test codes

Change-Id: Id655106309d032a2e99e26887db1836d2f598ef8
diff --git a/src/test/java/net/onrc/onos/ofcontroller/app/BaseApplication.java b/src/test/java/net/onrc/onos/ofcontroller/app/BaseApplication.java
new file mode 100644
index 0000000..6aa435c
--- /dev/null
+++ b/src/test/java/net/onrc/onos/ofcontroller/app/BaseApplication.java
@@ -0,0 +1,8 @@
+package net.onrc.onos.ofcontroller.app;
+
+/**
+ * This code is valid for the architectural study purpose only.
+ * @author Toshio Koide (t-koide@onlab.us)
+ */
+public interface BaseApplication {
+}
diff --git a/src/test/java/net/onrc/onos/ofcontroller/app/ConstrainedFlow.java b/src/test/java/net/onrc/onos/ofcontroller/app/ConstrainedFlow.java
new file mode 100644
index 0000000..7b18c34
--- /dev/null
+++ b/src/test/java/net/onrc/onos/ofcontroller/app/ConstrainedFlow.java
@@ -0,0 +1,88 @@
+package net.onrc.onos.ofcontroller.app;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+
+/**
+ * This code is valid for the architectural study purpose only.
+ * @author Toshio Koide (t-koide@onlab.us)
+ */
+public class ConstrainedFlow extends Flow {
+	public double bandwidth;
+	
+	/**
+	 * 
+	 * @param srcPort
+	 * @param dstPort
+	 * @param bandwidth
+	 */
+	public ConstrainedFlow(NetworkGraph graph, String name, SwitchPort srcPort, SwitchPort dstPort, double bandwidth) {
+		super(graph, name, srcPort, dstPort);
+		this.bandwidth = bandwidth;
+	}
+	
+	/**
+	 * calculate available bandwidth of specified link	
+	 * @param link
+	 * @return
+	 */
+	protected Double getAvailableBandwidth(Link link) {
+		Double capacity = link.getCapacity();
+		if (capacity.isInfinite()) {
+			return capacity;
+		}
+		Double bandwidth = capacity;
+		for (Flow flow: link.getFlows()) {
+			if (flow instanceof ConstrainedFlow) {
+				bandwidth -= ((ConstrainedFlow)flow).getBandwidth();
+			}
+		}
+		return bandwidth;
+	}
+
+	public Double getBandwidth() {
+		return bandwidth;
+	}
+
+	/**
+	 * calculate path by creating BFS tree satisfying the bandwidth condition
+	 */
+	@Override
+	public boolean calcPath() {
+		LinkedList<Switch> switchQueue = new LinkedList<Switch>();
+		HashSet<Switch> switchSearched = new HashSet<Switch>();
+		HashMap<Switch, Link> upstreamLinks = new HashMap<Switch, Link>();
+		
+		Switch srcSwitch = srcPort.getSwitch();
+		Switch dstSwitch = dstPort.getSwitch();
+		
+		switchQueue.add(srcSwitch);
+		switchSearched.add(srcSwitch);
+
+		while (!switchQueue.isEmpty()) {
+			Switch sw = switchQueue.poll();
+			if (sw == dstSwitch) {
+				// path has been searched.
+				// store path into itself
+				path.clear();
+				while (sw != srcSwitch) {
+					Link upstreamLink = upstreamLinks.get(sw);
+					path.add(0, upstreamLink);
+					sw = upstreamLink.getSrcPort().getSwitch();
+				}
+				return super.calcPath();
+			}
+			for (Link link: sw.getAdjLinks()) {
+				Switch reachedSwitch = link.getDstPort().getSwitch();
+				Double availableBandwidth = getAvailableBandwidth(link);
+				if (availableBandwidth < bandwidth || switchSearched.contains(reachedSwitch)) continue;
+				switchQueue.add(reachedSwitch);
+				switchSearched.add(reachedSwitch);
+				upstreamLinks.put(reachedSwitch, link);
+			}
+		}
+		state = FlowState.PathCalcurationFailed;
+		return false;
+	}
+}
diff --git a/src/test/java/net/onrc/onos/ofcontroller/app/Flow.java b/src/test/java/net/onrc/onos/ofcontroller/app/Flow.java
new file mode 100644
index 0000000..071d89f
--- /dev/null
+++ b/src/test/java/net/onrc/onos/ofcontroller/app/Flow.java
@@ -0,0 +1,106 @@
+package net.onrc.onos.ofcontroller.app;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Base class for Flow representation
+ * This code is valid for the architectural study purpose only.
+ * @author Toshio Koide (t-koide@onlab.us)
+ */
+public class Flow extends NetworkGraphEntity {
+	public enum FlowState {
+		Created,
+		Configuring,
+		Configured,
+		PathCalcurating,
+		PathCalcurated,
+		PathCalcurationFailed,
+		PathInstalled,
+		PathInstlationFailed,
+		FlowEntriesCalcurating,
+		FlowEntriesCalcurated,
+		FlowEntriesCalcuratinFailed,
+		FlowEntriesInstalling,
+		FlowEntriesInstalled,
+		FlowEntriesInstallationFailed,
+		FlowEntriesRemoving,
+		FlowEntriesRemoved,
+		FlowEntriesRemovalFailed,
+		PathRemoved,
+		PathRemovalFailed,
+	}
+
+	protected FlowState state = FlowState.Created;
+	
+	// configurations
+	protected SwitchPort srcPort = null;
+	protected SwitchPort dstPort = null;
+	
+	// path
+	protected Path path = new Path();
+	
+	// flow entries
+	protected Map<SwitchPort, FlowEntry> flowEntries = null;
+
+	public Flow(NetworkGraph graph, String name, SwitchPort srcPort, SwitchPort dstPort) {
+		super(graph);
+		this.srcPort = srcPort;
+		this.dstPort = dstPort;
+		state = FlowState.Created;
+	}
+	
+	FlowState getState() {
+		return state;
+	}
+	
+	boolean isState(FlowState state) {
+		return this.state == state;
+	}
+	
+	boolean calcPath() {
+		state = FlowState.PathCalcurated;
+		return true;
+	}
+	
+	public Path getPath() {
+		return path;
+	}
+	
+	public boolean installPath() {
+		for (Link link: path) {
+			link.addFlow(this);
+		}
+		state = FlowState.PathInstalled;
+		return true;
+	}
+	
+	public boolean uninstallPath() {
+		for (Link link: path) {
+			link.removeFlow(this);
+		}
+		state = FlowState.PathRemoved;
+		return true;
+	}
+
+	public void calcFlowEntries() {
+		flowEntries = new HashMap<SwitchPort, FlowEntry>();
+		state = FlowState.FlowEntriesCalcurated;
+	}
+	
+	public void installFlowEntries() {
+		state = FlowState.FlowEntriesInstalled;
+	}
+	
+	public void uninstallFlowEntries() {
+		state = FlowState.FlowEntriesRemoved;
+	}
+	
+	@Override
+	public String toString() {
+		return String.format("srcPort:%s, dstPort:%s, Path: %s",
+				srcPort.toString(),
+				dstPort.toString(),
+				path.toString());
+	}
+}
diff --git a/src/test/java/net/onrc/onos/ofcontroller/app/FlowEntry.java b/src/test/java/net/onrc/onos/ofcontroller/app/FlowEntry.java
new file mode 100644
index 0000000..76e90ed
--- /dev/null
+++ b/src/test/java/net/onrc/onos/ofcontroller/app/FlowEntry.java
@@ -0,0 +1,12 @@
+package net.onrc.onos.ofcontroller.app;
+
+/**
+ * Base class for Link representation
+ * This code is valid for the architectural study purpose only.
+ *
+ * @author Toshio Koide (t-koide@onlab.us)
+ * 
+ */
+public class FlowEntry {
+
+}
diff --git a/src/test/java/net/onrc/onos/ofcontroller/app/Link.java b/src/test/java/net/onrc/onos/ofcontroller/app/Link.java
new file mode 100644
index 0000000..dc3c0dd
--- /dev/null
+++ b/src/test/java/net/onrc/onos/ofcontroller/app/Link.java
@@ -0,0 +1,74 @@
+package net.onrc.onos.ofcontroller.app;
+
+import java.util.Collection;
+import java.util.HashSet;
+
+/**
+ * This code is valid for the architectural study purpose only.
+ * Base class for Link representation
+ *
+ * @author Toshio Koide (t-koide@onlab.us)
+ * 
+ */
+public class Link extends NetworkGraphEntity {
+	protected SwitchPort srcPort;
+	protected SwitchPort dstPort;
+	protected HashSet<Flow> flows;
+	protected Double capacity;
+
+	public Link(SwitchPort srcPort, SwitchPort dstPort) {
+		super(srcPort.getNetworkGraph());
+		this.srcPort = srcPort;
+		this.dstPort = dstPort;
+		this.flows = new HashSet<Flow>();
+		this.capacity = Double.POSITIVE_INFINITY;
+		setToPorts();
+	}
+	
+	public void setToPorts() {
+		srcPort.setOutgoingLink(this);
+		dstPort.setIncomingLink(this);		
+	}
+	
+	public void unsetFromPorts() {
+		srcPort.setOutgoingLink(null);
+		dstPort.setIncomingLink(null);
+	}
+	
+	public void setCapacity(Double capacity) {
+		this.capacity = capacity;
+	}
+	
+	public Double getCapacity() {
+		return capacity;
+	}
+
+	public boolean addFlow(Flow flow) {
+		return flows.add(flow);
+	}
+	
+	public boolean removeFlow(Flow flow) {
+		return flows.remove(flow);
+	}
+
+	public Collection<Flow> getFlows() {
+		return flows;
+	}
+
+	public SwitchPort getSrcPort() {
+		return srcPort;
+	}
+
+	public SwitchPort getDstPort() {
+		return dstPort;
+	}
+	
+	@Override
+	public String toString() {
+		return String.format("%s --(%f Mbps, %d flows)--> %s",
+				getSrcPort().toString(),
+				getCapacity(),
+				getFlows().size(),
+				getDstPort().toString());
+	}
+}
diff --git a/src/test/java/net/onrc/onos/ofcontroller/app/NamedNode.java b/src/test/java/net/onrc/onos/ofcontroller/app/NamedNode.java
new file mode 100644
index 0000000..c900d53
--- /dev/null
+++ b/src/test/java/net/onrc/onos/ofcontroller/app/NamedNode.java
@@ -0,0 +1,19 @@
+package net.onrc.onos.ofcontroller.app;
+
+public class NamedNode {
+	protected String name;
+	protected NetworkGraph graph;
+
+	public NamedNode(NetworkGraph graph, String name) {
+		this.graph = graph;
+		this.name = name;
+	}
+
+	public String getName() {
+		return name;
+	}
+	
+	public NetworkGraph getNetworkGraph() {
+		return graph;
+	}
+}
diff --git a/src/test/java/net/onrc/onos/ofcontroller/app/NetworkGraph.java b/src/test/java/net/onrc/onos/ofcontroller/app/NetworkGraph.java
new file mode 100644
index 0000000..a062b61
--- /dev/null
+++ b/src/test/java/net/onrc/onos/ofcontroller/app/NetworkGraph.java
@@ -0,0 +1,71 @@
+package net.onrc.onos.ofcontroller.app;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+
+/**
+ * This code is valid for the architectural study purpose only.
+ * @author Toshio Koide (t-koide@onlab.us)
+ */
+public class NetworkGraph {
+	protected HashSet<Flow> flows;
+	protected HashMap<String, Switch> switches;
+	
+	public NetworkGraph() {
+		flows = new HashSet<Flow>();
+		switches = new HashMap<String, Switch>();
+	}
+
+	// Switch operations
+	
+	public Switch addSwitch(String name) {
+		if (switches.containsKey(name)) {
+			return null; // should throw exception
+		}
+		Switch sw = new Switch(this, name);
+		switches.put(sw.getName(), sw);
+		return sw;
+		
+	}
+
+	public Switch getSwitch(String switchName) {
+		return switches.get(switchName);
+	}
+	
+	// Link operations
+	
+	public Link addLink(String srcSwitchName, Integer srcPortNo, String dstSwitchName, Integer dstPortNo) {
+		return new Link(
+				getSwitch(srcSwitchName).getPort(srcPortNo),
+				getSwitch(dstSwitchName).getPort(dstPortNo));
+	}
+	
+	public Link[] addBidirectionalLinks(String srcSwitchName, Integer srcPortNo, String dstSwitchName, Integer dstPortNo) {
+		Link[] links = new Link[2];
+		links[0] = addLink(srcSwitchName, srcPortNo, dstSwitchName, dstPortNo);
+		links[1] = addLink(dstSwitchName, dstPortNo, srcSwitchName, srcPortNo);
+		
+		return links;
+	}
+	
+	public Collection<Link> getLinks() {
+		LinkedList<Link> links = new LinkedList<Link>();
+		for (Switch sw: switches.values()) {
+			for (SwitchPort port: sw.getPorts()) {
+				Link link = port.outgoingLink;
+				if (link != null) {
+					links.add(link);
+				}
+			}
+		}
+		return links;
+	}
+
+	// Flow operations
+	
+	public boolean addFlow(Flow flow) {
+		return flows.add(flow);
+	}
+}
diff --git a/src/test/java/net/onrc/onos/ofcontroller/app/NetworkGraphEntity.java b/src/test/java/net/onrc/onos/ofcontroller/app/NetworkGraphEntity.java
new file mode 100644
index 0000000..9a26b31
--- /dev/null
+++ b/src/test/java/net/onrc/onos/ofcontroller/app/NetworkGraphEntity.java
@@ -0,0 +1,17 @@
+package net.onrc.onos.ofcontroller.app;
+
+/**
+ * This code is valid for the architectural study purpose only.
+ * @author Toshio Koide (t-koide@onlab.us)
+ */
+public class NetworkGraphEntity {
+	protected NetworkGraph graph;
+
+	public NetworkGraphEntity(NetworkGraph graph) {
+		this.graph = graph;
+	}
+	
+	public NetworkGraph getNetworkGraph() {
+		return graph;
+	}
+}
diff --git a/src/test/java/net/onrc/onos/ofcontroller/app/Path.java b/src/test/java/net/onrc/onos/ofcontroller/app/Path.java
new file mode 100644
index 0000000..318dbda
--- /dev/null
+++ b/src/test/java/net/onrc/onos/ofcontroller/app/Path.java
@@ -0,0 +1,25 @@
+package net.onrc.onos.ofcontroller.app;
+
+import java.util.Iterator;
+import java.util.LinkedList;
+
+/**
+ * Base class for Path representation
+ * This code is valid for the architectural study purpose only.
+ * @author Toshio Koide (t-koide@onlab.us)
+ */
+public class Path extends LinkedList<Link> {
+	private static final long serialVersionUID = 7127274096495173415L;
+	
+	@Override
+	public String toString() {
+		StringBuilder builder = new StringBuilder();
+		Iterator<Link> i = this.iterator();
+		while (i.hasNext()) {
+			builder.append(i.next().toString());
+			if (i.hasNext())
+				builder.append(", ");
+		}
+		return builder.toString();
+	}
+}
diff --git a/src/test/java/net/onrc/onos/ofcontroller/app/ShortestPath.java b/src/test/java/net/onrc/onos/ofcontroller/app/ShortestPath.java
new file mode 100644
index 0000000..4789c6e
--- /dev/null
+++ b/src/test/java/net/onrc/onos/ofcontroller/app/ShortestPath.java
@@ -0,0 +1,9 @@
+package net.onrc.onos.ofcontroller.app;
+
+/**
+ * @author Toshio Koide (t-koide@onlab.us)
+ * This code is valid for the architectural study purpose only.
+ */
+public class ShortestPath implements BaseApplication {
+
+}
diff --git a/src/test/java/net/onrc/onos/ofcontroller/app/ShortestPathTest.java b/src/test/java/net/onrc/onos/ofcontroller/app/ShortestPathTest.java
new file mode 100644
index 0000000..4bf1d4c
--- /dev/null
+++ b/src/test/java/net/onrc/onos/ofcontroller/app/ShortestPathTest.java
@@ -0,0 +1,18 @@
+package net.onrc.onos.ofcontroller.app;
+
+import static org.junit.Assert.*;
+
+import org.junit.Test;
+
+/**
+ * This code is valid for the architectural study purpose only.
+ * @author Toshio Koide (t-koide@onlab.us)
+ */
+public class ShortestPathTest {
+
+	@Test
+	public void test() {
+		fail("Not yet implemented");
+	}
+
+}
diff --git a/src/test/java/net/onrc/onos/ofcontroller/app/SimpleTrafficEngineering.java b/src/test/java/net/onrc/onos/ofcontroller/app/SimpleTrafficEngineering.java
new file mode 100644
index 0000000..3714da0
--- /dev/null
+++ b/src/test/java/net/onrc/onos/ofcontroller/app/SimpleTrafficEngineering.java
@@ -0,0 +1,77 @@
+package net.onrc.onos.ofcontroller.app;
+
+/**
+ * This code is valid for the architectural study purpose only.
+ * @author Toshio Koide (t-koide@onlab.us)
+ */
+public class SimpleTrafficEngineering implements BaseApplication {
+	NetworkGraph graph;
+	
+	/**
+	 * Instantiate SimpleTrafficEngineering application
+	 * 
+	 * 1. store NetworkGraph as a cache
+	 * 
+	 * @param graph
+	 */
+	public SimpleTrafficEngineering(NetworkGraph graph) {
+		this.graph = graph;
+	}
+
+	/**
+	 * Allocate specified bandwidth between specified switch ports
+	 * 
+	 * @param srcPort
+	 * @param dstPort
+	 * @param bandWidth
+	 * @return
+	 */
+	public ConstrainedFlow allocate(SwitchPort srcPort, SwitchPort dstPort, double bandWidth) {
+		ConstrainedFlow flow = new ConstrainedFlow(this.graph, null, srcPort, dstPort, bandWidth);
+
+		// 1. store Flow object to NetworkGraph
+		if (!graph.addFlow(flow)) {
+			return flow;
+		}
+
+		// 2. calculate path from srcPort to dstPort under condition of bandWidth
+		if (!flow.calcPath()) {
+			return flow;
+		}
+		
+		// debug (show path)
+		System.out.println("path was calculated:");
+		System.out.println("[Flow] " + flow.toString());
+
+		// 3. allocate bandwidth in NetworkGraph
+		if (!flow.installPath()) {
+			return flow;
+		}
+
+		// debug (show path)
+		System.out.println("bandwidth was allocated.");
+		System.out.println("[Flow] " + flow.toString());
+
+		// (then, flow entries are created and installed from stored path information in the Flow object by another processes)
+		return flow;
+	}
+
+	/**
+	 * Release specified Flow object
+	 * 
+	 * @param flow
+	 */
+	public void release(ConstrainedFlow flow) {
+		// 1. release bandwidth (remove property of links) in NetworkGraph
+		flow.uninstallPath();
+
+		// debug (show path)
+		System.out.println("bandwidth was released.");
+		System.out.println("[Flow] " + flow.toString());
+		
+		// 2. deactivate Flow object
+
+		// (then, flow entries are removed by another processes)
+		// (retain flow object in NetworkGraph as a removed flow object)
+	}
+}
diff --git a/src/test/java/net/onrc/onos/ofcontroller/app/SimpleTrafficEngineeringTest.java b/src/test/java/net/onrc/onos/ofcontroller/app/SimpleTrafficEngineeringTest.java
new file mode 100644
index 0000000..ceb9135
--- /dev/null
+++ b/src/test/java/net/onrc/onos/ofcontroller/app/SimpleTrafficEngineeringTest.java
@@ -0,0 +1,80 @@
+package net.onrc.onos.ofcontroller.app;
+
+import static org.junit.Assert.*;
+
+import net.onrc.onos.ofcontroller.app.Flow.FlowState;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * This code is valid for the architectural study purpose only.
+ * @author Toshio Koide (t-koide@onlab.us)
+ */
+public class SimpleTrafficEngineeringTest {
+	NetworkGraph g;
+
+	@Before
+	public void setUp() {
+		g = new NetworkGraph();
+
+		// add 10 switches (24 ports switch)
+		for (Integer i=1; i<10; i++) {
+			Switch sw = g.addSwitch("v" + i.toString());
+			for (Integer j=1; j<=24; j++) {
+				sw.addPort(j);
+			}
+		}
+
+		// add loop path
+		g.addBidirectionalLinks("v1", 1, "v2", 2);
+		g.addBidirectionalLinks("v2", 1, "v3", 2);
+		g.addBidirectionalLinks("v3", 1, "v4", 2);
+		g.addBidirectionalLinks("v4", 1, "v5", 2);
+		g.addBidirectionalLinks("v5", 1, "v6", 2);
+		g.addBidirectionalLinks("v6", 1, "v7", 2);
+		g.addBidirectionalLinks("v7", 1, "v8", 2);
+		g.addBidirectionalLinks("v8", 1, "v9", 2);
+		g.addBidirectionalLinks("v9", 1, "v1", 2);
+
+		// add other links
+		g.addBidirectionalLinks("v1", 3, "v2", 3);
+		g.addBidirectionalLinks("v2", 4, "v3", 4);
+		g.addBidirectionalLinks("v4", 5, "v3", 5);
+		g.addBidirectionalLinks("v5", 6, "v6", 6);
+		g.addBidirectionalLinks("v7", 7, "v6", 7);
+		g.addBidirectionalLinks("v8", 8, "v1", 8);
+		g.addBidirectionalLinks("v9", 9, "v1", 9);
+		
+		// set capacity of all links to 1000Mbps
+		for (Link link: g.getLinks()) {
+			link.setCapacity(1000.0);
+		}
+	}
+
+	@After
+	public void tearDown() {
+	}
+
+	@Test
+	public void useCase1() {
+		// load TE algorithm
+		SimpleTrafficEngineering te = new SimpleTrafficEngineering(g);
+
+		// get edge ports
+		SwitchPort srcPort = g.getSwitch("v1").getPort(20);
+		SwitchPort dstPort = g.getSwitch("v6").getPort(20);
+		
+		// specify bandwidth (Mbps)
+		double bandWidth = 1000.0;
+
+		// allocate flow
+		ConstrainedFlow flow = te.allocate(srcPort, dstPort, bandWidth);
+		assertTrue(flow.isState(FlowState.PathInstalled));
+
+		// release flow
+		te.release(flow);
+		assertTrue(flow.isState(FlowState.PathRemoved));
+	}
+}
diff --git a/src/test/java/net/onrc/onos/ofcontroller/app/Switch.java b/src/test/java/net/onrc/onos/ofcontroller/app/Switch.java
new file mode 100644
index 0000000..6b7b75c
--- /dev/null
+++ b/src/test/java/net/onrc/onos/ofcontroller/app/Switch.java
@@ -0,0 +1,50 @@
+package net.onrc.onos.ofcontroller.app;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.LinkedList;
+
+/**
+ * This code is valid for the architectural study purpose only.
+ * @author Toshio Koide (t-koide@onlab.us)
+ */
+public class Switch extends NetworkGraphEntity {
+	protected HashMap<Integer, SwitchPort> ports;
+	protected String name;
+	
+	public Switch(NetworkGraph graph, String name) {
+		super(graph);
+		this.name = name;
+		ports = new HashMap<Integer, SwitchPort>();
+	}
+
+	public SwitchPort addPort(Integer i) {
+		SwitchPort port = new SwitchPort(this, i);
+		ports.put(port.getPortNumber(), port);
+		return port;
+	}
+	
+	public SwitchPort getPort(Integer i) {
+		return ports.get(i);
+	}
+	
+	public Collection<SwitchPort> getPorts() {
+		return ports.values();
+	}
+
+	public Collection<Link> getAdjLinks() {
+		LinkedList<Link> links = new LinkedList<Link>();
+		for (SwitchPort port: getPorts()) {
+			Link link = port.getOutgointLink(); 
+			if (link != null) {
+				links.add(link);
+			}
+		}
+		return links;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+}
diff --git a/src/test/java/net/onrc/onos/ofcontroller/app/SwitchPort.java b/src/test/java/net/onrc/onos/ofcontroller/app/SwitchPort.java
new file mode 100644
index 0000000..7bea465
--- /dev/null
+++ b/src/test/java/net/onrc/onos/ofcontroller/app/SwitchPort.java
@@ -0,0 +1,49 @@
+package net.onrc.onos.ofcontroller.app;
+
+/**
+ * This code is valid for the architectural study purpose only.
+ * @author Toshio Koide (t-koide@onlab.us)
+ */
+public class SwitchPort extends NetworkGraphEntity {
+	protected Switch parentSwitch;
+	protected Integer portNumber;
+	protected Link outgoingLink;
+	protected Link incomingLink;
+
+	public SwitchPort(Switch parentSwitch, Integer portNumber) {
+		super(parentSwitch.getNetworkGraph());
+		this.parentSwitch = parentSwitch;
+		this.portNumber = portNumber;
+	}
+
+	public Switch getSwitch() {
+		return parentSwitch;
+	}
+
+	public void setOutgoingLink(Link link) {
+		outgoingLink = link;
+	}
+
+	public Link getOutgointLink() {
+		return outgoingLink;
+	}
+
+	public void setIncomingLink(Link link) {
+		incomingLink = link;
+	}
+	
+	public Link getIncomingLink() {
+		return incomingLink;
+	}
+
+	public Integer getPortNumber() {
+		return portNumber;
+	}
+	
+	@Override
+	public String toString() {
+		return String.format("%s:%d",
+				getSwitch().getName(),
+				getPortNumber());
+	}
+}