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