[ONOS-7839] suggestedPath for optical connectivity intent with optical-rest support

Change-Id: I2b5093ac26149e450a14467c71656447233b5ce2
diff --git a/apps/optical-model/src/main/java/org/onosproject/net/optical/intent/impl/compiler/OpticalConnectivityIntentCompiler.java b/apps/optical-model/src/main/java/org/onosproject/net/optical/intent/impl/compiler/OpticalConnectivityIntentCompiler.java
index 5a76aef..1355337 100644
--- a/apps/optical-model/src/main/java/org/onosproject/net/optical/intent/impl/compiler/OpticalConnectivityIntentCompiler.java
+++ b/apps/optical-model/src/main/java/org/onosproject/net/optical/intent/impl/compiler/OpticalConnectivityIntentCompiler.java
@@ -60,13 +60,13 @@
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.Optional;
+import java.util.Collection;
+import java.util.LinkedList;
+import java.util.ArrayList;
+import java.util.Collections;
 import java.util.Set;
 import java.util.stream.Collectors;
 import java.util.stream.IntStream;
@@ -139,8 +139,15 @@
         resources.add(srcPortResource);
         resources.add(dstPortResource);
 
+        // If there is a suggestedPath, use this path without further checking, otherwise trigger path computation
+        Stream<Path> paths;
+        if (intent.suggestedPath().isPresent()) {
+            paths = Stream.of(intent.suggestedPath().get());
+        } else {
+            paths = getOpticalPaths(intent);
+        }
+
         // Find first path that has the required resources
-        Stream<Path> paths = getOpticalPaths(intent);
         Optional<Map.Entry<Path, List<OchSignal>>> found = paths
                 .map(path -> Maps.immutableEntry(path, findFirstAvailableLambda(intent, path)))
                 .filter(entry -> !entry.getValue().isEmpty())
@@ -350,8 +357,16 @@
                 return ScalarWeight.NON_VIABLE_WEIGHT;
             }
 
+            /**
+             *
+             * @param edge edge to be weighed
+             * @return the metric retrieved from the annotations otherwise 1
+             */
             @Override
             public Weight weight(TopologyEdge edge) {
+
+                log.debug("Link {} metric {}", edge.link(), edge.link().annotations().value("metric"));
+
                 // Disregard inactive or non-optical links
                 if (edge.link().state() == Link.State.INACTIVE) {
                     return ScalarWeight.toWeight(-1);
@@ -375,7 +390,13 @@
                     }
                 }
 
-                return ScalarWeight.toWeight(1);
+                String metricString = edge.link().annotations().value("metric");
+                if (!metricString.isEmpty()) {
+                    double metric = Double.parseDouble(metricString);
+                    return ScalarWeight.toWeight(metric);
+                } else {
+                    return ScalarWeight.toWeight(1);
+                }
             }
         };
 
@@ -418,6 +439,7 @@
                         return path;
                     });
         }
+
         return paths;
     }
 }
diff --git a/apps/optical-model/src/main/java/org/onosproject/net/optical/util/OpticalIntentUtility.java b/apps/optical-model/src/main/java/org/onosproject/net/optical/util/OpticalIntentUtility.java
index 8deb5ba..004c302 100644
--- a/apps/optical-model/src/main/java/org/onosproject/net/optical/util/OpticalIntentUtility.java
+++ b/apps/optical-model/src/main/java/org/onosproject/net/optical/util/OpticalIntentUtility.java
@@ -25,6 +25,7 @@
 import org.onosproject.net.OchSignal;
 import org.onosproject.net.OduSignalType;
 import org.onosproject.net.Port;
+import org.onosproject.net.Path;
 import org.onosproject.net.device.DeviceService;
 import org.onosproject.net.intent.Intent;
 import org.onosproject.net.intent.Key;
@@ -84,7 +85,7 @@
 
             // continue only if both OduClt port's Devices are of the same type
             if (!(srcDevice.type().equals(dstDevice.type()))) {
-                log.debug("Devices without same deviceType: SRC=%s and DST=%s", srcDevice.type(), dstDevice.type());
+                log.debug("Devices without same deviceType: SRC {} and DST={}", srcDevice.type(), dstDevice.type());
                 return intent;
             }
 
