Implemented the API method to get all switch-controller information from Zookeeper. Also implemented the informational REST APIs for the Registry service
diff --git a/src/main/java/net/onrc/onos/registry/controller/ControllerRegistryEntry.java b/src/main/java/net/onrc/onos/registry/controller/ControllerRegistryEntry.java
new file mode 100644
index 0000000..69fdf0b
--- /dev/null
+++ b/src/main/java/net/onrc/onos/registry/controller/ControllerRegistryEntry.java
@@ -0,0 +1,27 @@
+package net.onrc.onos.registry.controller;
+
+import org.codehaus.jackson.annotate.JsonProperty;
+
+
+public class ControllerRegistryEntry implements Comparable<ControllerRegistryEntry> {
+
+	private String controllerId;
+	private int sequenceNumber;
+	
+	public ControllerRegistryEntry(String controllerId, int sequenceNumber) {
+		this.controllerId = controllerId;
+		this.sequenceNumber = sequenceNumber;
+	}
+	
+	@JsonProperty("controllerId")
+	public String getControllerId(){
+		return controllerId;
+	}
+
+	@Override
+	public int compareTo(ControllerRegistryEntry o) {
+		return sequenceNumber - o.sequenceNumber;
+		//return 0;
+	}
+
+}
diff --git a/src/main/java/net/onrc/onos/registry/controller/ControllerRegistryResource.java b/src/main/java/net/onrc/onos/registry/controller/ControllerRegistryResource.java
new file mode 100644
index 0000000..51f1d32
--- /dev/null
+++ b/src/main/java/net/onrc/onos/registry/controller/ControllerRegistryResource.java
@@ -0,0 +1,35 @@
+package net.onrc.onos.registry.controller;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+import org.restlet.resource.Get;
+import org.restlet.resource.ServerResource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ControllerRegistryResource extends ServerResource {
+
+	protected static Logger log = LoggerFactory.getLogger(ControllerRegistryResource.class);
+
+	@Get("json")
+	public Collection<String> getControllers() {
+		IControllerRegistryService registry = 
+				(IControllerRegistryService) getContext().getAttributes().
+				get(IControllerRegistryService.class.getCanonicalName());
+		
+		Collection<String> controllers = null;
+		try {
+			controllers = registry.getAllControllers();
+		} catch (RegistryException e) {
+			log.warn("Error retrieving controller list: {}", e.getMessage());
+		}
+		
+		if (controllers == null){
+			controllers = new ArrayList<String>();
+		}
+		
+		return controllers;
+	}
+	
+}
diff --git a/src/main/java/net/onrc/onos/registry/controller/IControllerRegistryService.java b/src/main/java/net/onrc/onos/registry/controller/IControllerRegistryService.java
index f2794cc..e924f6a 100644
--- a/src/main/java/net/onrc/onos/registry/controller/IControllerRegistryService.java
+++ b/src/main/java/net/onrc/onos/registry/controller/IControllerRegistryService.java
@@ -1,6 +1,7 @@
 package net.onrc.onos.registry.controller;
 
 import java.util.Collection;
+import java.util.List;
 import java.util.Map;
 
 import net.floodlightcontroller.core.module.IFloodlightService;
@@ -14,7 +15,7 @@
 	}
 	
 	// Acquire mastership for a switch. 
-	public void requestControl(long dpid, ControlChangeCallback cb) throws Exception;
+	public void requestControl(long dpid, ControlChangeCallback cb) throws RegistryException;
 	
 	// Release mastership for a switch
 	public void releaseControl(long dpid);
@@ -42,7 +43,7 @@
 	
 	public String getControllerForSwitch(long dpid) throws RegistryException;
 	
-	public Collection<Map<String, String>> getAllSwitches();
+	public Map<String, List<ControllerRegistryEntry>> getAllSwitches();
 	
 	public Collection<Long> getSwitchesControlledByController(String controllerId);
 }
diff --git a/src/main/java/net/onrc/onos/registry/controller/RegistryManager.java b/src/main/java/net/onrc/onos/registry/controller/RegistryManager.java
index 84f17c3..a5a3576 100644
--- a/src/main/java/net/onrc/onos/registry/controller/RegistryManager.java
+++ b/src/main/java/net/onrc/onos/registry/controller/RegistryManager.java
@@ -5,6 +5,7 @@
 import java.net.UnknownHostException;
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -13,7 +14,9 @@
 import net.floodlightcontroller.core.module.FloodlightModuleException;
 import net.floodlightcontroller.core.module.IFloodlightModule;
 import net.floodlightcontroller.core.module.IFloodlightService;
+import net.floodlightcontroller.restserver.IRestApiService;
 
