REST API for flow summary /wm/flow/getsummary/{0}/{0}/json
Check network map for missing link even on update link in link discovery to address issue 249
Only the master controller should delete links to address issue 249
diff --git a/src/main/java/net/floodlightcontroller/flowcache/FlowManager.java b/src/main/java/net/floodlightcontroller/flowcache/FlowManager.java
index 36d1059..a0c1635 100644
--- a/src/main/java/net/floodlightcontroller/flowcache/FlowManager.java
+++ b/src/main/java/net/floodlightcontroller/flowcache/FlowManager.java
@@ -8,6 +8,7 @@
 import java.util.List;
 import java.util.Map;
 import java.util.TreeMap;
+import java.util.Collections;
 import java.util.concurrent.BlockingQueue;
 import java.util.concurrent.Executors;
 import java.util.concurrent.LinkedBlockingQueue;
@@ -274,11 +275,13 @@
 		    String userState = flowEntryObj.getUserState();
 		    String switchState = flowEntryObj.getSwitchState();
 
+		    /**
 		    log.debug("Found Flow Entry {}: {}",
 			      flowEntryId.toString(),
 			      "User State: " + userState +
 			      " Switch State: " + switchState);
-
+		     */
+		    
 		    if (! switchState.equals("FE_SWITCH_NOT_UPDATED")) {
 			// Ignore the entry: nothing to do
 			continue;
@@ -956,6 +959,61 @@
     }
 
     /**
+     * Get summary of all installed flows by all installers in a given range
+     *
+     * @param flowId the data path endpoints of the flows to get.
+     * @param maxFlows: the maximum number of flows to be returned
+     * @return the Flow Paths if found, otherwise null.
+     */
+    @Override
+    public ArrayList<FlowPath> getAllFlowsSummary(FlowId flowId, int maxFlows) {
+		//
+		// TODO: The implementation below is not optimal:
+		// We fetch all flows, and then return only the subset that match
+		// the query conditions.
+		// We should use the appropriate Titan/Gremlin query to filter-out
+		// the flows as appropriate.
+		//
+	    ArrayList<FlowPath> allFlows = getAllFlows();
+	
+		if (allFlows == null) {
+		    log.debug("Get FlowPathsSummary for {} {}: no FlowPaths found", flowId, maxFlows);
+		    return null;
+		}
+	
+		Collections.sort(allFlows);
+		
+		ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
+		for (FlowPath flow : allFlows) {
+			
+			// start from desired flowId
+			if (flow.flowId().value() < flowId.value()) {
+				continue;
+			}
+			
+			// Summarize by making null flow entry fields that are not relevant to report
+			for (FlowEntry flowEntry : flow.dataPath().flowEntries()) {
+				flowEntry.setFlowEntryActions(null);
+				flowEntry.setFlowEntryMatch(null);
+			}
+			
+		    flowPaths.add(flow);
+		    if (maxFlows != 0 && flowPaths.size() >= maxFlows) {
+		    	break;
+		    }
+		}
+	
+		if (flowPaths.isEmpty()) {
+		    log.debug("Get FlowPathsSummary {} {}: no FlowPaths found", flowId, maxFlows);
+		    flowPaths = null;
+		} else {
+		    log.debug("Get FlowPathsSummary for {} {}: FlowPaths were found", flowId, maxFlows);
+		}
+	
+		return flowPaths;
+    }
+    
+    /**
      * Get all installed flows by all installers.
      *
      * @return the Flow Paths if found, otherwise null.
diff --git a/src/main/java/net/floodlightcontroller/flowcache/IFlowService.java b/src/main/java/net/floodlightcontroller/flowcache/IFlowService.java
index 48477f1..41c0f57 100644
--- a/src/main/java/net/floodlightcontroller/flowcache/IFlowService.java
+++ b/src/main/java/net/floodlightcontroller/flowcache/IFlowService.java
@@ -68,6 +68,15 @@
     ArrayList<FlowPath> getAllFlows(DataPathEndpoints dataPathEndpoints);
 
     /**
+     * Get summary of all installed flows by all installers.
+     *
+     * @param flowId: starting flow Id of the range
+     * @param maxFlows: number of flows to return
+     * @return the Flow Paths if found, otherwise null.
+     */
+    ArrayList<FlowPath> getAllFlowsSummary(FlowId flowId, int maxFlows);
+    
+    /**
      * Get all installed flows by all installers.
      *
      * @return the Flow Paths if found, otherwise null.
diff --git a/src/main/java/net/floodlightcontroller/flowcache/web/FlowWebRoutable.java b/src/main/java/net/floodlightcontroller/flowcache/web/FlowWebRoutable.java
index a40a508..19f9e14 100644
--- a/src/main/java/net/floodlightcontroller/flowcache/web/FlowWebRoutable.java
+++ b/src/main/java/net/floodlightcontroller/flowcache/web/FlowWebRoutable.java
@@ -20,6 +20,7 @@
         router.attach("/getall-by-installer-id/{installer-id}/{src-dpid}/{src-port}/{dst-dpid}/{dst-port}/json", GetAllFlowsByInstallerIdResource.class);
         router.attach("/getall-by-endpoints/{src-dpid}/{src-port}/{dst-dpid}/{dst-port}/json", GetAllFlowsByEndpointsResource.class);
         router.attach("/getall/json", GetAllFlowsResource.class);
+        router.attach("/getsummary/{flow-id}/{max-flows}/json", GetSummaryFlowsResource.class);
         return router;
     }
 
diff --git a/src/main/java/net/floodlightcontroller/flowcache/web/GetSummaryFlowsResource.java b/src/main/java/net/floodlightcontroller/flowcache/web/GetSummaryFlowsResource.java
index 74a44d4..7a928c9 100644
--- a/src/main/java/net/floodlightcontroller/flowcache/web/GetSummaryFlowsResource.java
+++ b/src/main/java/net/floodlightcontroller/flowcache/web/GetSummaryFlowsResource.java
@@ -12,12 +12,15 @@
 import org.slf4j.LoggerFactory;
 
 public class GetSummaryFlowsResource extends ServerResource {
-    protected static Logger log = LoggerFactory.getLogger(GetAllFlowsResource.class);
+    protected static Logger log = LoggerFactory.getLogger(GetSummaryFlowsResource.class);
 
     @Get("json")
     public ArrayList<FlowPath> retrieve() {
     	ArrayList<FlowPath> result = null;
     	
+    	FlowId flowId;
+    	int maxFlows = 0;
+    	
     	IFlowService flowService = (IFlowService)getContext().getAttributes().get(IFlowService.class.getCanonicalName());
 
         if (flowService == null) {
@@ -26,11 +29,15 @@
         }
 
         // Extract the arguments
-        log.debug("Get All Flows Endpoints");
+    	String flowIdStr = (String) getRequestAttributes().get("flow-id");
+    	String maxFlowStr = (String) getRequestAttributes().get("max-flows");
+    	log.debug("Get Summary Flows starting flow-id: " + flowIdStr + " max-flows: " + maxFlowStr);
+    	
+    	flowId = new FlowId(flowIdStr);
+    	maxFlows = Integer.parseInt(maxFlowStr);
+    	if (maxFlows < 0) maxFlows = 0;
 
-        FlowId flowId = new FlowId(0);
-        
-        result = flowService.getAllFlowsSummary(flowId, 0);
+        result = flowService.getAllFlowsSummary(flowId, maxFlows);
 
         return result;
     }
diff --git a/src/main/java/net/floodlightcontroller/linkdiscovery/internal/LinkDiscoveryManager.java b/src/main/java/net/floodlightcontroller/linkdiscovery/internal/LinkDiscoveryManager.java
index b08fd8c..fa75769 100644
--- a/src/main/java/net/floodlightcontroller/linkdiscovery/internal/LinkDiscoveryManager.java
+++ b/src/main/java/net/floodlightcontroller/linkdiscovery/internal/LinkDiscoveryManager.java
@@ -42,31 +42,30 @@
 import net.floodlightcontroller.core.FloodlightContext;
 import net.floodlightcontroller.core.IFloodlightProviderService;
 import net.floodlightcontroller.core.IFloodlightProviderService.Role;
-import net.floodlightcontroller.core.INetMapStorage.DM_OPERATION;
 import net.floodlightcontroller.core.IHAListener;
 import net.floodlightcontroller.core.IInfoProvider;
+import net.floodlightcontroller.core.INetMapStorage.DM_OPERATION;
 import net.floodlightcontroller.core.IOFMessageListener;
 import net.floodlightcontroller.core.IOFSwitch;
-import net.floodlightcontroller.core.internal.OFSwitchImpl;
 import net.floodlightcontroller.core.IOFSwitchListener;
 import net.floodlightcontroller.core.annotations.LogMessageCategory;
 import net.floodlightcontroller.core.annotations.LogMessageDoc;
 import net.floodlightcontroller.core.annotations.LogMessageDocs;
-//import net.floodlightcontroller.core.internal.SwitchStorageImpl;
+import net.floodlightcontroller.core.internal.OFSwitchImpl;
 import net.floodlightcontroller.core.module.FloodlightModuleContext;
 import net.floodlightcontroller.core.module.FloodlightModuleException;
 import net.floodlightcontroller.core.module.IFloodlightModule;
 import net.floodlightcontroller.core.module.IFloodlightService;
 import net.floodlightcontroller.core.util.SingletonTask;
 import net.floodlightcontroller.linkdiscovery.ILinkDiscovery;
+import net.floodlightcontroller.linkdiscovery.ILinkDiscovery.LDUpdate;
 import net.floodlightcontroller.linkdiscovery.ILinkDiscovery.LinkType;
 import net.floodlightcontroller.linkdiscovery.ILinkDiscovery.SwitchType;
-import net.floodlightcontroller.linkdiscovery.ILinkDiscovery.LDUpdate;
 import net.floodlightcontroller.linkdiscovery.ILinkDiscovery.UpdateOperation;
-import net.floodlightcontroller.linkdiscovery.web.LinkDiscoveryWebRoutable;
 import net.floodlightcontroller.linkdiscovery.ILinkDiscoveryListener;
 import net.floodlightcontroller.linkdiscovery.ILinkDiscoveryService;
 import net.floodlightcontroller.linkdiscovery.LinkInfo;
+import net.floodlightcontroller.linkdiscovery.web.LinkDiscoveryWebRoutable;
 import net.floodlightcontroller.packet.BSN;
 import net.floodlightcontroller.packet.Ethernet;
 import net.floodlightcontroller.packet.IPv4;
@@ -75,8 +74,8 @@
 import net.floodlightcontroller.restserver.IRestApiService;
 import net.floodlightcontroller.routing.Link;
 import net.floodlightcontroller.storage.IResultSet;
-import net.floodlightcontroller.storage.IStorageSourceService;
 import net.floodlightcontroller.storage.IStorageSourceListener;
+import net.floodlightcontroller.storage.IStorageSourceService;
 import net.floodlightcontroller.storage.OperatorPredicate;
 import net.floodlightcontroller.storage.StorageException;
 import net.floodlightcontroller.threadpool.IThreadPoolService;
@@ -84,6 +83,10 @@
 import net.floodlightcontroller.util.EventHistory;
 import net.floodlightcontroller.util.EventHistory.EvAction;
 
+import net.onrc.onos.registry.controller.IControllerRegistryService;
+import net.onrc.onos.registry.controller.IControllerRegistryService.ControlChangeCallback;
+import net.onrc.onos.registry.controller.RegistryException;
+
 import org.openflow.protocol.OFMessage;
 import org.openflow.protocol.OFPacketIn;
 import org.openflow.protocol.OFPacketOut;
@@ -146,7 +149,7 @@
     protected IStorageSourceService storageSource;
     protected IThreadPoolService threadPool;
     protected IRestApiService restApi;
-
+    protected IControllerRegistryService registryService;
 
     // LLDP and BDDP fields
     private static final byte[] LLDP_STANDARD_DST_MAC_STRING = 
@@ -1172,6 +1175,14 @@
      * @param links The List of @LinkTuple to delete.
      */
     protected void deleteLinks(List<Link> links, String reason) {
+    	deleteLinks(links, reason, Boolean.TRUE);
+    }
+    
+    /**
+     * Removes links from memory and storage.
+     * @param links The List of @LinkTuple to delete.
+     */
+    protected void deleteLinks(List<Link> links, String reason, Boolean hasControl) {
         NodePortTuple srcNpt, dstNpt;
 
         lock.writeLock().lock();
@@ -1219,7 +1230,9 @@
                 removeLinkFromStorage(lt);
 
                 // remote link from network map
-                linkStore.update(lt, DM_OPERATION.DELETE);
+                if (hasControl) {
+                	linkStore.update(lt, DM_OPERATION.DELETE);
+                }
                 
                 // TODO  Whenever link is removed, it has to checked if
                 // the switchports must be added to quarantine.
@@ -1244,7 +1257,10 @@
 
         IOFSwitch iofSwitch = floodlightProvider.getSwitches().get(sw);
         if (iofSwitch == null) return Command.CONTINUE;
-
+        
+        // If we do not control this switch, then we should not process its port status messages
+        if (!registryService.hasControl(iofSwitch.getId())) return Command.CONTINUE;
+        
         if (log.isTraceEnabled()) {
             log.trace("handlePortStatus: Switch {} port #{} reason {}; " +
                     "config is {} state is {}",
@@ -1418,7 +1434,11 @@
                 }
                 // add all tuples with an endpoint on this switch to erase list
                 eraseList.addAll(switchLinks.get(sw));
-                deleteLinks(eraseList, "Switch Removed");
+                
+                // We can get called to delete links when we lose mastership. To avoid clearing the network map in that case,
+                // figure out if we have control of the switch
+                boolean hasControl = registryService.hasControl(sw);
+                deleteLinks(eraseList, "Switch Removed", hasControl);
 
                 // Send a switch removed update
                 LDUpdate update = new LDUpdate(sw, null, UpdateOperation.SWITCH_REMOVED);
@@ -1848,6 +1868,7 @@
         l.add(IStorageSourceService.class);
         l.add(IThreadPoolService.class);
         l.add(IRestApiService.class);
+        l.add(IControllerRegistryService.class);
         return l;
     }
 
@@ -1858,6 +1879,7 @@
         storageSource = context.getServiceImpl(IStorageSourceService.class);
         threadPool = context.getServiceImpl(IThreadPoolService.class);
         restApi = context.getServiceImpl(IRestApiService.class);
+        registryService = context.getServiceImpl(IControllerRegistryService.class);
 
         // Set the autoportfast feature to false.
         this.autoPortFastFeature = false;
diff --git a/src/main/java/net/floodlightcontroller/linkdiscovery/internal/LinkStorageImpl.java b/src/main/java/net/floodlightcontroller/linkdiscovery/internal/LinkStorageImpl.java
index 503f2f3..83abc8e 100644
--- a/src/main/java/net/floodlightcontroller/linkdiscovery/internal/LinkStorageImpl.java
+++ b/src/main/java/net/floodlightcontroller/linkdiscovery/internal/LinkStorageImpl.java
@@ -47,7 +47,6 @@
 	public void update(Link link, LinkInfo linkinfo, DM_OPERATION op) {
 		switch (op) {
 		case UPDATE:
-			break;
 		case CREATE:
 		case INSERT:
 			addOrUpdateLink(link, linkinfo, op);
diff --git a/src/main/java/net/floodlightcontroller/util/FlowPath.java b/src/main/java/net/floodlightcontroller/util/FlowPath.java
index 11f23fe..7fcb2e6 100644
--- a/src/main/java/net/floodlightcontroller/util/FlowPath.java
+++ b/src/main/java/net/floodlightcontroller/util/FlowPath.java
@@ -9,7 +9,7 @@
 /**
  * The class representing the Flow Path.
  */
-public class FlowPath {
+public class FlowPath implements Comparable<FlowPath> {
     private FlowId flowId;		// The Flow ID
     private CallerId installerId;	// The Caller ID of the path installer
     private DataPath dataPath;		// The data path
@@ -91,4 +91,13 @@
 	ret += "]";
 	return ret;
     }
+    
+    /**
+     * CompareTo method to order flowPath by Id
+     */
+    @Override
+    public int compareTo(FlowPath f) {
+    	return (int) (this.flowId.value() - f.flowId.value());
+    }
+
 }