Make MPLS label request specifiable for a particular MPLS label

Change-Id: I4626229040c61e927a468ab5c486a907af0108ae
diff --git a/core/api/src/main/java/org/onosproject/net/resource/link/DefaultLinkResourceRequest.java b/core/api/src/main/java/org/onosproject/net/resource/link/DefaultLinkResourceRequest.java
index e61e87e..f8e143a 100644
--- a/core/api/src/main/java/org/onosproject/net/resource/link/DefaultLinkResourceRequest.java
+++ b/core/api/src/main/java/org/onosproject/net/resource/link/DefaultLinkResourceRequest.java
@@ -16,49 +16,47 @@
 package org.onosproject.net.resource.link;
 
 import java.util.Collection;
+import java.util.HashMap;
 import java.util.HashSet;
+import java.util.Map;
 import java.util.Set;
 import java.util.Objects;
+import java.util.stream.Collectors;
 
 import com.google.common.annotations.Beta;
+import com.google.common.collect.ImmutableMap;
 import org.onlab.util.Bandwidth;
 import org.onosproject.net.Link;
 import org.onosproject.net.intent.Constraint;
 import org.onosproject.net.intent.IntentId;
 
-import com.google.common.collect.ImmutableSet;
-
 import org.onosproject.net.intent.constraint.BandwidthConstraint;
 import org.onosproject.net.intent.constraint.LambdaConstraint;
 import org.onosproject.net.resource.ResourceRequest;
 import org.onosproject.net.resource.ResourceType;
 
+import static com.google.common.base.Preconditions.checkNotNull;
+
 /**
  * Implementation of {@link LinkResourceRequest}.
  */
 public final class DefaultLinkResourceRequest implements LinkResourceRequest {
 
     private final IntentId intentId;
-    private final Collection<Link> links;
-    private final Set<ResourceRequest> resources;
+    protected final Map<Link, Set<ResourceRequest>> requests;
 
     /**
-     * Creates a new link resource request with the given ID, links, and
-     * resource requests.
+     * Creates a new link resource request with the specified Intent ID,
+     * and resource requests over links.
      *
-     * @param intentId intent ID related to this request
-     * @param links a set of links for the request
-     * @param resources a set of resources to be requested
+     * @param intentId intent ID associated with this request
+     * @param requests resource requests over links
      */
-    private DefaultLinkResourceRequest(IntentId intentId,
-            Collection<Link> links,
-            Set<ResourceRequest> resources) {
-        this.intentId = intentId;
-        this.links = ImmutableSet.copyOf(links);
-        this.resources = ImmutableSet.copyOf(resources);
+    private DefaultLinkResourceRequest(IntentId intentId, Map<Link, Set<ResourceRequest>> requests) {
+        this.intentId = checkNotNull(intentId);
+        this.requests = checkNotNull(ImmutableMap.copyOf(requests));
     }
 
-
     @Override
     public ResourceType type() {
         return null;
@@ -71,12 +69,19 @@
 
     @Override
     public Collection<Link> links() {
-        return links;
+        return requests.keySet();
     }
 
     @Override
     public Set<ResourceRequest> resources() {
-        return resources;
+        return requests.values().stream()
+                .flatMap(Collection::stream)
+                .collect(Collectors.toSet());
+    }
+
+    @Override
+    public Set<ResourceRequest> resources(Link link) {
+        return requests.get(link);
     }
 
     /**
@@ -96,8 +101,7 @@
      */
     public static final class Builder implements LinkResourceRequest.Builder {
         private IntentId intentId;
-        private Collection<Link> links;
-        private Set<ResourceRequest> resources;
+        private Map<Link, Set<ResourceRequest>> requests;
 
         /**
          * Creates a new link resource request.
@@ -107,8 +111,10 @@
          */
         private Builder(IntentId intentId, Collection<Link> links) {
             this.intentId = intentId;
-            this.links = links;
-            this.resources = new HashSet<>();
+            this.requests = new HashMap<>();
+            for (Link link : links) {
+                requests.put(link, new HashSet<>());
+            }
         }
 
         /**
@@ -120,14 +126,18 @@
         @Deprecated
         @Override
         public Builder addLambdaRequest() {
-            resources.add(new LambdaResourceRequest());
+            for (Link link : requests.keySet()) {
+                requests.get(link).add(new LambdaResourceRequest());
+            }
             return this;
         }
 
         @Beta
         @Override
         public LinkResourceRequest.Builder addLambdaRequest(LambdaResource lambda) {
-            resources.add(new LambdaResourceRequest(lambda));
+            for (Link link : requests.keySet()) {
+                requests.get(link).add(new LambdaResourceRequest(lambda));
+            }
             return this;
         }
 
@@ -135,10 +145,36 @@
          * Adds Mpls request.
          *
          * @return self
+         * @deprecated in Emu Release
          */
+        @Deprecated
         @Override
         public Builder addMplsRequest() {
-            resources.add(new MplsLabelResourceRequest());
+            for (Link link : requests.keySet()) {
+                requests.get(link).add(new MplsLabelResourceRequest());
+            }
+            return this;
+        }
+
+        @Beta
+        @Override
+        public Builder addMplsRequest(MplsLabel label) {
+            for (Link link : requests.keySet()) {
+                requests.get(link).add(new MplsLabelResourceRequest(label));
+            }
+            return this;
+        }
+
+        @Beta
+        @Override
+        public LinkResourceRequest.Builder addMplsRequest(Map<Link, MplsLabel> labels) {
+            for (Link link : labels.keySet()) {
+                if (!requests.containsKey(link)) {
+                    requests.put(link, new HashSet<>());
+                }
+                requests.get(link).add(new MplsLabelResourceRequest(labels.get(link)));
+            }
+
             return this;
         }
 
@@ -150,7 +186,9 @@
          */
         @Override
         public Builder addBandwidthRequest(double bandwidth) {
-            resources.add(new BandwidthResourceRequest(new BandwidthResource(Bandwidth.bps(bandwidth))));
+            for (Link link : requests.keySet()) {
+                requests.get(link).add(new BandwidthResourceRequest(new BandwidthResource(Bandwidth.bps(bandwidth))));
+            }
             return this;
         }
 
@@ -172,13 +210,13 @@
          */
         @Override
         public LinkResourceRequest build() {
-            return new DefaultLinkResourceRequest(intentId, links, resources);
+            return new DefaultLinkResourceRequest(intentId, requests);
         }
     }
 
     @Override
     public int hashCode() {
-        return Objects.hash(intentId, links);
+        return Objects.hash(intentId, links());
     }
 
     @Override
@@ -191,6 +229,6 @@
         }
         final DefaultLinkResourceRequest other = (DefaultLinkResourceRequest) obj;
         return Objects.equals(this.intentId, other.intentId)
-                && Objects.equals(this.links, other.links);
+                && Objects.equals(this.links(), other.links());
     }
 }