+import org.apache.commons.lang.NotImplementedException;
 import org.apache.zookeeper.CreateMode;
 import org.apache.zookeeper.WatchedEvent;
 import org.apache.zookeeper.Watcher.Event.KeeperState;
@@ -28,27 +31,35 @@
 import com.netflix.curator.framework.recipes.cache.ChildData;
 import com.netflix.curator.framework.recipes.cache.PathChildrenCache;
 import com.netflix.curator.framework.recipes.cache.PathChildrenCache.StartMode;
+import com.netflix.curator.framework.recipes.cache.PathChildrenCacheEvent;
+import com.netflix.curator.framework.recipes.cache.PathChildrenCacheListener;
 import com.netflix.curator.framework.recipes.leader.LeaderLatch;
 import com.netflix.curator.framework.recipes.leader.Participant;
-import com.netflix.curator.retry.RetryOneTime;
+import com.netflix.curator.retry.ExponentialBackoffRetry;
 
 public class RegistryManager implements IFloodlightModule, IControllerRegistryService {
 
 	protected static Logger log = LoggerFactory.getLogger(RegistryManager.class);
 	protected String mastershipId = null;
 	
+	protected IRestApiService restApi;
+	
 	//TODO read this from configuration
 	protected String connectionString = "localhost:2181";
+	
+	
 	private final String namespace = "onos";
 	private final String switchLatchesPath = "/switches";
+	private final String controllerPath = "/controllers";
 	
 	protected CuratorFramework client;
 	
-	private final String controllerPath = "/controllers";
 	protected PathChildrenCache controllerCache;
+	protected PathChildrenCache switchCache;
 
 	protected Map<String, LeaderLatch> switchLatches;
 	protected Map<String, ControlChangeCallback> switchCallbacks;
+	protected Map<String, PathChildrenCache> switchPathCaches;
 	
 	protected boolean moduleEnabled = false;
 	
@@ -73,7 +84,11 @@
 					log.debug("Disconnected while leader - lost leadership for {}", dpid);
 					
 					isLeader = false;
-					switchCallbacks.get(dpid).controlChanged(HexString.toLong(dpid), false);
+					ControlChangeCallback cb = switchCallbacks.get(dpid);
+					if (cb != null) {
+						//Allow callback to be null if the requester doesn't want a callback
+						cb.controlChanged(HexString.toLong(dpid), false);
+					}
 				}
 				return;
 			}
@@ -108,10 +123,56 @@
 			//client.getChildren().usingWatcher(this).forPath(latchPath);
 		}
 	}
+	
+	
+	/*
+	 * Listens for changes to the switch znodes in Zookeeper. This maintains the second level of
+	 * PathChildrenCaches that hold the controllers contending for each switch - there's one for
+	 * each switch.
+	 */
+	PathChildrenCacheListener switchPathCacheListener = new PathChildrenCacheListener() {
+		@Override
+		public void childEvent(CuratorFramework client,
+				PathChildrenCacheEvent event) throws Exception {
+			// TODO Auto-generated method stub
+			log.debug("Root switch path cache got {} event", event.getType());
+			
+			String strSwitch = null;
+			if (event.getData() != null){
+				log.debug("Event path {}", event.getData().getPath());
+				String[] splitted = event.getData().getPath().split("/");
+				strSwitch = splitted[splitted.length - 1];
+				log.debug("Switch name is {}", strSwitch);
+			}
+			
+			switch (event.getType()){
+			case CHILD_ADDED:
+			case CHILD_UPDATED:
+				//Check we have a PathChildrenCache for this child, add one if not
+				if (switchPathCaches.get(strSwitch) == null){
+					PathChildrenCache pc = new PathChildrenCache(client, 
+							event.getData().getPath(), true);
+					pc.start(StartMode.NORMAL);
+					switchPathCaches.put(strSwitch, pc);
+				}
+				break;
+			case CHILD_REMOVED:
+				//Remove our PathChildrenCache for this child
+				PathChildrenCache pc = switchPathCaches.remove(strSwitch);
+				pc.close();
+				break;
+			default:
+				//All other events are connection status events. We need to do anything
+				//as the path cache handles these on its own.
+				break;
+			}
+			
+		}
+	};
 
 	
 	@Override
-	public void requestControl(long dpid, ControlChangeCallback cb) throws Exception {
+	public void requestControl(long dpid, ControlChangeCallback cb) throws RegistryException {
 		
 		if (!moduleEnabled) return;
 		
@@ -139,7 +200,7 @@
 			latch.start();
 		} catch (Exception e) {
 			log.warn("Error starting leader latch: {}", e.getMessage());
-			throw e;
+			throw new RegistryException("Error starting leader latch for " + dpidStr, e);
 		}
 		
 	}
