SinglePoint to MultiPoint Intent initial implementation

Change-Id: I1010997ce4ea993ae34afb8dab4b6c0ae112448d
diff --git a/core/api/src/main/java/org/onlab/onos/net/intent/LinkCollectionIntent.java b/core/api/src/main/java/org/onlab/onos/net/intent/LinkCollectionIntent.java
index ce1f6b1..3844611 100644
--- a/core/api/src/main/java/org/onlab/onos/net/intent/LinkCollectionIntent.java
+++ b/core/api/src/main/java/org/onlab/onos/net/intent/LinkCollectionIntent.java
@@ -16,6 +16,8 @@
 package org.onlab.onos.net.intent;
 
 import com.google.common.base.MoreObjects;
+import com.google.common.collect.ImmutableSet;
+
 import org.onlab.onos.core.ApplicationId;
 import org.onlab.onos.net.ConnectPoint;
 import org.onlab.onos.net.Link;
@@ -34,11 +36,11 @@
 
     private final Set<Link> links;
 
-    private final ConnectPoint egressPoint;
+    private final Set<ConnectPoint> egressPoints;
 
     /**
-     * Creates a new actionable intent capable of funneling the selected
-     * traffic along the specified convergent tree and out the given egress point.
+     * Creates a new actionable intent capable of funneling the selected traffic
+     * along the specified convergent tree and out the given egress point.
      *
      * @param appId       application identifier
      * @param selector    traffic match
@@ -77,7 +79,31 @@
         super(id(LinkCollectionIntent.class, selector, treatment, links, egressPoint, constraints),
                 appId, resources(links), selector, treatment, constraints);
         this.links = links;
-        this.egressPoint = egressPoint;
+        this.egressPoints = ImmutableSet.of(egressPoint);
+    }
+
+    /**
+     * Creates a new actionable intent capable of funneling the selected traffic
+     * along the specified convergent tree and out the given egress point.
+     *
+     * @param appId        application identifier
+     * @param selector     traffic match
+     * @param treatment    action
+     * @param links        traversed links
+     * @param egressPoints Set of egress point
+     * @throws NullPointerException {@code path} is null
+     */
+    public LinkCollectionIntent(ApplicationId appId,
+                                TrafficSelector selector,
+                                TrafficTreatment treatment,
+                                Set<Link> links,
+                                Set<ConnectPoint> egressPoints,
+                                List<Constraint> constraints) {
+        super(id(LinkCollectionIntent.class, selector, treatment, links,
+                 egressPoints), appId, resources(links), selector, treatment);
+
+        this.links = links;
+        this.egressPoints = ImmutableSet.copyOf(egressPoints);
     }
 
     /**
@@ -86,7 +112,7 @@
     protected LinkCollectionIntent() {
         super();
         this.links = null;
-        this.egressPoint = null;
+        this.egressPoints = null;
     }
 
     /**
@@ -104,8 +130,8 @@
      *
      * @return the egress point
      */
-    public ConnectPoint egressPoint() {
-        return egressPoint;
+    public Set<ConnectPoint> egressPoints() {
+        return egressPoints;
     }
 
     @Override
@@ -121,7 +147,7 @@
                 .add("selector", selector())
                 .add("treatment", treatment())
                 .add("links", links())
-                .add("egress", egressPoint())
+                .add("egress", egressPoints())
                 .toString();
     }
 }
diff --git a/core/api/src/main/java/org/onlab/onos/net/intent/SinglePointToMultiPointIntent.java b/core/api/src/main/java/org/onlab/onos/net/intent/SinglePointToMultiPointIntent.java
index efe96e2..7851e53 100644
--- a/core/api/src/main/java/org/onlab/onos/net/intent/SinglePointToMultiPointIntent.java
+++ b/core/api/src/main/java/org/onlab/onos/net/intent/SinglePointToMultiPointIntent.java
@@ -17,12 +17,15 @@
 
 import com.google.common.base.MoreObjects;
 import com.google.common.collect.Sets;
+
 import org.onlab.onos.core.ApplicationId;
 import org.onlab.onos.net.ConnectPoint;
 import org.onlab.onos.net.flow.TrafficSelector;
 import org.onlab.onos.net.flow.TrafficTreatment;
 
+import java.util.Collections;
 import java.util.Set;
+import java.util.List;
 
 import static com.google.common.base.Preconditions.checkArgument;
 import static com.google.common.base.Preconditions.checkNotNull;