diff --git a/core/api/src/main/java/org/onosproject/net/resource/link/LinkResourceRequest.java b/core/api/src/main/java/org/onosproject/net/resource/link/LinkResourceRequest.java
index 1478231..37622e7 100644
--- a/core/api/src/main/java/org/onosproject/net/resource/link/LinkResourceRequest.java
+++ b/core/api/src/main/java/org/onosproject/net/resource/link/LinkResourceRequest.java
@@ -15,15 +15,16 @@
  */
 package org.onosproject.net.resource.link;
 
+import java.util.Collection;
+import java.util.Map;
+import java.util.Set;
+
 import com.google.common.annotations.Beta;
 import org.onosproject.net.Link;
 import org.onosproject.net.intent.Constraint;
 import org.onosproject.net.intent.IntentId;
 import org.onosproject.net.resource.ResourceRequest;
 
-import java.util.Collection;
-import java.util.Set;
-
 /**
  * Representation of a request for link resource.
  */
@@ -51,6 +52,15 @@
     Set<ResourceRequest> resources();
 
     /**
+     * Returns the set of resource request against the specified link.
+     *
+     * @param link link whose associated resource request is to be returned
+     * @return set of resource request against the specified link
+     */
+    @Beta
+    Set<ResourceRequest> resources(Link link);
+
+    /**
      * Builder of link resource request.
      */
     interface Builder {
@@ -76,10 +86,30 @@
          * Adds MPLS request.
          *
          * @return self
+         * @deprecated in Emu Release
          */
+        @Deprecated
         Builder addMplsRequest();
 
         /**
+         * Adds MPLS request.
+         *
+         * @param label MPLS label to be requested
+         * @return self
+         */
+        @Beta
+        Builder addMplsRequest(MplsLabel label);
+
+        /**
+         * Adds MPLS request against the specified links.
+         *
+         * @param labels MPLS labels to be requested against links
+         * @return self
+         */
+        @Beta
+        Builder addMplsRequest(Map<Link, MplsLabel> labels);
+
+        /**
          * Adds bandwidth request with bandwidth value.
          *
          * @param bandwidth bandwidth value to be requested
diff --git a/core/api/src/main/java/org/onosproject/net/resource/link/MplsLabelResourceRequest.java b/core/api/src/main/java/org/onosproject/net/resource/link/MplsLabelResourceRequest.java
index 0a03f45..01a048b 100644
--- a/core/api/src/main/java/org/onosproject/net/resource/link/MplsLabelResourceRequest.java
+++ b/core/api/src/main/java/org/onosproject/net/resource/link/MplsLabelResourceRequest.java
@@ -15,15 +15,50 @@
  */
 package org.onosproject.net.resource.link;
 
+import com.google.common.annotations.Beta;
 import com.google.common.base.MoreObjects;
 import org.onosproject.net.resource.ResourceRequest;
 import org.onosproject.net.resource.ResourceType;
 
+import static com.google.common.base.Preconditions.checkNotNull;
+
 /**
  * Representation of a request for lambda resource.
  */
 public class MplsLabelResourceRequest implements ResourceRequest {
 
+    private final MplsLabel mplsLabel;
+
+    /**
+     * Constructs a request specifying the given MPLS label.
+     *
+     * @param mplsLabel MPLS label to be requested
+     */
+    @Beta
+    public MplsLabelResourceRequest(MplsLabel mplsLabel) {
+        this.mplsLabel = checkNotNull(mplsLabel);
+    }
+
+    /**
+     * Constructs a request asking an arbitrary available MPLS label.
+     *
+     * @deprecated in Emu Release
+     */
+    @Deprecated
+    public MplsLabelResourceRequest() {
+        this.mplsLabel = null;
+    }
+
+    /**
+     * Returns the MPLS label this request expects.
+     *
+     * @return the MPLS label this request expects
+     */
+    @Beta
+    public MplsLabel mplsLabel() {
+        return mplsLabel;
+    }
+
     @Override
     public ResourceType type() {
         return ResourceType.MPLS_LABEL;
@@ -32,6 +67,7 @@
     @Override
     public String toString() {
         return MoreObjects.toStringHelper(this)
+                .add("mplsLabel", mplsLabel)
                 .toString();
     }
 }
diff --git a/core/net/src/main/java/org/onosproject/net/resource/impl/LinkResourceManager.java b/core/net/src/main/java/org/onosproject/net/resource/impl/LinkResourceManager.java
index 5b2b0fb..fe05379 100644
--- a/core/net/src/main/java/org/onosproject/net/resource/impl/LinkResourceManager.java
+++ b/core/net/src/main/java/org/onosproject/net/resource/impl/LinkResourceManager.java
@@ -48,8 +48,8 @@
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
-import java.util.Iterator;
 import java.util.Map;
+import java.util.Optional;
 import java.util.Set;
 
 import static org.onosproject.security.AppGuard.checkPermission;
@@ -130,12 +130,15 @@
                     if (allocsPerLink.get(link) == null) {
                         allocsPerLink.put(link, new HashSet<>());
                     }
-                    Iterator<MplsLabel> mplsIter = getAvailableMplsLabels(link)
-                            .iterator();
-                    if (mplsIter.hasNext()) {
-                        allocsPerLink.get(link)
-                                .add(new MplsLabelResourceAllocation(mplsIter
-                                             .next()));
+
+                    Optional<MplsLabel> label = req.resources(link).stream()
+                            .filter(x -> x.type() == ResourceType.MPLS_LABEL)
+                            .map(x -> (MplsLabelResourceRequest) x)
+                            .map(MplsLabelResourceRequest::mplsLabel)
+                            .findFirst();
+
+                    if (label.isPresent()) {
+                        allocsPerLink.get(link).add(new MplsLabelResourceAllocation(label.get()));
                     } else {
                         log.info("Failed to allocate MPLS resource.");
                         break;
@@ -214,7 +217,8 @@
                         ((LambdaResourceAllocation) alloc).lambda()));
                 break;
             case MPLS_LABEL:
-                result.add(new MplsLabelResourceRequest());
+                result.add(new MplsLabelResourceRequest(
+                        ((MplsLabelResourceAllocation) alloc).mplsLabel()));
                 break;
             default:
                 break;