Rewrote optical connectivity intent compiler

Change-Id: I5acece3c14bed8a23f7bbe0c5a9bc0932a2a0881
diff --git a/core/api/src/main/java/org/onosproject/net/Device.java b/core/api/src/main/java/org/onosproject/net/Device.java
index ddfa6af..e36d762 100644
--- a/core/api/src/main/java/org/onosproject/net/Device.java
+++ b/core/api/src/main/java/org/onosproject/net/Device.java
@@ -26,7 +26,7 @@
      * Coarse classification of the type of the infrastructure device.
      */
     public enum Type {
-        SWITCH, ROUTER, ROADM, OTN, FIREWALL, BALANCER, IPS, IDS, CONTROLLER, OTHER
+        SWITCH, ROUTER, ROADM, OTN, ROADM_OTN, FIREWALL, BALANCER, IPS, IDS, CONTROLLER, OTHER
     }
 
     /**
diff --git a/core/api/src/main/java/org/onosproject/net/OchPort.java b/core/api/src/main/java/org/onosproject/net/OchPort.java
index 8a7836b..eb956f2 100644
--- a/core/api/src/main/java/org/onosproject/net/OchPort.java
+++ b/core/api/src/main/java/org/onosproject/net/OchPort.java
@@ -15,8 +15,6 @@
  */
 package org.onosproject.net;
 
-import org.onlab.util.Frequency;
-
 import java.util.Objects;
 
 import static com.google.common.base.MoreObjects.toStringHelper;