@@ -38,30 +41,50 @@
     /**
      * Creates a new single-to-multi point connectivity intent.
      *
-     * @param appId        application identifier
-     * @param selector     traffic selector
-     * @param treatment    treatment
+     * @param appId application identifier
+     * @param selector traffic selector
+     * @param treatment treatment
      * @param ingressPoint port on which traffic will ingress
      * @param egressPoints set of ports on which traffic will egress
-     * @throws NullPointerException     if {@code ingressPoint} or
-     *                                  {@code egressPoints} is null
+     * @throws NullPointerException if {@code ingressPoint} or
+     *             {@code egressPoints} is null
      * @throws IllegalArgumentException if the size of {@code egressPoints} is
-     *                                  not more than 1
+     *             not more than 1
      */
     public SinglePointToMultiPointIntent(ApplicationId appId,
-                                         TrafficSelector selector,
-                                         TrafficTreatment treatment,
-                                         ConnectPoint ingressPoint,
-                                         Set<ConnectPoint> egressPoints) {
+            TrafficSelector selector, TrafficTreatment treatment,
+            ConnectPoint ingressPoint, Set<ConnectPoint> egressPoints) {
+        this(appId, selector, treatment, ingressPoint, egressPoints, Collections.emptyList());
+    }
+
+    /**
+     * Creates a new single-to-multi point connectivity intent.
+     *
+     * @param appId application identifier
+     * @param selector traffic selector
+     * @param treatment treatment
+     * @param ingressPoint port on which traffic will ingress
+     * @param egressPoints set of ports on which traffic will egress
+     * @param constraints constraints to apply to the intent
+     * @throws NullPointerException if {@code ingressPoint} or
+     *             {@code egressPoints} is null
+     * @throws IllegalArgumentException if the size of {@code egressPoints} is
+     *             not more than 1
+     */
+    public SinglePointToMultiPointIntent(ApplicationId appId,
+            TrafficSelector selector, TrafficTreatment treatment,
+            ConnectPoint ingressPoint, Set<ConnectPoint> egressPoints,
+            List<Constraint> constraints) {
         super(id(SinglePointToMultiPointIntent.class, selector, treatment,
-                 ingressPoint, egressPoints), appId, null, selector, treatment);
+                 ingressPoint, egressPoints), appId, null, selector, treatment,
+              constraints);
         checkNotNull(egressPoints);
         checkNotNull(ingressPoint);
         checkArgument(!egressPoints.isEmpty(), "Egress point set cannot be empty");
         checkArgument(!egressPoints.contains(ingressPoint),
                 "Set of egresses should not contain ingress (ingress: %s)", ingressPoint);
 
-        this.ingressPoint = ingressPoint;
+        this.ingressPoint = checkNotNull(ingressPoint);
         this.egressPoints = Sets.newHashSet(egressPoints);
     }
 
@@ -75,7 +98,8 @@
     }
 
     /**
-     * Returns the port on which the ingress traffic should be connected to the egress.
+     * Returns the port on which the ingress traffic should be connected to the
+     * egress.
      *
      * @return ingress port
      */
@@ -101,6 +125,7 @@
                 .add("treatment", treatment())
                 .add("ingress", ingressPoint)
                 .add("egress", egressPoints)
+                .add("constraints", constraints())
                 .toString();
     }
 
diff --git a/core/api/src/test/java/org/onlab/onos/net/intent/LinkCollectionIntentTest.java b/core/api/src/test/java/org/onlab/onos/net/intent/LinkCollectionIntentTest.java
index ddee9f9..f69e479 100644
--- a/core/api/src/test/java/org/onlab/onos/net/intent/LinkCollectionIntentTest.java
+++ b/core/api/src/test/java/org/onlab/onos/net/intent/LinkCollectionIntentTest.java
@@ -28,6 +28,7 @@
 import org.onlab.onos.net.intent.constraint.LambdaConstraint;
 import org.onlab.onos.net.resource.Lambda;
 
+import com.google.common.collect.ImmutableSet;
 import com.google.common.testing.EqualsTester;
 
 import static org.hamcrest.MatcherAssert.assertThat;
@@ -111,7 +112,7 @@
         assertThat(collectionIntent.isInstallable(), is(true));
         assertThat(collectionIntent.treatment(), is(treatment));
         assertThat(collectionIntent.selector(), is(selector));
-        assertThat(collectionIntent.egressPoint(), is(egress));
+        assertThat(collectionIntent.egressPoints(), is(ImmutableSet.of(egress)));
         assertThat(collectionIntent.resources(), hasSize(1));
         final List<Constraint> createdConstraints = collectionIntent.constraints();
         assertThat(createdConstraints, hasSize(0));
@@ -140,7 +141,7 @@
         assertThat(collectionIntent.isInstallable(), is(true));
         assertThat(collectionIntent.treatment(), is(treatment));
         assertThat(collectionIntent.selector(), is(selector));
-        assertThat(collectionIntent.egressPoint(), is(egress));
+        assertThat(collectionIntent.egressPoints(), is(ImmutableSet.of(egress)));
 
         final List<Constraint> createdConstraints = collectionIntent.constraints();
         assertThat(createdConstraints, hasSize(1));
@@ -161,7 +162,7 @@
         assertThat(collectionIntent.isInstallable(), is(true));
         assertThat(collectionIntent.treatment(), nullValue());
         assertThat(collectionIntent.selector(), nullValue());
-        assertThat(collectionIntent.egressPoint(), nullValue());
+        assertThat(collectionIntent.egressPoints(), nullValue());
 
         final List<Constraint> createdConstraints = collectionIntent.constraints();
         assertThat(createdConstraints, hasSize(0));