Release resources when intent is withdrawn (ONOS-2048).
Create optical circuits using CLI (ONOS-2049).

Change-Id: I8e52e698a897b869147afffdc0294956df76aa0c
diff --git a/apps/optical/src/main/java/org/onosproject/optical/OpticalPathProvisioner.java b/apps/optical/src/main/java/org/onosproject/optical/OpticalPathProvisioner.java
index dc41ee9..96bacc5 100644
--- a/apps/optical/src/main/java/org/onosproject/optical/OpticalPathProvisioner.java
+++ b/apps/optical/src/main/java/org/onosproject/optical/OpticalPathProvisioner.java
@@ -140,7 +140,6 @@
                 case INSTALL_REQ:
                     break;
                 case INSTALLED:
-                    // track h2h & p2p intents using our connectivity
                     break;
                 case FAILED:
                     log.info("Intent {} failed, calling optical path provisioning app.", event.subject());
@@ -407,8 +406,10 @@
             if (intent instanceof OpticalConnectivityIntent) {
                 deviceResourceService.releasePorts(intent.id());
                 linkResourceService.releaseResources(linkResourceService.getAllocations(intent.id()));
+            } else if (intent instanceof  OpticalCircuitIntent) {
+                deviceResourceService.releasePorts(intent.id());
+                deviceResourceService.releaseMapping(intent.id());
             }
-            // TODO: add other layers
         }
     }
 
diff --git a/cli/src/main/java/org/onosproject/cli/net/AddOpticalIntentCommand.java b/cli/src/main/java/org/onosproject/cli/net/AddOpticalIntentCommand.java
index 6f00174..97341d7 100644
--- a/cli/src/main/java/org/onosproject/cli/net/AddOpticalIntentCommand.java
+++ b/cli/src/main/java/org/onosproject/cli/net/AddOpticalIntentCommand.java
@@ -18,13 +18,18 @@
 import org.apache.karaf.shell.commands.Argument;
 import org.apache.karaf.shell.commands.Command;
 import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.OchPort;
+import org.onosproject.net.OduCltPort;
 import org.onosproject.net.OduSignalType;
+import org.onosproject.net.Port;
+import org.onosproject.net.device.DeviceService;
 import org.onosproject.net.intent.Intent;
 import org.onosproject.net.intent.IntentService;
+import org.onosproject.net.intent.OpticalCircuitIntent;
 import org.onosproject.net.intent.OpticalConnectivityIntent;
 
 /**
- * Installs optical connectivity intents.
+ * Installs optical connectivity or circuit intents, depending on given port types.
  */
 @Command(scope = "onos", name = "add-optical-intent",
          description = "Installs optical connectivity intent")
@@ -48,14 +53,33 @@
 
         ConnectPoint egress = ConnectPoint.deviceConnectPoint(egressDeviceString);
 
-        // FIXME: Hardcoded ODU signal type
-        Intent intent = OpticalConnectivityIntent.builder()
-                .appId(appId())
-                .key(key())
-                .src(ingress)
-                .dst(egress)
-                .signalType(OduSignalType.ODU4)
-                .build();
+        DeviceService deviceService = get(DeviceService.class);
+        Port srcPort = deviceService.getPort(ingress.deviceId(), ingress.port());
+        Port dstPort = deviceService.getPort(egress.deviceId(), egress.port());
+
+        Intent intent;
+        // FIXME: Hardcoded signal types
+        if (srcPort instanceof OduCltPort && dstPort instanceof OduCltPort) {
+            intent = OpticalCircuitIntent.builder()
+                    .appId(appId())
+                    .key(key())
+                    .src(ingress)
+                    .dst(egress)
+                    .signalType(OduCltPort.SignalType.CLT_10GBE)
+                    .build();
+        } else if (srcPort instanceof OchPort && dstPort instanceof OchPort) {
+            intent = OpticalConnectivityIntent.builder()
+                    .appId(appId())
+                    .key(key())
+                    .src(ingress)
+                    .dst(egress)
+                    .signalType(OduSignalType.ODU4)
+                    .build();
+        } else {
+            print("Unable to create optical intent between connect points {} and {}", ingress, egress);
+            return;
+        }
+
         service.submit(intent);
         print("Optical intent submitted:\n%s", intent.toString());
     }
diff --git a/core/api/src/main/java/org/onosproject/net/resource/device/DeviceResourceService.java b/core/api/src/main/java/org/onosproject/net/resource/device/DeviceResourceService.java
index 81bd1b7..8813b5b 100644
--- a/core/api/src/main/java/org/onosproject/net/resource/device/DeviceResourceService.java
+++ b/core/api/src/main/java/org/onosproject/net/resource/device/DeviceResourceService.java
@@ -67,7 +67,12 @@
      */
     Set<IntentId> getMapping(IntentId intentId);
 
-    void releaseMapping(IntentId keyIntentId, IntentId valIntentId);
+    /**
+     * Release mapping of given intent.
+     *
+     * @param intentId intent ID
+     */
+    void releaseMapping(IntentId intentId);
 
     /**
      * Release ports associated with given intent ID.
diff --git a/core/api/src/main/java/org/onosproject/net/resource/device/DeviceResourceStore.java b/core/api/src/main/java/org/onosproject/net/resource/device/DeviceResourceStore.java
index c73cab7..31cab02 100644
--- a/core/api/src/main/java/org/onosproject/net/resource/device/DeviceResourceStore.java
+++ b/core/api/src/main/java/org/onosproject/net/resource/device/DeviceResourceStore.java
@@ -66,12 +66,11 @@
     Set<IntentId> getMapping(IntentId intentId);
 
     /**
-     * Releases the mapping between the given intents.
+     * Releases the mapping of the given intent.
      *
-     * @param keyIntentId key intent ID
-     * @param valIntentId value intent ID
+     * @param intentId intent ID
      */
-    void releaseMapping(IntentId keyIntentId, IntentId valIntentId);
+    void releaseMapping(IntentId intentId);
 
     /**
      * Releases the ports allocated to the given intent.
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
index c9437de..62b4112 100644
--- 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
@@ -73,8 +73,8 @@
     }
 
     @Override
-    public void releaseMapping(IntentId keyIntentId, IntentId valIntentId) {
-        store.releaseMapping(keyIntentId, valIntentId);
+    public void releaseMapping(IntentId intentId) {
+        store.releaseMapping(intentId);
     }
 
     @Override
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
index 519fc83..09c2269 100644
--- 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
@@ -168,21 +168,6 @@
     }
 
     @Override
-    public void releaseMapping(IntentId keyIntentId, IntentId valIntentId) {
-        if (!intentMapping.containsKey(keyIntentId)) {
-            return;
-        }
-
-        Set<IntentId> intents = intentMapping.get(keyIntentId).value();
-
-        try {
-            intents.remove(valIntentId);
-        } catch (Exception e) {
-            log.error("Trying to remove non-existing mapping {} {}", keyIntentId, valIntentId);
-        }
-    }
-
-    @Override
     public boolean allocateMapping(IntentId keyIntentId, IntentId valIntentId) {
         Set<IntentId> intents = intentMapping.get(keyIntentId).value();
 
@@ -198,6 +183,17 @@
     }
 
     @Override
+    public void releaseMapping(IntentId intentId) {
+        for (IntentId intent : intentMapping.keySet()) {
+            // TODO: optimize by checking for identical src & dst
+            Set<IntentId> mapping = intentMapping.get(intent).value();
+            if (mapping.remove(intentId)) {
+                return;
+            }
+        }
+    }
+
+    @Override
     public boolean releasePorts(IntentId intentId) {
         checkNotNull(intentId);