@@ -29,9 +27,6 @@
  */
 public class OchPort extends DefaultPort {
 
-    public static final Frequency CENTER_FREQUENCY = Frequency.ofTHz(193.1);
-    public static final Frequency FLEX_GRID_SLOT = Frequency.ofGHz(12.5);
-
     private final OduSignalType signalType;
     private final boolean isTunable;
     private final OchSignal lambda;
@@ -43,7 +38,7 @@
      * @param number      port number
      * @param isEnabled   port enabled state
      * @param signalType  ODU signal type
-     * @param isTunable   maximum frequency in MHz
+     * @param isTunable   tunable wavelength capability
      * @param lambda      OCh signal
      * @param annotations optional key/value annotations
      */
diff --git a/core/api/src/main/java/org/onosproject/net/OchSignal.java b/core/api/src/main/java/org/onosproject/net/OchSignal.java
index e629b5e..356950c 100644
--- a/core/api/src/main/java/org/onosproject/net/OchSignal.java
+++ b/core/api/src/main/java/org/onosproject/net/OchSignal.java
@@ -30,11 +30,10 @@
  * See ITU G.709 "Interfaces for the Optical Transport Network (OTN)".
  * </p>
  */
-// TODO: consider which is better, OchSignal or OpticalChannelSignal
 public class OchSignal implements Lambda {
 
-    private static final Frequency CENTER_FREQUENCY = Frequency.ofTHz(193.1);
-    private static final Frequency FLEX_GRID_SLOT = Frequency.ofGHz(12.5);
+    public static final Frequency CENTER_FREQUENCY = Frequency.ofTHz(193.1);
+    public static final Frequency FLEX_GRID_SLOT = Frequency.ofGHz(12.5);
 
     private final GridType gridType;
     private final ChannelSpacing channelSpacing;
@@ -57,10 +56,9 @@
               int spacingMultiplier, int slotGranularity) {
         this.gridType = checkNotNull(gridType);
         this.channelSpacing = checkNotNull(channelSpacing);
-        // TODO: check the precondition for spacingMultiplier. Is negative value permitted?
+        // Negative values are permitted for spacingMultiplier
         this.spacingMultiplier = spacingMultiplier;
-
-        checkArgument(slotGranularity > 0, "slotGranularity must be more than 0, but %s", slotGranularity);
+        checkArgument(slotGranularity > 0, "slotGranularity must be larger than 0, received %s", slotGranularity);
         this.slotGranularity = slotGranularity;
     }
 
diff --git a/core/api/src/main/java/org/onosproject/net/device/OchPortDescription.java b/core/api/src/main/java/org/onosproject/net/device/OchPortDescription.java
index 7f3d7f0..c3a7f41 100644
--- a/core/api/src/main/java/org/onosproject/net/device/OchPortDescription.java
+++ b/core/api/src/main/java/org/onosproject/net/device/OchPortDescription.java
@@ -40,7 +40,7 @@
      * @param isEnabled   port enabled state
      * @param signalType  ODU signal type
      * @param isTunable   tunable wavelength capability
-     * @param lambda      Och signal
+     * @param lambda      OCh signal
      * @param annotations optional key/value annotations map
      */
     public OchPortDescription(PortNumber number, boolean isEnabled, OduSignalType signalType,
diff --git a/core/api/src/main/java/org/onosproject/net/intent/OpticalConnectivityIntent.java b/core/api/src/main/java/org/onosproject/net/intent/OpticalConnectivityIntent.java
index 6b48b00..c2b84ab 100644
--- a/core/api/src/main/java/org/onosproject/net/intent/OpticalConnectivityIntent.java
+++ b/core/api/src/main/java/org/onosproject/net/intent/OpticalConnectivityIntent.java
@@ -24,8 +24,8 @@
 import static com.google.common.base.Preconditions.checkNotNull;
 
 /**
- * An optical layer intent for connectivity from one transponder port to another
- * transponder port. No traffic selector or traffic treatment are needed.
+ * An optical layer intent for connectivity between two OCh ports.
+ * No traffic selector or traffic treatment are needed.
  */
 public final class OpticalConnectivityIntent extends Intent {
     private final ConnectPoint src;
diff --git a/core/api/src/main/java/org/onosproject/net/intent/OpticalPathIntent.java b/core/api/src/main/java/org/onosproject/net/intent/OpticalPathIntent.java
index 0013c0d..5e1eacc 100644
--- a/core/api/src/main/java/org/onosproject/net/intent/OpticalPathIntent.java
+++ b/core/api/src/main/java/org/onosproject/net/intent/OpticalPathIntent.java
@@ -15,11 +15,9 @@
  */
 package org.onosproject.net.intent;
 
-import java.util.Collection;
-
 import org.onosproject.core.ApplicationId;
 import org.onosproject.net.ConnectPoint;
-import org.onosproject.net.Link;
+import org.onosproject.net.OchSignal;
 import org.onosproject.net.Path;
 
 import com.google.common.base.MoreObjects;
@@ -32,27 +30,27 @@
     private final ConnectPoint src;
     private final ConnectPoint dst;
     private final Path path;
-
+    private final OchSignal lambda;
 
     private OpticalPathIntent(ApplicationId appId,
                               Key key,
                               ConnectPoint src,
                               ConnectPoint dst,
                               Path path,
+                              OchSignal lambda,
                               int priority) {
-        super(appId,
-                key,
-                ImmutableSet.copyOf(path.links()),
-                priority);
+        super(appId, key, ImmutableSet.copyOf(path.links()), priority);
         this.src = checkNotNull(src);
         this.dst = checkNotNull(dst);
         this.path = checkNotNull(path);
+        this.lambda = checkNotNull(lambda);
     }
 
     protected OpticalPathIntent() {
         this.src = null;
         this.dst = null;
         this.path = null;
+        this.lambda = null;
     }
 
     /**
@@ -72,6 +70,7 @@
         private ConnectPoint src;
         private ConnectPoint dst;
         private Path path;
+        private OchSignal lambda;
         Key key;
 
         @Override
@@ -123,6 +122,17 @@
         }
 
         /**
+         * Sets the optical channel (lambda) for the intent that will be built.
+         *
+         * @param lambda the optical channel
+         * @return this builder
+         */
+        public Builder lambda(OchSignal lambda) {
+            this.lambda = lambda;
+            return this;
+        }
+
+        /**
          * Builds an optical path intent from the accumulated parameters.
          *
          * @return optical path intent
@@ -135,6 +145,7 @@
                     src,
                     dst,
                     path,
+                    lambda,
                     priority
             );
         }
@@ -153,6 +164,10 @@
         return path;
     }
 
+    public OchSignal lambda() {
+        return lambda;
+    }
+
     @Override
     public String toString() {
         return MoreObjects.toStringHelper(getClass())
@@ -163,11 +178,7 @@
                 .add("ingressPort", src)
                 .add("egressPort", dst)
                 .add("path", path)
+                .add("lambda", lambda)
                 .toString();
     }
-
-
-    public Collection<Link> requiredLinks() {
-        return path.links();
-    }
 }
diff --git a/core/api/src/main/java/org/onosproject/net/resource/DeviceResourceService.java b/core/api/src/main/java/org/onosproject/net/resource/DeviceResourceService.java
new file mode 100644
index 0000000..10e5911
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/resource/DeviceResourceService.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.net.resource;
+
+import org.onosproject.net.Port;
+import org.onosproject.net.intent.Intent;
+import org.onosproject.net.intent.IntentId;
+
+import java.util.Set;
+
+/**
+ * Service for providing device resources.
+ */
+public interface DeviceResourceService {
+    /**
+     * Request a set of ports needed to satisfy the intent.
+     *
+     * @param intent the intent
+     * @return set of ports
+     */
+    Set<Port> requestPorts(Intent intent);
+
+    /**
+     * Release ports associated with given intent ID.
+     *
+     * @param intentId intent ID
+     */
+    void releasePorts(IntentId intentId);
+}
diff --git a/core/api/src/main/java/org/onosproject/net/resource/DeviceResourceStore.java b/core/api/src/main/java/org/onosproject/net/resource/DeviceResourceStore.java
new file mode 100644
index 0000000..5df661c
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/resource/DeviceResourceStore.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.net.resource;
+
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.Port;
+import org.onosproject.net.intent.IntentId;
+
+import java.util.Set;
+
+public interface DeviceResourceStore {
+    Set<Port> getFreePorts(DeviceId deviceId);
+
+    void allocatePorts(Set<Port> port, IntentId intent);
+
+    void releasePorts(IntentId intent);
+}
diff --git a/core/api/src/test/java/org/onosproject/net/NetTestTools.java b/core/api/src/test/java/org/onosproject/net/NetTestTools.java
index b0601dd..eccb743 100644
--- a/core/api/src/test/java/org/onosproject/net/NetTestTools.java
+++ b/core/api/src/test/java/org/onosproject/net/NetTestTools.java
@@ -89,6 +89,10 @@
         return new DefaultPath(PID, links, ids.length);
     }
 
+    // Creates OCh signal
+    public static OchSignal createLambda() {
+        return new OchSignal(GridType.DWDM, ChannelSpacing.CHL_6P25GHZ, 8, 4);
+    }
 
     /**
      * Verifies that Annotations created by merging {@code annotations} is
diff --git a/core/api/src/test/java/org/onosproject/net/intent/OpticalPathIntentTest.java b/core/api/src/test/java/org/onosproject/net/intent/OpticalPathIntentTest.java
index f05e93c..3296336 100644
--- a/core/api/src/test/java/org/onosproject/net/intent/OpticalPathIntentTest.java
+++ b/core/api/src/test/java/org/onosproject/net/intent/OpticalPathIntentTest.java
@@ -18,6 +18,7 @@
 import org.hamcrest.Matchers;
 import org.junit.Before;
 import org.junit.Test;
+import org.onosproject.net.OchSignal;
 import org.onosproject.net.Path;
 
 import com.google.common.testing.EqualsTester;
@@ -28,6 +29,7 @@
 import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable;
 import static org.onosproject.net.NetTestTools.APP_ID;
 import static org.onosproject.net.NetTestTools.connectPoint;
+import static org.onosproject.net.NetTestTools.createLambda;
 import static org.onosproject.net.NetTestTools.createPath;
 
 public class OpticalPathIntentTest extends AbstractIntentTest {
@@ -37,6 +39,7 @@
     OpticalPathIntent intent1;
     OpticalPathIntent intent2;
     Path defaultPath;
+    OchSignal lambda;
 
     @Before
     public void opticalPathIntentTestSetUp() {
@@ -46,6 +49,7 @@
                 .src(connectPoint("one", 1))
                 .dst(connectPoint("two", 2))
                 .path(defaultPath)
+                .lambda(createLambda())
                 .priority(PRIORITY)
                 .build();
 
@@ -54,6 +58,7 @@
                 .src(connectPoint("two", 1))
                 .dst(connectPoint("one", 2))
                 .path(defaultPath)
+                .lambda(createLambda())
                 .priority(PRIORITY)
                 .build();
     }
diff --git a/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/OpticalConnectivityIntentCompiler.java b/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/OpticalConnectivityIntentCompiler.java
index 372d65b..91c9df3 100644
--- a/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/OpticalConnectivityIntentCompiler.java
+++ b/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/OpticalConnectivityIntentCompiler.java
@@ -15,6 +15,7 @@
  */
 package org.onosproject.net.intent.impl.compiler;
 
+import java.util.Collections;
 import java.util.List;
 import java.util.Set;
 
@@ -23,16 +24,31 @@
 import org.apache.felix.scr.annotations.Deactivate;
 import org.apache.felix.scr.annotations.Reference;
 import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.onlab.util.Frequency;
+import org.onosproject.net.ChannelSpacing;
 import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.GridType;
 import org.onosproject.net.Link;
+import org.onosproject.net.OchPort;
+import org.onosproject.net.OchSignal;
+import org.onosproject.net.OmsPort;
 import org.onosproject.net.Path;
+import org.onosproject.net.Port;
+import org.onosproject.net.device.DeviceService;
 import org.onosproject.net.intent.Intent;
 import org.onosproject.net.intent.IntentCompiler;
 import org.onosproject.net.intent.IntentExtensionService;
 import org.onosproject.net.intent.OpticalConnectivityIntent;
 import org.onosproject.net.intent.OpticalPathIntent;
-import org.onosproject.net.intent.impl.PathNotFoundException;
+import org.onosproject.net.resource.DefaultLinkResourceRequest;
+import org.onosproject.net.resource.DeviceResourceService;
+import org.onosproject.net.resource.LambdaResource;
+import org.onosproject.net.resource.LambdaResourceAllocation;
 import org.onosproject.net.resource.LinkResourceAllocations;
+import org.onosproject.net.resource.LinkResourceRequest;
+import org.onosproject.net.resource.LinkResourceService;
+import org.onosproject.net.resource.ResourceAllocation;
+import org.onosproject.net.resource.ResourceType;
 import org.onosproject.net.topology.LinkWeight;
 import org.onosproject.net.topology.Topology;
 import org.onosproject.net.topology.TopologyEdge;
@@ -40,18 +56,32 @@
 
 import com.google.common.collect.ImmutableList;
 
+import static com.google.common.base.Preconditions.checkArgument;
+
 /**
  * An intent compiler for {@link org.onosproject.net.intent.OpticalConnectivityIntent}.
  */
 @Component(immediate = true)
 public class OpticalConnectivityIntentCompiler implements IntentCompiler<OpticalConnectivityIntent> {
 
+    private static final GridType DEFAULT_OCH_GRIDTYPE = GridType.DWDM;
+    private static final ChannelSpacing DEFAULT_CHANNEL_SPACING = ChannelSpacing.CHL_50GHZ;
+
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected IntentExtensionService intentManager;
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected TopologyService topologyService;
 
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected DeviceService deviceService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected LinkResourceService linkResourceService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected DeviceResourceService deviceResourceService;
+
     @Activate
     public void activate() {
         intentManager.registerCompiler(OpticalConnectivityIntent.class, this);
@@ -66,19 +96,152 @@
     public List<Intent> compile(OpticalConnectivityIntent intent,
                                 List<Intent> installable,
                                 Set<LinkResourceAllocations> resources) {
-        // TODO: compute multiple paths using the K-shortest path algorithm
-        Path path = calculateOpticalPath(intent.getSrc(), intent.getDst());
-        Intent newIntent = OpticalPathIntent.builder()
-                .appId(intent.appId())
-                .src(intent.getSrc())
-                .dst(intent.getDst())
-                .path(path)
-                .build();
-        return ImmutableList.of(newIntent);
+        // Check if source and destination are optical OCh ports
+        ConnectPoint src = intent.getSrc();
+        ConnectPoint dst = intent.getDst();
+        Port srcPort = deviceService.getPort(src.deviceId(), src.port());
+        Port dstPort = deviceService.getPort(dst.deviceId(), dst.port());
+        checkArgument(srcPort instanceof OchPort);
+        checkArgument(dstPort instanceof OchPort);
+
+        // Calculate available light paths
+        Set<Path> paths = getOpticalPaths(intent);
+
+        // Use first path that can be successfully reserved
+        for (Path path : paths) {
+            // Request and reserve lambda on path
+            LinkResourceAllocations linkAllocs = assignWavelength(intent, path);
+            if (linkAllocs == null) {
+                continue;
+            }
+
+            OmsPort omsPort = (OmsPort) deviceService.getPort(path.src().deviceId(), path.src().port());
+
+            // Try to reserve port resources, roll back if unsuccessful
+            Set<Port> portAllocs = deviceResourceService.requestPorts(intent);
+            if (portAllocs == null) {
+                linkResourceService.releaseResources(linkAllocs);
+                continue;
+            }
+
+            // Create installable optical path intent
+            LambdaResourceAllocation lambdaAlloc = getWavelength(path, linkAllocs);
+            OchSignal ochSignal = getOchSignal(lambdaAlloc, omsPort.minFrequency(), omsPort.grid());
+
+            Intent newIntent = OpticalPathIntent.builder()
+                    .appId(intent.appId())
+                    .src(intent.getSrc())
+                    .dst(intent.getDst())
+                    .path(path)
+                    .lambda(ochSignal)
+                    .build();
+
+            return ImmutableList.of(newIntent);
+        }
+
+        return Collections.emptyList();
     }
 
-    private Path calculateOpticalPath(ConnectPoint start, ConnectPoint end) {
-        // TODO: support user policies
+    /**
+     * Find the lambda allocated to the path.
+     *
+     * @param path the path
+     * @param linkAllocs the link allocations
+     * @return
+     */
+    private LambdaResourceAllocation getWavelength(Path path, LinkResourceAllocations linkAllocs) {
+        for (Link link : path.links()) {
+            for (ResourceAllocation alloc : linkAllocs.getResourceAllocation(link)) {
+                if (alloc.type() == ResourceType.LAMBDA) {
+                    return (LambdaResourceAllocation) alloc;
+                }
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * Request and reserve first available wavelength across path.
+     *
+     * @param path path in WDM topology
+     * @return first available lambda resource allocation
+     */
+    private LinkResourceAllocations assignWavelength(Intent intent, Path path) {
+        LinkResourceRequest.Builder request =
+                DefaultLinkResourceRequest.builder(intent.id(), path.links())
+                .addLambdaRequest();
+
+        LinkResourceAllocations allocations = linkResourceService.requestResources(request.build());
+
+        checkWavelengthContinuity(allocations, path);
+
+        return allocations;
+    }
+
+    /**
+     * Checks wavelength continuity constraint across path, i.e., an identical lambda is used on all links.
+     * @return true if wavelength continuity is met, false otherwise
+     */
+    private boolean checkWavelengthContinuity(LinkResourceAllocations allocations, Path path) {
+        if (allocations == null) {
+            return false;
+        }
+
+        LambdaResource lambda = null;
+
+        for (Link link : path.links()) {
+            for (ResourceAllocation alloc : allocations.getResourceAllocation(link)) {
+                if (alloc.type() == ResourceType.LAMBDA) {
+                    LambdaResource nextLambda = ((LambdaResourceAllocation) alloc).lambda();
+                    if (nextLambda == null) {
+                        return false;
+                    }
+                    if (lambda == null) {
+                        lambda = nextLambda;
+                        continue;
+                    }
+                    if (!lambda.equals(nextLambda)) {
+                        return false;
+                    }
+                }
+            }
+        }
+
+        return true;
+    }
+
+    /**
+     * Convert lambda resource allocation in OCh signal.
+     *
+     * @param alloc lambda resource allocation
+     * @param minFrequency minimum frequency
+     * @param grid grid spacing frequency
+     * @return OCh signal
+     */
+    private OchSignal getOchSignal(LambdaResourceAllocation alloc, Frequency minFrequency, Frequency grid) {
+        int channel = alloc.lambda().toInt();
+
+        // Calculate center frequency
+        Frequency centerFrequency = minFrequency.add(grid.multiply(channel)).add(grid.floorDivision(2));
+
+        // Build OCh signal object
+        int spacingMultiplier = (int) (centerFrequency.subtract(OchSignal.CENTER_FREQUENCY).asHz() / grid.asHz());
+        int slotGranularity = (int) (grid.asHz() / ChannelSpacing.CHL_12P5GHZ.frequency().asHz());
+        OchSignal ochSignal = new OchSignal(DEFAULT_OCH_GRIDTYPE, DEFAULT_CHANNEL_SPACING,
+                spacingMultiplier, slotGranularity);
+
+        return ochSignal;
+    }
+
+    /**
+     * Calculates optical paths in WDM topology.
+     *
+     * @param intent optical connectivity intent
+     * @return set of paths in WDM topology
+     */
+    private Set<Path> getOpticalPaths(OpticalConnectivityIntent intent) {
+        // Route in WDM topology
         Topology topology = topologyService.currentTopology();
         LinkWeight weight = new LinkWeight() {
             @Override
@@ -86,18 +249,18 @@
                 if (edge.link().state() == Link.State.INACTIVE) {
                     return -1;
                 }
-                return edge.link().type() == Link.Type.OPTICAL ? +1 : -1;
+                if (edge.link().type() != Link.Type.OPTICAL) {
+                    return -1;
+                }
+                return edge.link().annotations().value("optical.type").equals("WDM") ? +1 : -1;
             }
         };
 
+        ConnectPoint start = intent.getSrc();
+        ConnectPoint end = intent.getDst();
         Set<Path> paths = topologyService.getPaths(topology, start.deviceId(),
-                                                   end.deviceId(), weight);
-        if (paths.isEmpty()) {
-            throw new PathNotFoundException(start.elementId(), end.elementId());
-        }
+                end.deviceId(), weight);
 
-        // TODO: let's be more intelligent about this eventually
-        return paths.iterator().next();
+        return paths;
     }
-
 }
diff --git a/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/OpticalPathIntentCompiler.java b/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/OpticalPathIntentCompiler.java
index 2cf4ccb..84368d9 100644
--- a/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/OpticalPathIntentCompiler.java
+++ b/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/OpticalPathIntentCompiler.java
@@ -30,29 +30,21 @@
 import org.onosproject.net.flow.FlowRule;
 import org.onosproject.net.flow.TrafficSelector;
 import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.flow.criteria.Criteria;
+import org.onosproject.net.flow.instructions.Instructions;
 import org.onosproject.net.intent.FlowRuleIntent;
 import org.onosproject.net.intent.Intent;
 import org.onosproject.net.intent.IntentCompiler;
 import org.onosproject.net.intent.IntentExtensionService;
 import org.onosproject.net.intent.OpticalPathIntent;
-import org.onosproject.net.intent.impl.IntentCompilationException;
-import org.onosproject.net.resource.DefaultLinkResourceRequest;
-import org.onosproject.net.resource.LambdaResource;
-import org.onosproject.net.resource.LambdaResourceAllocation;
 import org.onosproject.net.resource.LinkResourceAllocations;
-import org.onosproject.net.resource.LinkResourceRequest;
 import org.onosproject.net.resource.LinkResourceService;
-import org.onosproject.net.resource.ResourceAllocation;
-import org.onosproject.net.resource.ResourceType;
-import org.onosproject.net.topology.TopologyService;
 
 import java.util.Collections;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Set;
 
-import static org.onosproject.net.flow.DefaultTrafficTreatment.builder;
-
 @Component(immediate = true)
 public class OpticalPathIntentCompiler implements IntentCompiler<OpticalPathIntent> {
 
@@ -63,15 +55,10 @@
     protected CoreService coreService;
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
-    protected TopologyService topologyService;
-
-    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected LinkResourceService resourceService;
 
     private ApplicationId appId;
 
-    static final short SIGNAL_TYPE = (short) 1;
-
     @Activate
     public void activate() {
         appId = coreService.registerApplication("org.onosproject.net.intent");
@@ -86,64 +73,50 @@
     @Override
     public List<Intent> compile(OpticalPathIntent intent, List<Intent> installable,
                                 Set<LinkResourceAllocations> resources) {
-        LinkResourceAllocations allocations = assignWavelength(intent);
-
         return Collections.singletonList(
-                new FlowRuleIntent(appId, createRules(intent, allocations), intent.resources()));
+                new FlowRuleIntent(appId, createRules(intent), intent.resources()));
     }
 
-    private LinkResourceAllocations assignWavelength(OpticalPathIntent intent) {
-        LinkResourceRequest.Builder request = DefaultLinkResourceRequest
-                .builder(intent.id(), intent.path().links())
-                .addLambdaRequest();
-        return resourceService.requestResources(request.build());
-    }
-
-    private List<FlowRule> createRules(OpticalPathIntent intent, LinkResourceAllocations allocations) {
+    private List<FlowRule> createRules(OpticalPathIntent intent) {
         TrafficSelector.Builder selectorBuilder = DefaultTrafficSelector.builder();
         selectorBuilder.matchInPort(intent.src().port());
 
         List<FlowRule> rules = new LinkedList<>();
-        ConnectPoint prev = intent.src();
+        ConnectPoint current = intent.src();
 
         for (Link link : intent.path().links()) {
-            ResourceAllocation allocation = allocations.getResourceAllocation(link).stream()
-                    .filter(x -> x.type() == ResourceType.LAMBDA)
-                    .findFirst()
-                    .orElseThrow(() -> new IntentCompilationException("Lambda was not assigned successfully"));
-            LambdaResource la = ((LambdaResourceAllocation) allocation).lambda();
-
             TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
-            treatmentBuilder.setLambda((short) la.toInt());
+            treatmentBuilder.add(Instructions.modL0Lambda(intent.lambda()));
             treatmentBuilder.setOutput(link.src().port());
 
-            FlowRule rule = new DefaultFlowRule(prev.deviceId(),
-                    selectorBuilder.build(),
-                    treatmentBuilder.build(),
-                    100,
-                    appId,
-                    100,
-                    true);
+            FlowRule rule = DefaultFlowRule.builder()
+                    .forDevice(current.deviceId())
+                    .withSelector(selectorBuilder.build())
+                    .withTreatment(treatmentBuilder.build())
+                    .withPriority(100)
+                    .fromApp(appId)
+                    .makePermanent()
+                    .build();
 
             rules.add(rule);
 
-            prev = link.dst();
+            current = link.dst();
             selectorBuilder.matchInPort(link.dst().port());
-            selectorBuilder.matchOpticalSignalType(SIGNAL_TYPE);
-            selectorBuilder.matchLambda((short) la.toInt());
-
+            selectorBuilder.add(Criteria.matchLambda(intent.lambda()));
         }
 
-        // build the last T port rule
-        TrafficTreatment.Builder treatmentLast = builder();
+        // Build the egress ROADM rule
+        TrafficTreatment.Builder treatmentLast = DefaultTrafficTreatment.builder();
         treatmentLast.setOutput(intent.dst().port());
-        FlowRule rule = new DefaultFlowRule(intent.dst().deviceId(),
-                selectorBuilder.build(),
-                treatmentLast.build(),
-                100,
-                appId,
-                100,
-                true);
+
+        FlowRule rule = new DefaultFlowRule.Builder()
+                .forDevice(intent.dst().deviceId())
+                .withSelector(selectorBuilder.build())
+                .withTreatment(treatmentLast.build())
+                .withPriority(100)
+                .fromApp(appId)
+                .makePermanent()
+                .build();
         rules.add(rule);
 
         return rules;
diff --git a/core/net/src/main/java/org/onosproject/net/resource/impl/DeviceResourceManager.java b/core/net/src/main/java/org/onosproject/net/resource/impl/DeviceResourceManager.java
new file mode 100644
index 0000000..cfa290b
--- /dev/null
+++ b/core/net/src/main/java/org/onosproject/net/resource/impl/DeviceResourceManager.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.net.resource.impl;
+
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Deactivate;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.apache.felix.scr.annotations.Service;
+import org.onosproject.net.Port;
+import org.onosproject.net.intent.Intent;
+import org.onosproject.net.intent.IntentId;
+import org.onosproject.net.intent.OpticalConnectivityIntent;
+import org.onosproject.net.resource.DeviceResourceService;
+import org.onosproject.net.resource.DeviceResourceStore;
+import org.slf4j.Logger;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Provides basic implementation of device resources allocation.
+ */
+@Component(immediate = true)
+@Service
+public class DeviceResourceManager implements DeviceResourceService {
+
+    private final Logger log = getLogger(getClass());
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    private DeviceResourceStore store;
+
+    @Activate
+    public void activate() {
+        log.info("Started");
+    }
+
+    @Deactivate
+    public void deactivate() {
+        log.info("Stopped");
+    }
+
+    @Override
+    public Set<Port> requestPorts(Intent intent) {
+        checkNotNull(intent);
+        if (intent instanceof OpticalConnectivityIntent) {
+            OpticalConnectivityIntent opticalIntent = (OpticalConnectivityIntent) intent;
+            Set<Port> srcPorts = store.getFreePorts(opticalIntent.getSrc().deviceId());
+            Set<Port> dstPorts = store.getFreePorts(opticalIntent.getDst().deviceId());
+
+            Port srcPort = getTypedPort(srcPorts, Port.Type.OCH);
+            Port dstPort = getTypedPort(dstPorts, Port.Type.OCH);
+
+            if (srcPort == null || dstPort == null) {
+                return null;
+            }
+
+            Set<Port> allocPorts = new HashSet(Arrays.asList(srcPort, dstPort));
+
+            store.allocatePorts(allocPorts, intent.id());
+
+            return allocPorts;
+        }
+
+        return null;
+    }
+
+    @Override
+    public void releasePorts(IntentId intentId) {
+        store.releasePorts(intentId);
+    }
+
+    private Port getTypedPort(Set<Port> ports, Port.Type type) {
+        for (Port port : ports) {
+            if (port.type() == type) {
+                return port;
+            }
+        }
+
+        return null;
+    }
+}
diff --git a/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/OpticalPathIntentCompilerTest.java b/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/OpticalPathIntentCompilerTest.java
index 08e8e4f..a18f2c5 100644
--- a/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/OpticalPathIntentCompilerTest.java
+++ b/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/OpticalPathIntentCompilerTest.java
@@ -52,6 +52,7 @@
 import static org.onosproject.net.Link.Type.DIRECT;
 import static org.onosproject.net.NetTestTools.PID;
 import static org.onosproject.net.NetTestTools.connectPoint;
+import static org.onosproject.net.NetTestTools.createLambda;
 
 public class OpticalPathIntentCompilerTest {
 
@@ -93,6 +94,7 @@
                 .src(d1p1)
                 .dst(d3p1)
                 .path(new DefaultPath(PID, links, hops))
+                .lambda(createLambda())
                 .build();
         intentExtensionService = createMock(IntentExtensionService.class);
         intentExtensionService.registerCompiler(OpticalPathIntent.class, sut);
diff --git a/core/store/dist/src/main/java/org/onosproject/store/resource/impl/ConsistentDeviceResourceStore.java b/core/store/dist/src/main/java/org/onosproject/store/resource/impl/ConsistentDeviceResourceStore.java
new file mode 100644
index 0000000..b5e1655
--- /dev/null
+++ b/core/store/dist/src/main/java/org/onosproject/store/resource/impl/ConsistentDeviceResourceStore.java
@@ -0,0 +1,156 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.store.resource.impl;
+
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Deactivate;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.apache.felix.scr.annotations.Service;
+import org.onlab.util.KryoNamespace;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.Port;
+import org.onosproject.net.device.DeviceService;
+import org.onosproject.net.intent.IntentId;
+import org.onosproject.net.resource.DeviceResourceStore;
+import org.onosproject.store.serializers.KryoNamespaces;
+import org.onosproject.store.service.ConsistentMap;
+import org.onosproject.store.service.Serializer;
+import org.onosproject.store.service.StorageService;
+import org.onosproject.store.service.TransactionContext;
+import org.onosproject.store.service.TransactionalMap;
+import org.slf4j.Logger;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static org.slf4j.LoggerFactory.getLogger;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Store that manages device resources using Copycat-backed TransactionalMaps.
+ */
+@Component(immediate = true, enabled = true)
+@Service
+public class ConsistentDeviceResourceStore implements DeviceResourceStore {
+    private final Logger log = getLogger(getClass());
+
+    private static final String PORT_ALLOCATIONS = "PortAllocations";
+    private static final String INTENT_ALLOCATIONS = "IntentAllocations";
+
+    private static final Serializer SERIALIZER = Serializer.using(
+            new KryoNamespace.Builder().register(KryoNamespaces.API).build());
+
+    private ConsistentMap<Port, IntentId> portAllocMap;
+    private ConsistentMap<IntentId, Set<Port>> intentAllocMap;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected StorageService storageService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected DeviceService deviceService;
+
+    @Activate
+    public void activate() {
+        portAllocMap = storageService.<Port, IntentId>consistentMapBuilder()
+                .withName(PORT_ALLOCATIONS)
+                .withSerializer(SERIALIZER)
+                .build();
+        intentAllocMap = storageService.<IntentId, Set<Port>>consistentMapBuilder()
+                .withName(INTENT_ALLOCATIONS)
+                .withSerializer(SERIALIZER)
+                .build();
+        log.info("Started");
+    }
+
+    @Deactivate
+    public void deactivate() {
+        log.info("Stopped");
+    }
+
+    private TransactionalMap<Port, IntentId> getPortAllocs(TransactionContext tx) {
+        return tx.getTransactionalMap(PORT_ALLOCATIONS, SERIALIZER);
+    }
+
+    private TransactionalMap<IntentId, Set<Port>> getIntentAllocs(TransactionContext tx) {
+        return tx.getTransactionalMap(INTENT_ALLOCATIONS, SERIALIZER);
+    }
+
+    private TransactionContext getTxContext() {
+        return storageService.transactionContextBuilder().build();
+    }
+
+    @Override
+    public Set<Port> getFreePorts(DeviceId deviceId) {
+        checkNotNull(deviceId);
+
+        Set<Port> freePorts = new HashSet<>();
+        for (Port port : deviceService.getPorts(deviceId)) {
+            if (!portAllocMap.containsKey(port)) {
+                freePorts.add(port);
+            }
+        }
+
+        return freePorts;
+    }
+
+    @Override
+    public void allocatePorts(Set<Port> ports, IntentId intentId) {
+        checkNotNull(ports);
+        checkArgument(ports.size() > 0);
+        checkNotNull(intentId);
+
+        TransactionContext tx = getTxContext();
+        tx.begin();
+        try {
+            TransactionalMap<Port, IntentId> portAllocs = getPortAllocs(tx);
+            for (Port port : ports) {
+                portAllocs.put(port, intentId);
+            }
+            TransactionalMap<IntentId, Set<Port>> intentAllocs = getIntentAllocs(tx);
+            intentAllocs.put(intentId, ports);
+            tx.commit();
+        } catch (Exception e) {
+            log.error("Exception thrown, rolling back", e);
+            tx.abort();
+            throw e;
+        }
+    }
+
+    @Override
+    public void releasePorts(IntentId intentId) {
+        checkNotNull(intentId);
+
+        TransactionContext tx = getTxContext();
+        tx.begin();
+        try {
+            TransactionalMap<IntentId, Set<Port>> intentAllocs = getIntentAllocs(tx);
+            Set<Port> ports = intentAllocs.get(intentId);
+            intentAllocs.remove(intentId);
+
+            TransactionalMap<Port, IntentId> portAllocs = getPortAllocs(tx);
+            for (Port port : ports) {
+                portAllocs.remove(port);
+            }
+        } catch (Exception e) {
+            log.error("Exception thrown, rolling back", e);
+            tx.abort();
+            throw e;
+        }
+    }
+}
diff --git a/core/store/dist/src/main/java/org/onosproject/store/resource/impl/ConsistentLinkResourceStore.java b/core/store/dist/src/main/java/org/onosproject/store/resource/impl/ConsistentLinkResourceStore.java
index 6b22b75..454d04c 100644
--- a/core/store/dist/src/main/java/org/onosproject/store/resource/impl/ConsistentLinkResourceStore.java
+++ b/core/store/dist/src/main/java/org/onosproject/store/resource/impl/ConsistentLinkResourceStore.java
@@ -17,6 +17,8 @@
 import org.apache.felix.scr.annotations.Activate;
 import org.apache.felix.scr.annotations.Deactivate;
 import org.onlab.util.Bandwidth;
+import org.onosproject.net.OmsPort;
+import org.onosproject.net.device.DeviceService;
 import org.slf4j.Logger;
 import org.onlab.util.KryoNamespace;
 import org.onlab.util.PositionalParameterStringFormatter;
@@ -55,7 +57,6 @@
 import static com.google.common.base.Preconditions.checkState;
 import static org.slf4j.LoggerFactory.getLogger;
 import static org.onosproject.net.AnnotationKeys.BANDWIDTH;
-import static org.onosproject.net.AnnotationKeys.OPTICAL_WAVES;
 
 /**
  * Store that manages link resources using Copycat-backed TransactionalMaps.
@@ -78,7 +79,7 @@
 
     // table to store current allocations
     /** LinkKey -> List<LinkResourceAllocations>. */
-    private static final String LINK_RESOURCE_ALLOCATIONS = "LinkResourceAllocations";
+    private static final String LINK_RESOURCE_ALLOCATIONS = "o";
 
     /** IntentId -> LinkResourceAllocations. */
     private static final String INTENT_ALLOCATIONS = "IntentAllocations";
@@ -95,6 +96,9 @@
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected LinkService linkService;
 
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected DeviceService deviceService;
+
     @Activate
     public void activate() {
         intentAllocMap = storageService.<IntentId, LinkResourceAllocations>consistentMapBuilder()
@@ -136,14 +140,14 @@
 
     private Set<LambdaResourceAllocation> getLambdaResourceCapacity(Link link) {
         Set<LambdaResourceAllocation> allocations = new HashSet<>();
-        try {
-            final int waves = Integer.parseInt(link.annotations().value(OPTICAL_WAVES));
-            for (int i = 1; i <= waves; i++) {
-                allocations.add(new LambdaResourceAllocation(LambdaResource.valueOf(i)));
-            }
-        } catch (NumberFormatException e) {
-            log.debug("No {} annotation on link {}", OPTICAL_WAVES, link);
+
+        OmsPort port = (OmsPort) deviceService.getPort(link.src().deviceId(), link.src().port());
+
+        // Assume fixed grid for now
+        for (int i = 0; i < port.totalChannels(); i++) {
+            allocations.add(new LambdaResourceAllocation(LambdaResource.valueOf(i)));
         }
+
         return allocations;
     }