Add PathCalcRuntime class

- creates a set of PathIntent from a set of ShortestPathIntent and/or ConstrainedShortestPathIntent

Change-Id: Icbff563cad43611abe4a8f1555b6937719f2ee88
diff --git a/src/main/java/net/onrc/onos/intent/runtime/PathCalcRuntime.java b/src/main/java/net/onrc/onos/intent/runtime/PathCalcRuntime.java
new file mode 100644
index 0000000..3e09f8c
--- /dev/null
+++ b/src/main/java/net/onrc/onos/intent/runtime/PathCalcRuntime.java
@@ -0,0 +1,80 @@
+package net.onrc.onos.intent.runtime;
+
+import java.util.Collection;
+import java.util.HashSet;
+
+import net.onrc.onos.intent.ConstrainedBFSTree;
+import net.onrc.onos.intent.ConstrainedShortestPathIntent;
+import net.onrc.onos.intent.Intent;
+import net.onrc.onos.intent.PathIntent;
+import net.onrc.onos.intent.PathIntents;
+import net.onrc.onos.intent.ShortestPathIntent;
+import net.onrc.onos.ofcontroller.networkgraph.NetworkGraph;
+import net.onrc.onos.ofcontroller.networkgraph.Path;
+import net.onrc.onos.ofcontroller.networkgraph.Switch;
+
+/**
+ * @author Toshio Koide (t-koide@onlab.us)
+ */
+public class PathCalcRuntime {
+	NetworkGraph graph;
+	HashSet<Intent> inputIntents = new HashSet<Intent>();
+	PathIntents outputIntents = new PathIntents();
+
+	public PathCalcRuntime(NetworkGraph g) {
+		this.graph = g;
+	}
+
+	public Collection<Intent> getInputIntents() {
+		return inputIntents;
+	}
+
+	public PathIntents getOutputIntents() {
+		return outputIntents;
+	}
+
+	public void addInputIntents(Collection<Intent> inputIntents) {
+		this.inputIntents.addAll(inputIntents);
+		this.outputIntents = calcPathIntents(inputIntents);
+	}
+
+	protected PathIntents calcPathIntents(Collection<Intent> originalIntents) {
+		PathIntents pathIntents = new PathIntents();
+
+		for (Intent intent: originalIntents) {
+			if (!(intent instanceof ShortestPathIntent)) {
+				// unsupported intent type.
+				// TODO should push back the intent to caller
+				continue;
+			}
+
+			ShortestPathIntent spIntent = (ShortestPathIntent) intent;
+			Switch srcSwitch = spIntent.getSourcePort().getSwitch();
+			Switch dstSwitch = spIntent.getDestinationPort().getSwitch();
+			if (srcSwitch == null || dstSwitch == null) {
+				// incomplete intent.
+				// TODO should push back the intent to caller
+				continue;
+			}
+
+			Double bandwidth = null;
+			ConstrainedBFSTree tree = null;
+			if (intent instanceof ConstrainedShortestPathIntent) {
+				bandwidth = ((ConstrainedShortestPathIntent) intent).getBandwidth();
+				tree = new ConstrainedBFSTree(srcSwitch, pathIntents, bandwidth);
+			}
+			else {
+				tree = new ConstrainedBFSTree(srcSwitch);
+			}
+			Path path = tree.getPath(dstSwitch);
+			if (path == null) {
+				// path not found.
+				// TODO should push back the intent to caller
+				continue;
+			}
+
+			pathIntents.addIntent(new PathIntent(path, bandwidth, intent));
+		}
+		return pathIntents;
+	}
+}
\ No newline at end of file
diff --git a/src/main/java/net/onrc/onos/ofcontroller/networkgraph/MutableNetworkGraph.java b/src/main/java/net/onrc/onos/ofcontroller/networkgraph/MutableNetworkGraph.java
deleted file mode 100644
index ea4b6a9..0000000
--- a/src/main/java/net/onrc/onos/ofcontroller/networkgraph/MutableNetworkGraph.java
+++ /dev/null
@@ -1,126 +0,0 @@
-package net.onrc.onos.ofcontroller.networkgraph;
-
-import java.net.InetAddress;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.LinkedList;
-
-import net.floodlightcontroller.util.MACAddress;
-
-/**
- * @author Toshio Koide (t-koide@onlab.us)
- */
-public class MutableNetworkGraph implements NetworkGraph {
-	protected HashMap<Long, SwitchImpl> switches;
-	protected HashMap<MACAddress, Device> devices;
-	
-	public MutableNetworkGraph() {
-		switches = new HashMap<Long, SwitchImpl>();
-		devices = new HashMap<MACAddress, Device>();
-	}
-
-	// Switch operations
-	
-	public Switch addSwitch(Long switchId) {
-		if (switches.containsKey(switchId)) {
-			return null; // should throw exception
-		}
-		SwitchImpl sw = new SwitchImpl(this, switchId);
-		switches.put(sw.getDpid(), sw);
-		return sw;
-		
-	}
-
-	@Override
-	public Switch getSwitch(Long dpid) {
-		return switches.get(dpid);
-	}
-	
-	@Override
-	public Iterable<? extends Switch> getSwitches() {
-		return switches.values();
-	}
-	
-	// Link operations
-	
-	public Link addLink(Long srcDpid, Long srcPortNo, Long dstDpid, Long dstPortNo) {
-		return new LinkImpl(
-				this,
-				getSwitch(srcDpid).getPort(srcPortNo),
-				getSwitch(dstDpid).getPort(dstPortNo));
-	}
-	
-	public Link[] addBidirectionalLinks(Long srcDpid, Long srcPortNo, Long dstDpid, Long dstPortNo) {
-		Link[] links = new Link[2];
-		links[0] = addLink(srcDpid, srcPortNo, dstDpid, dstPortNo);
-		links[1] = addLink(dstDpid, dstPortNo, srcDpid, srcPortNo);
-		
-		return links;
-	}
-	
-	@Override
-	public Collection<Link> getLinks() {
-		LinkedList<Link> links = new LinkedList<Link>();
-		for (Switch sw: switches.values()) {
-			for (Port port: sw.getPorts()) {
-				Link link = port.getOutgoingLink();
-				if (link != null) {
-					links.add(link);
-				}
-			}
-		}
-		return links;
-	}
-
-	@Override
-	public Iterable<Link> getOutgoingLinksFromSwitch(Long dpid) {
-		LinkedList<Link> links = new LinkedList<Link>();
-		for (Port port: getSwitch(dpid).getPorts()) {
-			Link link = port.getOutgoingLink();
-			if (link != null) {
-				links.add(link);
-			}
-		}
-		return links;
-	}
-
-	@Override
-	public Iterable<Link> getIncomingLinksFromSwitch(Long dpid) {
-		LinkedList<Link> links = new LinkedList<Link>();
-		for (Port port: getSwitch(dpid).getPorts()) {
-			Link link = port.getIncomingLink();
-			if (link != null) {
-				links.add(link);
-			}
-		}
-		return links;
-	}
-	
-	// Device operations
-
-	@Override
-	public Iterable<Device> getDeviceByIp(InetAddress ipAddress) {
-		// TODO optimize it
-		HashSet<Device> result = new HashSet<Device>();
-		for (Device d: devices.values()) {
-			Collection<InetAddress> addrs = d.getIpAddress();
-			for (InetAddress addr: addrs) {
-				if (addr.equals(ipAddress)) {
-					result.add(d);
-					break;
-				}
-			}
-		}
-		return result;
-	}
-
-	@Override
-	public Device getDeviceByMac(MACAddress address) {
-		return devices.get(address);
-	}
-
-	public void addDevice(Device device) {
-		devices.put(device.getMacAddress(), device);
-	}
-}
diff --git a/src/test/java/net/onrc/onos/intent/runtime/UseCaseTest.java b/src/test/java/net/onrc/onos/intent/runtime/UseCaseTest.java
new file mode 100644
index 0000000..8f7b02f
--- /dev/null
+++ b/src/test/java/net/onrc/onos/intent/runtime/UseCaseTest.java
@@ -0,0 +1,164 @@
+package net.onrc.onos.intent.runtime;
+
+import java.util.LinkedList;
+
+import net.onrc.onos.intent.ConstrainedShortestPathIntent;
+import net.onrc.onos.intent.Intent;
+import net.onrc.onos.intent.PathIntent;
+import net.onrc.onos.intent.PathIntents;
+import net.onrc.onos.intent.ShortestPathIntent;
+import net.onrc.onos.ofcontroller.networkgraph.*;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * @author Toshio Koide (t-koide@onlab.us)
+ */
+public class UseCaseTest {
+	public class MutableNetworkGraph extends AbstractNetworkGraph {
+		public Switch addSwitch(Long switchId) {
+			SwitchImpl sw = new SwitchImpl(this, switchId);
+			switches.put(sw.getDpid(), sw);
+			return sw;
+
+		}
+
+		public Link addLink(Long srcDpid, Long srcPortNo, Long dstDpid, Long dstPortNo) {
+			return new LinkImpl(
+					this,
+					getSwitch(srcDpid).getPort(srcPortNo),
+					getSwitch(dstDpid).getPort(dstPortNo));
+		}
+
+		public Link[] addBidirectionalLinks(Long srcDpid, Long srcPortNo, Long dstDpid, Long dstPortNo) {
+			Link[] links = new Link[2];
+			links[0] = addLink(srcDpid, srcPortNo, dstDpid, dstPortNo);
+			links[1] = addLink(dstDpid, dstPortNo, srcDpid, srcPortNo);
+
+			return links;
+		}
+	}
+
+	NetworkGraph g;
+
+	@Before
+	public void setUp() {
+		MutableNetworkGraph g = new MutableNetworkGraph();
+
+		// add 10 switches (24 ports switch)
+		for (Long dpid=1L; dpid<10L; dpid++) {
+			SwitchImpl sw = (SwitchImpl) g.addSwitch(dpid);
+			for (Long j=1L; j<=24L; j++) {
+				sw.addPort(j);
+			}
+		}
+
+		// add loop path
+		g.addBidirectionalLinks(1L, 1L, 2L, 2L);
+		g.addBidirectionalLinks(2L, 1L, 3L, 2L);
+		g.addBidirectionalLinks(3L, 1L, 4L, 2L);
+		g.addBidirectionalLinks(4L, 1L, 5L, 2L);
+		g.addBidirectionalLinks(5L, 1L, 6L, 2L);
+		g.addBidirectionalLinks(6L, 1L, 7L, 2L);
+		g.addBidirectionalLinks(7L, 1L, 8L, 2L);
+		g.addBidirectionalLinks(8L, 1L, 9L, 2L);
+		g.addBidirectionalLinks(9L, 1L, 1L, 2L);
+
+		// add other links
+		g.addBidirectionalLinks(1L, 3L, 5L, 3L);
+		g.addBidirectionalLinks(2L, 4L, 5L, 4L);
+		g.addBidirectionalLinks(2L, 5L, 7L, 5L);
+		g.addBidirectionalLinks(3L, 6L, 7L, 6L);
+		g.addBidirectionalLinks(3L, 7L, 8L, 7L);
+		g.addBidirectionalLinks(3L, 8L, 9L, 8L);
+		g.addBidirectionalLinks(4L, 9l, 9L, 9L);
+
+		// set capacity of all links to 1000Mbps
+		for (Link link: g.getLinks()) {
+			((LinkImpl)link).setCapacity(1000.0);
+		}
+
+		/*
+		// add Devices
+		for (Long l=1L; l<=9L; l++) {
+			DeviceImpl d = new DeviceImpl(g, MACAddress.valueOf(l));
+			d.addAttachmentPoint(g.getSwitch(l).getPort(20L));
+			g.addDevice(d);
+		}
+		*/
+
+		this.g = g;
+	}
+
+	@After
+	public void tearDown() {
+	}
+
+	private void showResult(PathIntents intents) {
+		for (PathIntent pathIntent: intents.getIntents()) {
+			System.out.println("Parent intent: " + pathIntent.getParentIntent().toString());
+			System.out.println("Path:");
+			for (Link link: pathIntent.getPath()) {
+				System.out.printf("%s --(%f/%f)--> %s\n",
+						link.getSourcePort(),
+						link.getCapacity() - intents.getAvailableBandwidth(link),
+						link.getCapacity(),
+						link.getDestinationPort());
+			}
+		}
+	}
+
+	@Test
+	public void useCase1() {
+		// create shortest path intents
+		LinkedList<Intent> intents = new LinkedList<Intent>();
+		intents.add(new ShortestPathIntent(g, 1L, 20L, 1L, 4L, 20L, 4L));
+		intents.add(new ShortestPathIntent(g, 2L, 20L, 2L, 6L, 20L, 5L));
+		intents.add(new ShortestPathIntent(g, 4L, 20L, 3L, 8L, 20L, 6L));
+
+		// compile high-level intents into low-level intents (calculate paths)
+		PathCalcRuntime runtime1 = new PathCalcRuntime(g);
+		runtime1.addInputIntents(intents);
+
+		// show results
+		showResult(runtime1.getOutputIntents());
+	}
+
+	@Test
+	public void useCase2() {
+		// create constrained shortest path intents
+		LinkedList<Intent> intents = new LinkedList<Intent>();
+		intents.add(new ConstrainedShortestPathIntent(g, 1L, 20L, 1L, 4L, 20L, 17L, 400.0));
+		intents.add(new ConstrainedShortestPathIntent(g, 2L, 20L, 2L, 6L, 20L, 18L, 400.0));
+		intents.add(new ConstrainedShortestPathIntent(g, 4L, 20L, 3L, 8L, 20L, 19L, 400.0));
+		intents.add(new ConstrainedShortestPathIntent(g, 3L, 20L, 4L, 8L, 20L, 20L, 400.0));
+		intents.add(new ConstrainedShortestPathIntent(g, 4L, 20L, 5L, 8L, 20L, 21L, 400.0));
+
+		// compile high-level intents into low-level intents (calculate paths)
+		PathCalcRuntime runtime1 = new PathCalcRuntime(g);
+		runtime1.addInputIntents(intents);
+
+		// show results
+		showResult(runtime1.getOutputIntents());
+	}
+
+	@Test
+	public void useCase3() {
+		// create constrained & not best effort shortest path intents
+		LinkedList<Intent> intents = new LinkedList<Intent>();
+		intents.add(new ConstrainedShortestPathIntent(g, 1L, 20L, 1L, 4L, 20L, 6L, 600.0));
+		intents.add(new ConstrainedShortestPathIntent(g, 2L, 20L, 2L, 6L, 20L, 7L, 600.0));
+		intents.add(new ShortestPathIntent(g, 4L, 20L, 3L, 8L, 20L, 8L));
+		intents.add(new ShortestPathIntent(g, 4L, 20L, 4L, 8L, 20L, 9L));
+		intents.add(new ConstrainedShortestPathIntent(g, 4L, 20L, 5L, 8L, 20L, 10L, 600.0));
+
+		// compile high-level intents into low-level intents (calculate paths)
+		PathCalcRuntime runtime1 = new PathCalcRuntime(g);
+		runtime1.addInputIntents(intents);
+
+		// show results
+		showResult(runtime1.getOutputIntents());
+	}
+}