MasteshipService, store, and CLI commands use RoleInfo

Change-Id: Ibc569498a67d33d088e5c9f89c6bb1f45eadc26e
diff --git a/cli/src/main/java/org/onlab/onos/cli/RolesCommand.java b/cli/src/main/java/org/onlab/onos/cli/RolesCommand.java
index 0456e4a..b81a0c2 100644
--- a/cli/src/main/java/org/onlab/onos/cli/RolesCommand.java
+++ b/cli/src/main/java/org/onlab/onos/cli/RolesCommand.java
@@ -7,6 +7,7 @@
 
 import org.apache.karaf.shell.commands.Command;
 import org.onlab.onos.cluster.NodeId;
+import org.onlab.onos.cluster.RoleInfo;
 import org.onlab.onos.mastership.MastershipService;
 import org.onlab.onos.net.Device;
 import org.onlab.onos.net.DeviceId;
@@ -20,8 +21,7 @@
         description = "Lists mastership roles of nodes for each device.")
 public class RolesCommand extends AbstractShellCommand {
 
-    private static final String FMT_HDR = "%s: master=%s\nstandbys: %s nodes";
-    private static final String FMT_SB = "\t%s";
+    private static final String FMT_HDR = "%s: master=%s, standbys=%s";
 
     @Override
     protected void execute() {
@@ -53,22 +53,14 @@
      * @param master the current master
      */
     protected void printRoles(MastershipService service, DeviceId deviceId) {
-        List<NodeId> nodes = service.getNodesFor(deviceId);
-        NodeId first = null;
-        NodeId master = null;
+        RoleInfo nodes = service.getNodesFor(deviceId);
+        StringBuilder builder = new StringBuilder();
+        for (NodeId nid : nodes.backups()) {
+            builder.append(nid).append(" ");
+        }
 
-        if (!nodes.isEmpty()) {
-            first = nodes.get(0);
-        }
-        if (first != null &&
-                first.equals(service.getMasterFor(deviceId))) {
-            master = nodes.get(0);
-            nodes.remove(master);
-        }
-        print(FMT_HDR, deviceId, master == null ? "NONE" : master, nodes.size());
-
-        for (NodeId nid : nodes) {
-            print(FMT_SB, nid);
-        }
+        print(FMT_HDR, deviceId,
+                nodes.master() == null ? "NONE" : nodes.master(),
+                builder.toString());
     }
 }
diff --git a/core/store/hz/common/src/main/java/org/onlab/onos/store/common/RoleInfo.java b/core/api/src/main/java/org/onlab/onos/cluster/RoleInfo.java
similarity index 95%
rename from core/store/hz/common/src/main/java/org/onlab/onos/store/common/RoleInfo.java
rename to core/api/src/main/java/org/onlab/onos/cluster/RoleInfo.java
index 904488b..bf7442e 100644
--- a/core/store/hz/common/src/main/java/org/onlab/onos/store/common/RoleInfo.java
+++ b/core/api/src/main/java/org/onlab/onos/cluster/RoleInfo.java
@@ -1,12 +1,10 @@
-package org.onlab.onos.store.common;
+package org.onlab.onos.cluster;
 
 import java.util.Collections;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Objects;
 
-import org.onlab.onos.cluster.NodeId;
-
 import static com.google.common.base.Preconditions.checkNotNull;
 
 /**
diff --git a/core/api/src/main/java/org/onlab/onos/mastership/MastershipEvent.java b/core/api/src/main/java/org/onlab/onos/mastership/MastershipEvent.java
index 7b8531c..9f75fc4 100644
--- a/core/api/src/main/java/org/onlab/onos/mastership/MastershipEvent.java
+++ b/core/api/src/main/java/org/onlab/onos/mastership/MastershipEvent.java
@@ -56,7 +56,10 @@
     }
 
     /**
-     * Returns the NodeID of the node responsible for triggering the event.
+     * Returns the NodeID of the node associated with the event.
+     * For MASTER_CHANGED this is the newly elected master, and for
+     * BACKUPS_CHANGED, this is the node that was newly added, removed, or
+     * whose position was changed in the list.
      *
      * @return node ID as a subject
      */
diff --git a/core/api/src/main/java/org/onlab/onos/mastership/MastershipService.java b/core/api/src/main/java/org/onlab/onos/mastership/MastershipService.java
index 224bc05..30cb545 100644
--- a/core/api/src/main/java/org/onlab/onos/mastership/MastershipService.java
+++ b/core/api/src/main/java/org/onlab/onos/mastership/MastershipService.java
@@ -1,9 +1,9 @@
 package org.onlab.onos.mastership;
 
-import java.util.List;
 import java.util.Set;
 
 import org.onlab.onos.cluster.NodeId;
+import org.onlab.onos.cluster.RoleInfo;
 import org.onlab.onos.net.DeviceId;
 import org.onlab.onos.net.MastershipRole;
 
@@ -57,7 +57,7 @@
      * @param deviceId the identifier of the device
      * @return a list of controller IDs
      */
-    List<NodeId> getNodesFor(DeviceId deviceId);
+    RoleInfo getNodesFor(DeviceId deviceId);
 
     /**
      * Returns the devices for which a controller is master.
diff --git a/core/api/src/main/java/org/onlab/onos/mastership/MastershipStore.java b/core/api/src/main/java/org/onlab/onos/mastership/MastershipStore.java
index 5e7b0e4..bd7a354 100644
--- a/core/api/src/main/java/org/onlab/onos/mastership/MastershipStore.java
+++ b/core/api/src/main/java/org/onlab/onos/mastership/MastershipStore.java
@@ -1,9 +1,9 @@
 package org.onlab.onos.mastership;
 
-import java.util.List;
 import java.util.Set;
 
 import org.onlab.onos.cluster.NodeId;
+import org.onlab.onos.cluster.RoleInfo;
 import org.onlab.onos.net.DeviceId;
 import org.onlab.onos.net.MastershipRole;
 import org.onlab.onos.store.Store;
@@ -42,13 +42,12 @@
     NodeId getMaster(DeviceId deviceId);
 
     /**
-     * Returns the controllers connected to a device, in mastership-
-     * preference order.
+     * Returns the master and backup nodes for a device.
      *
      * @param deviceId the device identifier
-     * @return an ordered list of controller IDs
+     * @return a RoleInfo containing controller IDs
      */
-    List<NodeId> getNodes(DeviceId deviceId);
+    RoleInfo getNodes(DeviceId deviceId);
 
     /**
      * Returns the devices that a controller instance is master of.
diff --git a/core/store/hz/common/src/test/java/org/onlab/onos/store/common/RoleInfoTest.java b/core/api/src/test/java/org/onlab/onos/cluster/RoleInfoTest.java
similarity index 91%
rename from core/store/hz/common/src/test/java/org/onlab/onos/store/common/RoleInfoTest.java
rename to core/api/src/test/java/org/onlab/onos/cluster/RoleInfoTest.java
index c7e43ff..46ab02e 100644
--- a/core/store/hz/common/src/test/java/org/onlab/onos/store/common/RoleInfoTest.java
+++ b/core/api/src/test/java/org/onlab/onos/cluster/RoleInfoTest.java
@@ -1,9 +1,8 @@
-package org.onlab.onos.store.common;
+package org.onlab.onos.cluster;
 
 import java.util.List;
 
 import org.junit.Test;
-import org.onlab.onos.cluster.NodeId;
 
 import com.google.common.collect.Lists;
 
@@ -29,7 +28,6 @@
     @Test
     public void basics() {
         assertEquals("wrong master", new NodeId("n1"), RI1.master());
-        System.out.println(RI1.toString());
         assertEquals("wrong Backups", RI1.backups(), Lists.newArrayList(N2, N3));
 
         assertNotEquals("equals() broken", RI1, RI2);
diff --git a/core/api/src/test/java/org/onlab/onos/mastership/MastershipServiceAdapter.java b/core/api/src/test/java/org/onlab/onos/mastership/MastershipServiceAdapter.java
index af376e8..8169dfb 100644
--- a/core/api/src/test/java/org/onlab/onos/mastership/MastershipServiceAdapter.java
+++ b/core/api/src/test/java/org/onlab/onos/mastership/MastershipServiceAdapter.java
@@ -1,10 +1,10 @@
 package org.onlab.onos.mastership;
 
 import org.onlab.onos.cluster.NodeId;
+import org.onlab.onos.cluster.RoleInfo;
 import org.onlab.onos.net.DeviceId;
 import org.onlab.onos.net.MastershipRole;
 
-import java.util.List;
 import java.util.Set;
 
 /**
@@ -49,7 +49,7 @@
     }
 
     @Override
-    public List<NodeId> getNodesFor(DeviceId deviceId) {
+    public RoleInfo getNodesFor(DeviceId deviceId) {
         return null;
     }
 }
diff --git a/core/net/src/main/java/org/onlab/onos/cluster/impl/MastershipManager.java b/core/net/src/main/java/org/onlab/onos/cluster/impl/MastershipManager.java
index 867c6cb..b2c172a 100644
--- a/core/net/src/main/java/org/onlab/onos/cluster/impl/MastershipManager.java
+++ b/core/net/src/main/java/org/onlab/onos/cluster/impl/MastershipManager.java
@@ -3,7 +3,6 @@
 import static com.google.common.base.Preconditions.checkNotNull;
 import static org.slf4j.LoggerFactory.getLogger;
 
-import java.util.List;
 import java.util.Set;
 import java.util.concurrent.atomic.AtomicInteger;
 
@@ -18,6 +17,7 @@
 import org.onlab.onos.cluster.ClusterService;
 import org.onlab.onos.cluster.ControllerNode;
 import org.onlab.onos.cluster.NodeId;
+import org.onlab.onos.cluster.RoleInfo;
 import org.onlab.onos.event.AbstractListenerRegistry;
 import org.onlab.onos.event.EventDeliveryService;
 import org.onlab.onos.mastership.MastershipAdminService;
@@ -128,7 +128,7 @@
     }
 
     @Override
-    public List<NodeId> getNodesFor(DeviceId deviceId) {
+    public RoleInfo getNodesFor(DeviceId deviceId) {
         checkNotNull(deviceId, DEVICE_ID_NULL);
         return store.getNodes(deviceId);
     }
diff --git a/core/store/hz/cluster/src/main/java/org/onlab/onos/store/mastership/impl/DistributedMastershipStore.java b/core/store/hz/cluster/src/main/java/org/onlab/onos/store/mastership/impl/DistributedMastershipStore.java
index 28ba049..aaf056c 100644
--- a/core/store/hz/cluster/src/main/java/org/onlab/onos/store/mastership/impl/DistributedMastershipStore.java
+++ b/core/store/hz/cluster/src/main/java/org/onlab/onos/store/mastership/impl/DistributedMastershipStore.java
@@ -2,9 +2,6 @@
 
 import static org.onlab.onos.mastership.MastershipEvent.Type.MASTER_CHANGED;
 
-import java.util.Collections;
-import java.util.LinkedList;
-import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
@@ -16,6 +13,7 @@
 import org.apache.felix.scr.annotations.Service;
 import org.onlab.onos.cluster.ClusterService;
 import org.onlab.onos.cluster.NodeId;
+import org.onlab.onos.cluster.RoleInfo;
 import org.onlab.onos.mastership.MastershipEvent;
 import org.onlab.onos.mastership.MastershipStore;
 import org.onlab.onos.mastership.MastershipStoreDelegate;
@@ -161,20 +159,11 @@
 
 
     @Override
-    public List<NodeId> getNodes(DeviceId deviceId) {
-        List<NodeId> nodes = new LinkedList<>();
-
-        //add current master to head - if there is one.
+    public RoleInfo getNodes(DeviceId deviceId) {
         roleMap.lock(deviceId);
         try {
             RoleValue rv = getRoleValue(deviceId);
-            NodeId master = rv.get(MASTER);
-            if (master != null) {
-                nodes.add(master);
-            }
-            //We ignore NONE nodes.
-            nodes.addAll(rv.nodesOfRole(STANDBY));
-            return Collections.unmodifiableList(nodes);
+            return rv.roleInfo();
         } finally {
             roleMap.unlock(deviceId);
         }
diff --git a/core/store/hz/cluster/src/main/java/org/onlab/onos/store/mastership/impl/RoleValue.java b/core/store/hz/cluster/src/main/java/org/onlab/onos/store/mastership/impl/RoleValue.java
index 51dd293..1ccee6b 100644
--- a/core/store/hz/cluster/src/main/java/org/onlab/onos/store/mastership/impl/RoleValue.java
+++ b/core/store/hz/cluster/src/main/java/org/onlab/onos/store/mastership/impl/RoleValue.java
@@ -7,8 +7,8 @@
 import java.util.Map;
 
 import org.onlab.onos.cluster.NodeId;
+import org.onlab.onos.cluster.RoleInfo;
 import org.onlab.onos.net.MastershipRole;
-import org.onlab.onos.store.common.RoleInfo;
 
 /**
  * A structure that holds node mastership roles associated with a
diff --git a/core/store/trivial/src/main/java/org/onlab/onos/store/trivial/impl/SimpleMastershipStore.java b/core/store/trivial/src/main/java/org/onlab/onos/store/trivial/impl/SimpleMastershipStore.java
index f4b035c..fe34959 100644
--- a/core/store/trivial/src/main/java/org/onlab/onos/store/trivial/impl/SimpleMastershipStore.java
+++ b/core/store/trivial/src/main/java/org/onlab/onos/store/trivial/impl/SimpleMastershipStore.java
@@ -18,6 +18,7 @@
 import org.onlab.onos.cluster.ControllerNode;
 import org.onlab.onos.cluster.DefaultControllerNode;
 import org.onlab.onos.cluster.NodeId;
+import org.onlab.onos.cluster.RoleInfo;
 import org.onlab.onos.mastership.MastershipEvent;
 import org.onlab.onos.mastership.MastershipStore;
 import org.onlab.onos.mastership.MastershipStoreDelegate;
@@ -97,15 +98,11 @@
     }
 
     @Override
-    public List<NodeId> getNodes(DeviceId deviceId) {
+    public RoleInfo getNodes(DeviceId deviceId) {
         List<NodeId> nodes = new ArrayList<>();
-
         nodes.addAll(backups);
-        if (!nodes.contains(masterMap.get(deviceId))) {
-            nodes.add(masterMap.get(deviceId));
-        }
 
-        return Collections.unmodifiableList(nodes);
+        return new RoleInfo(masterMap.get(deviceId), nodes);
     }
 
     @Override
diff --git a/providers/lldp/src/test/java/org/onlab/onos/provider/lldp/impl/LLDPLinkProviderTest.java b/providers/lldp/src/test/java/org/onlab/onos/provider/lldp/impl/LLDPLinkProviderTest.java
index bbf2de2..4410aaf 100644
--- a/providers/lldp/src/test/java/org/onlab/onos/provider/lldp/impl/LLDPLinkProviderTest.java
+++ b/providers/lldp/src/test/java/org/onlab/onos/provider/lldp/impl/LLDPLinkProviderTest.java
@@ -9,6 +9,7 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.onlab.onos.cluster.NodeId;
+import org.onlab.onos.cluster.RoleInfo;
 import org.onlab.onos.mastership.MastershipListener;
 import org.onlab.onos.mastership.MastershipService;
 import org.onlab.onos.mastership.MastershipTermService;
@@ -481,8 +482,8 @@
         }
 
         @Override
-        public List<NodeId> getNodesFor(DeviceId deviceId) {
-            return Collections.emptyList();
+        public RoleInfo getNodesFor(DeviceId deviceId) {
+            return new RoleInfo(new NodeId("foo"), Collections.<NodeId>emptyList());
         }
     }