Implemented asynchronous topology detection thread to determine when links are in the network map
diff --git a/src/main/java/net/onrc/onos/ofcontroller/bgproute/BgpRoute.java b/src/main/java/net/onrc/onos/ofcontroller/bgproute/BgpRoute.java
index 244c533..c57d4d8 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/bgproute/BgpRoute.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/bgproute/BgpRoute.java
@@ -6,9 +6,15 @@
 import java.net.UnknownHostException;
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Comparator;
 import java.util.HashMap;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.concurrent.ConcurrentSkipListSet;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
 
 import net.floodlightcontroller.core.IFloodlightProviderService;
 import net.floodlightcontroller.core.IOFSwitch;
@@ -17,13 +23,17 @@
 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.devicemanager.IDeviceService;
 import net.floodlightcontroller.packet.Ethernet;
 import net.floodlightcontroller.packet.IPv4;
 import net.floodlightcontroller.restserver.IRestApiService;
+import net.floodlightcontroller.routing.Link;
 import net.floodlightcontroller.topology.ITopologyListener;
 import net.floodlightcontroller.topology.ITopologyService;
+import net.onrc.onos.ofcontroller.core.INetMapTopologyService.ITopoLinkService;
 import net.onrc.onos.ofcontroller.core.INetMapTopologyService.ITopoRouteService;
+import net.onrc.onos.ofcontroller.core.internal.TopoLinkServiceImpl;
 import net.onrc.onos.ofcontroller.linkdiscovery.ILinkDiscovery;
 import net.onrc.onos.ofcontroller.linkdiscovery.ILinkDiscovery.LDUpdate;
 import net.onrc.onos.ofcontroller.proxyarp.ProxyArpManager;
@@ -86,19 +96,65 @@
 	
 	protected final short BGP_PORT = 179;
 	
+	protected final int TOPO_DETECTION_WAIT = 2; //seconds
+	
 	//Configuration stuff
 	protected Map<String, GatewayRouter> gatewayRouters;
 	protected List<String> switches;
 	protected Map<String, Interface> interfaces;
 	protected List<BgpPeer> bgpPeers;
-	//protected long bgpdAttachmentDpid;
-	//protected short bgpdAttachmentPort;
 	protected SwitchPort bgpdAttachmentPoint;
 	
 	//True when all switches have connected
 	protected volatile boolean switchesConnected = false;
 	//True when we have a full mesh of shortest paths between gateways
 	protected volatile boolean topologyReady = false;
+
+	//protected ConcurrentSkipListSet<LDUpdate> linkUpdates;
+	protected ArrayList<LDUpdate> linkUpdates;
+	protected SingletonTask topologyChangeDetectorTask;
+	
+	//protected ILinkStorage linkStorage;//XXX
+	
+	protected class TopologyChangeDetector implements Runnable {
+		@Override
+		public void run() {
+			log.debug("Running topology change detection task");
+			synchronized (linkUpdates) {
+				//This is the model the REST API uses to retrive network graph info
+				ITopoLinkService topoLinkService = new TopoLinkServiceImpl();
+				
+				List<Link> activeLinks = topoLinkService.getActiveLinks();
+				for (Link l : activeLinks){
+					log.debug("active link: {}", l);
+				}
+				
+				Iterator<LDUpdate> it = linkUpdates.iterator();
+				while (it.hasNext()){
+					LDUpdate ldu = it.next();
+					Link l = new Link(ldu.getSrc(), ldu.getSrcPort(), 
+							ldu.getDst(), ldu.getDstPort());
+					
+					if (activeLinks.contains(l)){
+						log.debug("Not found: {}", l);
+						it.remove();
+					}
+				}
+			}
+			
+			if (linkUpdates.isEmpty()){
+				//All updates have been seen in network map.
+				//We can check if topology is ready
+				log.debug("No know changes outstanding. Checking topology now");
+				checkStatus();
+			}
+			else {
+				//We know of some link updates that haven't propagated to the database yet
+				log.debug("Some changes not found in network map- size {}", linkUpdates.size());
+				topologyChangeDetectorTask.reschedule(TOPO_DETECTION_WAIT, TimeUnit.SECONDS);
+			}
+		}
+	}
 	
 	private void readGatewaysConfiguration(String gatewaysFilename){
 		File gatewaysFile = new File(gatewaysFilename);
@@ -177,6 +233,28 @@
 		//part of the controller core
 		proxyArp = new ProxyArpManager(floodlightProvider, topology);
 		
+		/*
+		linkStorage = new LinkStorageImpl();
+		//XXX Hack to pull out the database location from NetworkGraphPublisher's config
+		String databaseConfig = null;
+		for (IFloodlightModule fm : context.getAllModules()){
+			if (fm instanceof NetworkGraphPublisher){
+				Map<String, String> configMap = context.getConfigParams(fm);
+				databaseConfig = configMap.get("dbconf");
+				break;
+			}
+		}	
+		if (databaseConfig == null){
+			log.error("Couldn't find database config string \"dbconf\"");
+			System.exit(1);
+		}
+		linkStorage.init(databaseConfig);
+		*/
+		//linkUpdates = new ConcurrentSkipListSet<ILinkDiscovery.LDUpdate>();
+		linkUpdates = new ArrayList<LDUpdate>();
+		ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
+		topologyChangeDetectorTask = new SingletonTask(executor, new TopologyChangeDetector());
+		
 		//Read in config values
 		bgpdRestIp = context.getConfigParams(this).get("BgpdRestIp");
 		if (bgpdRestIp == null){
@@ -793,6 +871,7 @@
 	private void beginRouting(){
 		log.debug("Topology is now ready, beginning routing function");
 		setupBgpPaths();
+		setupFullMesh();
 		
 		//Traverse ptree and create flows for all routes
 		for (PtreeNode node = ptree.begin(); node != null; node = ptree.next(node)){
@@ -875,16 +954,41 @@
 				//They happen way too frequently (may be a bug in our link discovery)
 				refreshNeeded = true;
 			}
+			
 			log.debug("Topo change {}", ldu.getOperation());
+			/*
+			if (ldu.getOperation().equals(ILinkDiscovery.UpdateOperation.LINK_ADDED)){
+				log.debug("Link Added: src={} outPort={} dst={} inPort={}",
+						new Object[] {
+						HexString.toHexString(ldu.getSrc()), ldu.getSrcPort(),
+						HexString.toHexString(ldu.getDst()), ldu.getDstPort()});
+				TopoLinkServiceImpl impl = new TopoLinkServiceImpl();
+				
+				List<Link> retval = impl.getActiveLinks();
+				
+				log.debug("retval size {}", retval.size());
+				
+				for (Link l : retval){
+					log.debug("link {}", l);
+				}
+			}
+			*/
+			if (ldu.getOperation().equals(ILinkDiscovery.UpdateOperation.LINK_ADDED)){
+				synchronized (linkUpdates) {
+					linkUpdates.add(ldu);
+				}
+			}
 		}
 		
 		if (refreshNeeded){
-			if (topologyReady){
+			topologyChangeDetectorTask.reschedule(TOPO_DETECTION_WAIT, TimeUnit.SECONDS);
+			/*if (topologyReady){
 				setupFullMesh();
 			}
 			else{
 				checkStatus();
-			}
+			}*/
+			
 		}
 	}