[CORD-575] Implements VPWS transport in SR app

Changes:
- Enables the BoS==False use case;
- Adds RandomNeighborSet to emulate the hashing;

Change-Id: I5cc05eb25f5185e612061880fcdb194ed71277d8
diff --git a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/NeighborSet.java b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/NeighborSet.java
index aefcd21..06f7861 100644
--- a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/NeighborSet.java
+++ b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/NeighborSet.java
@@ -16,13 +16,14 @@
 
 package org.onosproject.segmentrouting.grouphandler;
 
-import static com.google.common.base.Preconditions.checkNotNull;
+import org.onosproject.net.DeviceId;
 
 import java.util.HashSet;
 import java.util.Objects;
 import java.util.Set;
 
-import org.onosproject.net.DeviceId;
+import static com.google.common.base.MoreObjects.toStringHelper;
+import static com.google.common.base.Preconditions.checkNotNull;
 
 /**
  * Representation of a set of neighbor switch dpids along with edge node
@@ -34,31 +35,36 @@
     private final Set<DeviceId> neighbors;
     private final int edgeLabel;
     public static final int NO_EDGE_LABEL = -1;
+    private boolean mplsSet;
 
     /**
      * Constructor with set of neighbors. Edge label is
      * default to -1.
      *
      * @param neighbors set of neighbors to be part of neighbor set
+     * @param isMplsSet indicates if it is a mpls neighbor set
      */
-    public NeighborSet(Set<DeviceId> neighbors) {
+    public NeighborSet(Set<DeviceId> neighbors, boolean isMplsSet) {
         checkNotNull(neighbors);
         this.edgeLabel = NO_EDGE_LABEL;
         this.neighbors = new HashSet<>();
         this.neighbors.addAll(neighbors);
+        this.mplsSet = isMplsSet;
     }
 
     /**
      * Constructor with set of neighbors and edge label.
      *
      * @param neighbors set of neighbors to be part of neighbor set
+     * @param isMplsSet indicates if it is a mpls neighbor set
      * @param edgeLabel label to be pushed as part of group operation
      */
-    public NeighborSet(Set<DeviceId> neighbors, int edgeLabel) {
+    public NeighborSet(Set<DeviceId> neighbors, boolean isMplsSet, int edgeLabel) {
         checkNotNull(neighbors);
         this.edgeLabel = edgeLabel;
         this.neighbors = new HashSet<>();
         this.neighbors.addAll(neighbors);
+        this.mplsSet = isMplsSet;
     }
 
     /**
@@ -67,6 +73,46 @@
     public NeighborSet() {
         this.edgeLabel = NO_EDGE_LABEL;
         this.neighbors = new HashSet<>();
+        this.mplsSet = true;
+    }
+
+    /**
+     * Factory method for NeighborSet hierarchy.
+     *
+     * @param random the expected behavior.
+     * @param neighbors the set of neighbors to be part of neighbor set
+     * @param isMplsSet indicates if it is a mpls neighbor set
+     * @return the neighbor set object.
+     */
+    public static NeighborSet neighborSet(boolean random, Set<DeviceId> neighbors, boolean isMplsSet) {
+        return random ?
+                new RandomNeighborSet(neighbors) :
+                new NeighborSet(neighbors, isMplsSet);
+    }
+
+    /**
+     * Factory method for NeighborSet hierarchy.
+     *
+     * @param random the expected behavior.
+     * @param neighbors the set of neighbors to be part of neighbor set
+     * @param isMplsSet indicates if it is a mpls neighbor set
+     * @param edgeLabel label to be pushed as part of group operation
+     * @return the neighbor set object
+     */
+    public static NeighborSet neighborSet(boolean random, Set<DeviceId> neighbors, boolean isMplsSet, int edgeLabel) {
+        return random ?
+                new RandomNeighborSet(neighbors, edgeLabel) :
+                new NeighborSet(neighbors, isMplsSet, edgeLabel);
+    }
+
+    /**
+     * Factory method for NeighborSet hierarchy.
+     *
+     * @param random the expected behavior.
+     * @return the neighbor set object
+     */
+    public static NeighborSet neighborSet(boolean random) {
+        return random ? new RandomNeighborSet() : new NeighborSet();
     }
 
     /**
@@ -87,6 +133,26 @@
         return edgeLabel;
     }
 
+    /**
+     * Gets the first neighbor of the set. The default
+     * implementation assure the first neighbor is the
+     * first of the set. Subclasses can modify this.
+     *
+     * @return the first neighbor of the set
+     */
+    public DeviceId getFirstNeighbor() {
+        return neighbors.isEmpty() ? DeviceId.NONE : neighbors.iterator().next();
+    }
+
+    /**
+     * Gets the value of mplsSet.
+     *
+     * @return the value of mplsSet
+     */
+    public boolean mplsSet() {
+        return mplsSet;
+    }
+
     // The list of neighbor ids and label are used for comparison.
     @Override
     public boolean equals(Object o) {
@@ -99,25 +165,22 @@
         NeighborSet that = (NeighborSet) o;
         return (this.neighbors.containsAll(that.neighbors) &&
                 that.neighbors.containsAll(this.neighbors) &&
-                (this.edgeLabel == that.edgeLabel));
+                (this.edgeLabel == that.edgeLabel) &&
+                (this.mplsSet == that.mplsSet));
     }
 
     // The list of neighbor ids and label are used for comparison.
     @Override
     public int hashCode() {
-        int result = 17;
-        int combinedHash = 0;
-        for (DeviceId d : neighbors) {
-            combinedHash = combinedHash + Objects.hash(d);
-        }
-        result = 31 * result + combinedHash + Objects.hash(edgeLabel);
-
-        return result;
+        return Objects.hash(neighbors, edgeLabel, mplsSet);
     }
 
     @Override
     public String toString() {
-        return " Neighborset Sw: " + neighbors
-                + " and Label: " + edgeLabel;
+        return toStringHelper(this)
+                .add("Neighborset Sw", neighbors)
+                .add("Label", edgeLabel)
+                .add("MplsSet", mplsSet)
+                .toString();
     }
 }