@@ -269,15 +330,50 @@
 	
 	@Override
 	public Collection<Long> getSwitchesControlledByController(String controllerId) {
-		// TODO Auto-generated method stub
-		return null;
+		//TODO remove this if not needed
+		throw new NotImplementedException();
 	}
 	
 
 	@Override
-	public Collection<Map<String, String>> getAllSwitches() {
-		// TODO Auto-generated method stub
-		return null;
+	public Map<String, List<ControllerRegistryEntry>> getAllSwitches() {
+		Map<String, List<ControllerRegistryEntry>> data = 
+				new HashMap<String, List<ControllerRegistryEntry>>();
+		
+		for (Map.Entry<String, PathChildrenCache> entry : switchPathCaches.entrySet()){
+			List<ControllerRegistryEntry> contendingControllers =
+					 new ArrayList<ControllerRegistryEntry>(); 
+			
+			if (entry.getValue().getCurrentData().size() < 1){
+				log.info("Switch entry with no leader elections: {}", entry.getKey());
+				continue;
+			}
+			
+			for (ChildData d : entry.getValue().getCurrentData()) {
+				/*
+				if (d.getPath().length() < 1){
+					log.info("Switch entry with no leader elections: {}", d.getPath());
+					continue;
+				}
+				*/
+				
+				String controllerId = null;
+				try {
+					controllerId = new String(d.getData(), "UTF-8");
+				} catch (UnsupportedEncodingException e) {
+					log.warn("Encoding exception: {}", e.getMessage());
+				}
+				
+				String[] splitted = d.getPath().split("-");
+				int sequenceNumber = Integer.parseInt(splitted[splitted.length - 1]);
+				
+				contendingControllers.add(new ControllerRegistryEntry(controllerId, sequenceNumber));
+			 }
+			
+			Collections.sort(contendingControllers);
+			data.put(entry.getKey(), contendingControllers);
+		}
+		return data;
 	}
 	
 	/*
@@ -302,13 +398,17 @@
 	
 	@Override
 	public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
-		// no module dependencies
-		return null;
+		Collection<Class<? extends IFloodlightService>> l =
+                new ArrayList<Class<? extends IFloodlightService>>();
+        l.add(IRestApiService.class);
+		return l;
 	}
 	
 	@Override
 	public void init (FloodlightModuleContext context) throws FloodlightModuleException {
 		
+		restApi = context.getServiceImpl(IRestApiService.class);
+		
 		//Read config to see if we should try and connect to zookeeper
 		Map<String, String> configOptions = context.getConfigParams(this);
 		String enableZookeeper = configOptions.get("enableZookeeper");
@@ -332,19 +432,34 @@
 
 		switchLatches = new HashMap<String, LeaderLatch>();
 		switchCallbacks = new HashMap<String, ControlChangeCallback>();
+		switchPathCaches = new HashMap<String, PathChildrenCache>();
 		
-		//RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3);
-		RetryPolicy retryPolicy = new RetryOneTime(0);
+		RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3);
+		//RetryPolicy retryPolicy = new RetryOneTime(0);
 		client = CuratorFrameworkFactory.newClient(connectionString, retryPolicy);
 		
 		client.start();
 		
 		client = client.usingNamespace(namespace);
 		
+		//Put some data in for testing
+		try {
+			registerController(mastershipId);
+			requestControl(2L, null);
+		} catch (RegistryException e1) {
+			// TODO Auto-generated catch block
+			e1.printStackTrace();
+		}
+		
 		controllerCache = new PathChildrenCache(client, controllerPath, true);
+		switchCache = new PathChildrenCache(client, switchLatchesPath, true);
+		switchCache.getListenable().addListener(switchPathCacheListener);
 		
 		try {
 			controllerCache.start(StartMode.BUILD_INITIAL_CACHE);
+			
+			//Don't prime the cache, we want a notification for each child node in the path
+			switchCache.start(StartMode.NORMAL);
 		} catch (Exception e) {
 			// TODO Auto-generated catch block
 			e.printStackTrace();
@@ -353,7 +468,7 @@
 	
 	@Override
 	public void startUp (FloodlightModuleContext context) {
-		// Nothing to be done on startup
+		restApi.addRestletRoutable(new RegistryWebRoutable());
 	}
 
 }
diff --git a/src/main/java/net/onrc/onos/registry/controller/RegistryRouteResource.java b/src/main/java/net/onrc/onos/registry/controller/RegistryRouteResource.java
deleted file mode 100644
index 5dadafa..0000000
--- a/src/main/java/net/onrc/onos/registry/controller/RegistryRouteResource.java
+++ /dev/null
@@ -1,32 +0,0 @@
-package net.onrc.onos.registry.controller;
-
-import org.restlet.resource.ServerResource;
-import org.restlet.resource.Get;
-import org.restlet.resource.Post;
-import org.restlet.resource.Delete;
-
-import org.slf4j.LoggerFactory;
-import org.slf4j.Logger;
-
-public class RegistryRouteResource extends ServerResource {
-
-	protected static Logger log = LoggerFactory.getLogger(RegistryRouteResource.class);
-
-	@Get
-	public String get(String fmJson) {
-		// TODO
-		return null;
-	}
-	
-	@Post
-	public String store (String fmJson) {
-		//TODO
-		return null;
-	}
-	
-	@Delete
-	public String delete (String fmJson) {
-		//TODO
-		return null;
-	}
-}
diff --git a/src/main/java/net/onrc/onos/registry/controller/RegistryRunner.java b/src/main/java/net/onrc/onos/registry/controller/RegistryRunner.java
index 8522893..1f4ea63 100644
--- a/src/main/java/net/onrc/onos/registry/controller/RegistryRunner.java
+++ b/src/main/java/net/onrc/onos/registry/controller/RegistryRunner.java
@@ -1,5 +1,8 @@
 package net.onrc.onos.registry.controller;
 
+import java.util.List;
+import java.util.Map;
+
 import net.floodlightcontroller.core.module.FloodlightModuleContext;
 import net.floodlightcontroller.core.module.FloodlightModuleException;
 import net.onrc.onos.registry.controller.IControllerRegistryService.ControlChangeCallback;
@@ -52,8 +55,14 @@
 			
 			rm.registerController(id);
 			
-			Thread.sleep(5000);
+			Thread.sleep(1000);
 			
+			Map<String, List<ControllerRegistryEntry>> switches = rm.getAllSwitches();
+			for (List<ControllerRegistryEntry> ls : switches.values()){
+				for (ControllerRegistryEntry cre : ls){
+					log.debug("ctrlr: {}", cre.getControllerId());
+				}
+			}
 			//"Server" loop
 			while (true) {
 				Thread.sleep(60000);
diff --git a/src/main/java/net/onrc/onos/registry/controller/RegistryWebRoutable.java b/src/main/java/net/onrc/onos/registry/controller/RegistryWebRoutable.java
index 8b5123b..74dede4 100644
--- a/src/main/java/net/onrc/onos/registry/controller/RegistryWebRoutable.java
+++ b/src/main/java/net/onrc/onos/registry/controller/RegistryWebRoutable.java
@@ -1,17 +1,18 @@
 package net.onrc.onos.registry.controller;
 
+import net.floodlightcontroller.restserver.RestletRoutable;
+
 import org.restlet.Context;
 import org.restlet.Restlet;
 import org.restlet.routing.Router;
 
-import net.floodlightcontroller.restserver.RestletRoutable;
-
 public class RegistryWebRoutable implements RestletRoutable {
 
 	@Override
 	public Restlet getRestlet(Context context) {
 		Router router = new Router(context);
-		router.attach("/json", RegistryRouteResource.class);
+		router.attach("/controllers/json", ControllerRegistryResource.class);
+		router.attach("/switches/json", SwitchRegistryResource.class);
 		return router;
 	}
 
diff --git a/src/main/java/net/onrc/onos/registry/controller/SwitchRegistryResource.java b/src/main/java/net/onrc/onos/registry/controller/SwitchRegistryResource.java
new file mode 100644
index 0000000..17ad48c
--- /dev/null
+++ b/src/main/java/net/onrc/onos/registry/controller/SwitchRegistryResource.java
@@ -0,0 +1,40 @@
+package net.onrc.onos.registry.controller;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.restlet.resource.Get;
+import org.restlet.resource.ServerResource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class SwitchRegistryResource extends ServerResource {
+
+	protected static Logger log = LoggerFactory.getLogger(SwitchRegistryResource.class);
+	
+	@Get("json")
+	public Map<String, List<ControllerRegistryEntry>> getAllControllers(){
+		IControllerRegistryService registry = 
+				(IControllerRegistryService) getContext().getAttributes().
+				get(IControllerRegistryService.class.getCanonicalName());
+		
+		Map<String, List<ControllerRegistryEntry>> switches = null;
+		switches = registry.getAllSwitches();
+		
+		if (switches == null){
+			switches = new HashMap<String, List<ControllerRegistryEntry>>();
+		}
+		
+		log.debug("GETTING ALL CONTROLLERS");
+		
+		for (List<ControllerRegistryEntry> list: switches.values()){
+			for (ControllerRegistryEntry en : list) {
+				log.debug("Controller id {}", en.getControllerId());
+			}
+		}
+		
+		
+		return switches;
+	}
+}