@@ -109,7 +110,7 @@
                         .bidirectional(bidirectional)
                         .build();
             } else {
-                log.debug("Wrong Device Type for connect points %s and %s", ingress, egress);
+                log.debug("Wrong Device Type for connect points {} and {}", ingress, egress);
             }
         } else if (srcPort instanceof OchPort && dstPort instanceof OchPort) {
             OduSignalType signalType = ((OchPort) srcPort).signalType();
@@ -123,7 +124,92 @@
                     .ochSignal(signal)
                     .build();
         } else {
-            log.debug("Unable to create optical intent between connect points %s and %s", ingress, egress);
+            log.debug("Unable to create optical intent between connect points {} and {}", ingress, egress);
+        }
+
+        return intent;
+    }
+
+    /**
+     * Returns a new optical intent created from the method parameters, strict suggestedPath is specified.
+     *
+     * @param ingress ingress description (device/port)
+     * @param egress egress description (device/port)
+     * @param deviceService device service
+     * @param key intent key
+     * @param appId application id
+     * @param bidirectional if this argument is true, the optical link created
+     * will be bidirectional, otherwise the link will be unidirectional.
+     * @param signal optical signal
+     * @param path suggested path for the intent
+     *
+     * @return created intent
+     */
+    public static Intent createExplicitOpticalIntent(ConnectPoint ingress, ConnectPoint
+            egress, DeviceService deviceService, Key key, ApplicationId appId, boolean
+                                                     bidirectional, OchSignal signal, Path path) {
+
+        Intent intent = null;
+
+        if (ingress == null || egress == null) {
+            log.error("Invalid endpoint(s); could not create optical intent");
+            return intent;
+        }
+
+        DeviceService ds = opticalView(deviceService);
+
+        Port srcPort = ds.getPort(ingress.deviceId(), ingress.port());
+        Port dstPort = ds.getPort(egress.deviceId(), egress.port());
+
+        if (srcPort instanceof OduCltPort && dstPort instanceof OduCltPort) {
+            Device srcDevice = ds.getDevice(ingress.deviceId());
+            Device dstDevice = ds.getDevice(egress.deviceId());
+
+            // continue only if both OduClt port's Devices are of the same type
+            if (!(srcDevice.type().equals(dstDevice.type()))) {
+                log.debug("Devices without same deviceType: SRC={} and DST={}", srcDevice.type(), dstDevice.type());
+                return intent;
+            }
+
+            CltSignalType signalType = ((OduCltPort) srcPort).signalType();
+            if (Device.Type.ROADM.equals(srcDevice.type()) ||
+                    Device.Type.ROADM_OTN.equals(srcDevice.type())) {
+                intent = OpticalCircuitIntent.builder()
+                        .appId(appId)
+                        .key(key)
+                        .src(ingress)
+                        .dst(egress)
+                        .signalType(signalType)
+                        .bidirectional(bidirectional)
+                        .build();
+            } else if (Device.Type.OTN.equals(srcDevice.type())) {
+                intent = OpticalOduIntent.builder()
+                        .appId(appId)
+                        .key(key)
+                        .src(ingress)
+                        .dst(egress)
+                        .signalType(signalType)
+                        .bidirectional(bidirectional)
+                        .build();
+            } else {
+                log.error("Wrong Device Type for connect points: " +
+                        "ingress {} of type {}; egress {} of type {}",
+                        ingress, srcDevice.type(), egress, dstDevice.type());
+            }
+        } else if (srcPort instanceof OchPort && dstPort instanceof OchPort) {
+            OduSignalType signalType = ((OchPort) srcPort).signalType();
+            intent = OpticalConnectivityIntent.builder()
+                    .appId(appId)
+                    .key(key)
+                    .src(ingress)
+                    .dst(egress)
+                    .signalType(signalType)
+                    .bidirectional(bidirectional)
+                    .ochSignal(signal)
+                    .suggestedPath(path)
+                    .build();
+        } else {
+            log.error("Unable to create explicit optical intent between connect points {} and {}", ingress, egress);
         }
 
         return intent;