Optimize rerouting

- calculates multiple link down events at one time

Change-Id: I18cca13c8d9da29d675b4650b5be61922041c861
diff --git a/src/main/java/net/onrc/onos/intent/runtime/PathCalcRuntimeModule.java b/src/main/java/net/onrc/onos/intent/runtime/PathCalcRuntimeModule.java
index 2c269fd..6bdca51 100755
--- a/src/main/java/net/onrc/onos/intent/runtime/PathCalcRuntimeModule.java
+++ b/src/main/java/net/onrc/onos/intent/runtime/PathCalcRuntimeModule.java
@@ -3,6 +3,7 @@
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Iterator;
 import java.util.Map;
 
@@ -38,24 +39,41 @@
 	private INetworkGraphService networkGraphService;
 	private IntentMap highLevelIntents;
 	private PathIntentMap pathIntents;
-        private IControllerRegistryService controllerRegistry;
-        private PersistIntent persistIntent;
+	private IControllerRegistryService controllerRegistry;
+	private PersistIntent persistIntent;
 
 	private IEventChannel<Long, IntentOperationList> eventChannel;
 	private static final String EVENT_CHANNEL_NAME = "onos.pathintent";
 
-	private void reroutePaths(LinkEvent linkEvent) {
-		Collection<PathIntent> oldPaths = pathIntents.getIntentsByLink(linkEvent);
-		if (oldPaths == null) return;
+	// ================================================================================
+	// private methods
+	// ================================================================================
+
+	private void reroutePaths(Collection<LinkEvent> removedLinkEvents) {
+		HashSet<PathIntent> oldPaths = new HashSet<>();
+		for (LinkEvent linkEvent : removedLinkEvents) {
+			Collection<PathIntent> intents = pathIntents.getIntentsByLink(linkEvent);
+			if (intents == null)
+				continue;
+			oldPaths.addAll(intents);
+		}
+
+		if (oldPaths.isEmpty())
+			return;
 		IntentOperationList reroutingOperation = new IntentOperationList();
-		for (PathIntent pathIntent: oldPaths) {
-			// TODO use Operator.UPDATE instead of REMOVE and ADD in order to optimize
+		for (PathIntent pathIntent : oldPaths) {
+			// TODO use Operator.UPDATE instead of REMOVE and ADD in order to
+			// optimize
 			reroutingOperation.add(Operator.REMOVE, new Intent(pathIntent.getParentIntent().getId()));
 			reroutingOperation.add(Operator.ADD, pathIntent.getParentIntent());
 		}
 		executeIntentOperations(reroutingOperation);
 	}
 
+	// ================================================================================
+	// IFloodlightModule implementations
+	// ================================================================================
+
 	@Override
 	public Collection<Class<? extends IFloodlightService>> getModuleServices() {
 		Collection<Class<? extends IFloodlightService>> l = new ArrayList<>(1);
@@ -82,7 +100,7 @@
 	public void init(FloodlightModuleContext context) throws FloodlightModuleException {
 		datagridService = context.getServiceImpl(IDatagridService.class);
 		networkGraphService = context.getServiceImpl(INetworkGraphService.class);
-                controllerRegistry = context.getServiceImpl(IControllerRegistryService.class);
+		controllerRegistry = context.getServiceImpl(IControllerRegistryService.class);
 	}
 
 	@Override
@@ -90,15 +108,16 @@
 		highLevelIntents = new IntentMap();
 		runtime = new PathCalcRuntime(networkGraphService.getNetworkGraph());
 		pathIntents = new PathIntentMap();
-		eventChannel = datagridService.createChannel(
-				EVENT_CHANNEL_NAME,
-				Long.class,
-				IntentOperationList.class);
+		eventChannel = datagridService.createChannel(EVENT_CHANNEL_NAME, Long.class, IntentOperationList.class);
 		networkGraphService.registerNetworkGraphListener(this);
-                persistIntent = new PersistIntent(controllerRegistry, networkGraphService);
+		persistIntent = new PersistIntent(controllerRegistry, networkGraphService);
 
 	}
 
+	// ================================================================================
+	// IPathCalcRuntimeService implementations
+	// ================================================================================
+
 	@Override
 	public IntentOperationList executeIntentOperations(IntentOperationList list) {
 		// update the map of high-level intents
@@ -106,7 +125,7 @@
 
 		// prepare high-level intents' state changes
 		HashMap<String, IntentState> states = new HashMap<>();
-		for (IntentOperation op: list) {
+		for (IntentOperation op : list) {
 			String id = op.intent.getId();
 			states.put(id, IntentState.INST_REQ);
 		}
@@ -129,7 +148,8 @@
 		}
 		highLevelIntents.changeStates(states);
 
-		// update the map of low-level intents and publish the low-level operations
+		// update the map of low-level intents and publish the low-level
+		// operations
 		pathIntents.executeOperations(pathIntentOperations);
 		eventChannel.addEntry(key, pathIntentOperations);
 		return pathIntentOperations;
@@ -151,19 +171,21 @@
 		pathIntents.purge();
 	}
 
+	// ================================================================================
+	// INetworkGraphListener implementations
+	// ================================================================================
+
 	@Override
-	public void networkGraphEvents(
-				Collection<SwitchEvent> addedSwitchEvents,
-				Collection<SwitchEvent> removedSwitchEvents,
-				Collection<PortEvent> addedPortEvents,
-				Collection<PortEvent> removedPortEvents,
-				Collection<LinkEvent> addedLinkEvents,
-				Collection<LinkEvent> removedLinkEvents,
-				Collection<DeviceEvent> addedDeviceEvents,
-				Collection<DeviceEvent> removedDeviceEvents) {
-	    // TODO: The implementation below is incomplete
-	    for (LinkEvent linkEvent : removedLinkEvents) {
-		reroutePaths(linkEvent);
-	    }
+	public void networkGraphEvents(Collection<SwitchEvent> addedSwitchEvents,
+			Collection<SwitchEvent> removedSwitchEvents,
+			Collection<PortEvent> addedPortEvents,
+			Collection<PortEvent> removedPortEvents,
+			Collection<LinkEvent> addedLinkEvents,
+			Collection<LinkEvent> removedLinkEvents,
+			Collection<DeviceEvent> addedDeviceEvents,
+			Collection<DeviceEvent> removedDeviceEvents) {
+		// TODO need optimization.
+		// This reroutes only if when some links are removed for now.
+		reroutePaths(removedLinkEvents);
 	}
-}
+}
\ No newline at end of file
diff --git a/src/test/java/net/onrc/onos/intent/runtime/UseCaseTest.java b/src/test/java/net/onrc/onos/intent/runtime/UseCaseTest.java
index d060cf1..698f790 100755
--- a/src/test/java/net/onrc/onos/intent/runtime/UseCaseTest.java
+++ b/src/test/java/net/onrc/onos/intent/runtime/UseCaseTest.java
@@ -18,13 +18,13 @@
 import net.onrc.onos.intent.PathIntentMap;
 import net.onrc.onos.intent.ShortestPathIntent;
 import net.onrc.onos.intent.persist.PersistIntent;
+import net.onrc.onos.ofcontroller.networkgraph.DeviceEvent;
 import net.onrc.onos.ofcontroller.networkgraph.INetworkGraphListener;
 import net.onrc.onos.ofcontroller.networkgraph.INetworkGraphService;
-import net.onrc.onos.ofcontroller.networkgraph.DeviceEvent;
 import net.onrc.onos.ofcontroller.networkgraph.LinkEvent;
+import net.onrc.onos.ofcontroller.networkgraph.NetworkGraph;
 import net.onrc.onos.ofcontroller.networkgraph.PortEvent;
 import net.onrc.onos.ofcontroller.networkgraph.SwitchEvent;
-import net.onrc.onos.ofcontroller.networkgraph.NetworkGraph;
 import net.onrc.onos.registry.controller.IControllerRegistryService;
 
 import org.easymock.EasyMock;
@@ -46,8 +46,8 @@
 	private FloodlightModuleContext modContext;
 	private IDatagridService datagridService;
 	private INetworkGraphService networkGraphService;
-        private IControllerRegistryService controllerRegistryService;
-        private PersistIntent persistIntent;
+	private IControllerRegistryService controllerRegistryService;
+	private PersistIntent persistIntent;
 	@SuppressWarnings("rawtypes")
 	private IEventChannel eventChannel;
 
@@ -60,24 +60,24 @@
 
 		datagridService = EasyMock.createMock(IDatagridService.class);
 		networkGraphService = EasyMock.createMock(INetworkGraphService.class);
-                controllerRegistryService = EasyMock.createMock(IControllerRegistryService.class);
+		controllerRegistryService = EasyMock.createMock(IControllerRegistryService.class);
 		modContext = EasyMock.createMock(FloodlightModuleContext.class);
 		eventChannel = EasyMock.createMock(IEventChannel.class);
-                persistIntent = PowerMock.createMock(PersistIntent.class);
-                
-                PowerMock.expectNew(PersistIntent.class,
-                        EasyMock.anyObject(IControllerRegistryService.class),
-                        EasyMock.anyObject(INetworkGraphService.class)).andReturn(persistIntent);
+		persistIntent = PowerMock.createMock(PersistIntent.class);
+
+		PowerMock.expectNew(PersistIntent.class,
+				EasyMock.anyObject(IControllerRegistryService.class),
+				EasyMock.anyObject(INetworkGraphService.class)).andReturn(persistIntent);
 
 		EasyMock.expect(modContext.getServiceImpl(EasyMock.eq(IDatagridService.class)))
 		.andReturn(datagridService).once();
 		EasyMock.expect(modContext.getServiceImpl(EasyMock.eq(INetworkGraphService.class)))
 		.andReturn(networkGraphService).once();
-                EasyMock.expect(modContext.getServiceImpl(EasyMock.eq(IControllerRegistryService.class)))
-                        .andReturn(controllerRegistryService).once();
-                EasyMock.expect(persistIntent.getKey()).andReturn(1L).anyTimes();
-                EasyMock.expect(persistIntent.persistIfLeader(EasyMock.eq(1L), 
-                        EasyMock.anyObject(IntentOperationList.class))).andReturn(true).anyTimes();
+		EasyMock.expect(modContext.getServiceImpl(EasyMock.eq(IControllerRegistryService.class)))
+		.andReturn(controllerRegistryService).once();
+		EasyMock.expect(persistIntent.getKey()).andReturn(1L).anyTimes();
+		EasyMock.expect(persistIntent.persistIfLeader(EasyMock.eq(1L),
+				EasyMock.anyObject(IntentOperationList.class))).andReturn(true).anyTimes();
 
 		EasyMock.expect(networkGraphService.getNetworkGraph()).andReturn(g).anyTimes();
 		networkGraphService.registerNetworkGraphListener(EasyMock.anyObject(INetworkGraphListener.class));
@@ -89,8 +89,8 @@
 		EasyMock.replay(datagridService);
 		EasyMock.replay(networkGraphService);
 		EasyMock.replay(modContext);
-                EasyMock.replay(controllerRegistryService);
-                PowerMock.replay(persistIntent, PersistIntent.class);
+		EasyMock.replay(controllerRegistryService);
+		PowerMock.replay(persistIntent, PersistIntent.class);
 	}
 
 	@After
