Pushed Switch Mastership Events into the Topology event channel.
Needed for ONOS-1729
For now those events are not used.

Also, added new TopologyElement attribute type: TYPE_ALL_LAYERS
which applies to the Mastership Events.

NOTE: Currently, those events are intercepted within the
Floodlight Controller.java class. The interception point might be moved
once it becomes clear whether the event origin should be the mastership
election mechanism or the "role change request" accepted by the switch.
In addition, the interception point needs to be moved/ported as appropriate
once we move to the newer 1.3 OpenFlow driver implementation and eventloop.

Change-Id: Iff06ed5aee867c428a8378e31f9d51dbe3e6b978
diff --git a/src/main/java/net/floodlightcontroller/core/internal/Controller.java b/src/main/java/net/floodlightcontroller/core/internal/Controller.java
index ae362a2..e34c958 100644
--- a/src/main/java/net/floodlightcontroller/core/internal/Controller.java
+++ b/src/main/java/net/floodlightcontroller/core/internal/Controller.java
@@ -36,6 +36,7 @@
 import java.util.concurrent.BlockingQueue;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.concurrent.CopyOnWriteArraySet;
 import java.util.concurrent.Executors;
 import java.util.concurrent.Future;
@@ -59,12 +60,14 @@
 import net.floodlightcontroller.core.web.CoreWebRoutable;
 import net.floodlightcontroller.restserver.IRestApiService;
 import net.floodlightcontroller.threadpool.IThreadPoolService;
+import net.onrc.onos.api.registry.ILocalSwitchMastershipListener;
 import net.onrc.onos.core.linkdiscovery.ILinkDiscoveryService;
 import net.onrc.onos.core.main.IOFSwitchPortListener;
 import net.onrc.onos.core.packet.Ethernet;
 import net.onrc.onos.core.registry.IControllerRegistryService;
 import net.onrc.onos.core.registry.IControllerRegistryService.ControlChangeCallback;
 import net.onrc.onos.core.registry.RegistryException;
+import net.onrc.onos.core.util.Dpid;
 
 import org.jboss.netty.bootstrap.ServerBootstrap;
 import org.jboss.netty.buffer.ChannelBuffer;
@@ -162,6 +165,9 @@
     protected Set<IOFSwitchListener> switchListeners;
     protected BlockingQueue<IUpdate> updates;
 
+    private CopyOnWriteArrayList<ILocalSwitchMastershipListener> localSwitchMastershipListeners =
+        new CopyOnWriteArrayList<>();
+
     // Module dependencies
     protected IRestApiService restApi;
     protected IThreadPoolService threadPool;
@@ -300,46 +306,59 @@
 
     protected class RoleChangeCallback implements ControlChangeCallback {
         @Override
-        public void controlChanged(long dpid, boolean hasControl) {
+        public void controlChanged(long dpidLong, boolean hasControl) {
+            Dpid dpid = new Dpid(dpidLong);
             log.info("Role change callback for switch {}, hasControl {}",
-                    HexString.toHexString(dpid), hasControl);
+                     dpid, hasControl);
 
             synchronized (roleChanger) {
+                Role role = null;
+                /*
+                 * issue #229
+                 * Cannot rely on sw.getRole() as it can be behind due to pending
+                 * role changes in the queue. Just submit it and late the RoleChanger
+                 * handle duplicates.
+                 */
+                if (hasControl) {
+                    role = Role.MASTER;
+                } else {
+                    role = Role.SLAVE;
+                }
+                //
+                // Inform all listeners about the Controller role change.
+                //
+                // NOTE: The role change here is triggered by the mastership
+                // election mechanism, and reflects what the Controller itself
+                // believes its role should be. The role change request hasn't
+                // been accepted by the switch itself.
+                // If the semantics for informing the listeners is changed
+                // (i.e., the listeners should be informed after the switch
+                // has accepted the role change), then the code below should
+                // be moved to method handleRoleReplyMessage() or its
+                // equivalent.
+                // 
+                for (ILocalSwitchMastershipListener listener : localSwitchMastershipListeners) {
+                    listener.controllerRoleChanged(dpid, role);
+                }
+
                 OFSwitchImpl sw = null;
                 for (OFSwitchImpl connectedSw : connectedSwitches) {
-                    if (connectedSw.getId() == dpid) {
+                    if (connectedSw.getId() == dpidLong) {
                         sw = connectedSw;
                         break;
                     }
                 }
                 if (sw == null) {
                     log.warn("Switch {} not found in connected switches",
-                            HexString.toHexString(dpid));
+                             dpid);
                     return;
                 }
 
-                Role role = null;
-                                
-                                /*
-                                 * issue #229
-                                 * Cannot rely on sw.getRole() as it can be behind due to pending
-                                 * role changes in the queue. Just submit it and late the RoleChanger
-                                 * handle duplicates.
-                                 */
-
-                if (hasControl) {
-                    role = Role.MASTER;
-                } else {
-                    role = Role.SLAVE;
-                }
-
                 log.debug("Sending role request {} msg to {}", role, sw);
                 Collection<OFSwitchImpl> swList = new ArrayList<OFSwitchImpl>(1);
                 swList.add(sw);
                 roleChanger.submitRequest(swList, role);
-
             }
-
         }
     }
 
@@ -392,6 +411,16 @@
                 }
                 synchronized (roleChanger) {
                     if (controlRequested) {
+
+                        //
+                        // Inform all listeners about the switch disconnection
+                        //
+                        Dpid dpid = new Dpid(sw.getId());
+                        for (ILocalSwitchMastershipListener listener :
+                                 localSwitchMastershipListeners) {
+                            listener.switchDisconnected(dpid);
+                        }
+
                         registryService.releaseControl(sw.getId());
                     }
                     connectedSwitches.remove(sw);
@@ -1519,6 +1548,18 @@
     }
 
     @Override
+    public void addLocalSwitchMastershipListener(
+                ILocalSwitchMastershipListener listener) {
+        this.localSwitchMastershipListeners.addIfAbsent(listener);
+    }
+
+    @Override
+    public void removeLocalSwitchMastershipListener(
+                ILocalSwitchMastershipListener listener) {
+        this.localSwitchMastershipListeners.remove(listener);
+    }
+
+    @Override
     @LogMessageDocs({
             @LogMessageDoc(message = "Failed to inject OFMessage {message} onto " +
                     "a null switch",