@@ -98,8 +98,8 @@
 		EasyMock.verify(datagridService);
 		EasyMock.verify(networkGraphService);
 		EasyMock.verify(modContext);
-                EasyMock.verify(controllerRegistryService);
-                PowerMock.verify(persistIntent, PersistIntent.class);
+		EasyMock.verify(controllerRegistryService);
+		PowerMock.verify(persistIntent, PersistIntent.class);
 	}
 
 	private void showResult(PathIntentMap intents) {
@@ -222,27 +222,29 @@
 		LinkEvent linkEvent = new LinkEvent(1L, 2L, 9L, 1L);
 		removedLinkEvents.clear();
 		removedLinkEvents.add(linkEvent);
-		runtime1.networkGraphEvents(addedSwitchEvents,
-					    removedSwitchEvents,
-					    addedPortEvents,
-					    removedPortEvents,
-					    addedLinkEvents,
-					    removedLinkEvents,
-					    addedDeviceEvents,
-					    removedDeviceEvents);
+		runtime1.networkGraphEvents(
+				addedSwitchEvents,
+				removedSwitchEvents,
+				addedPortEvents,
+				removedPortEvents,
+				addedLinkEvents,
+				removedLinkEvents,
+				addedDeviceEvents,
+				removedDeviceEvents);
 
 		((MockNetworkGraph)g).removeLink(9L, 1L, 1L, 2L);
 		linkEvent = new LinkEvent(9L, 1L, 1L, 2L);
 		removedLinkEvents.clear();
 		removedLinkEvents.add(linkEvent);
-		runtime1.networkGraphEvents(addedSwitchEvents,
-					    removedSwitchEvents,
-					    addedPortEvents,
-					    removedPortEvents,
-					    addedLinkEvents,
-					    removedLinkEvents,
-					    addedDeviceEvents,
-					    removedDeviceEvents);
+		runtime1.networkGraphEvents(
+				addedSwitchEvents,
+				removedSwitchEvents,
+				addedPortEvents,
+				removedPortEvents,
+				addedLinkEvents,
+				removedLinkEvents,
+				addedDeviceEvents,
+				removedDeviceEvents);
 		System.out.println("Link goes down.");
 
 		// show results step2