Bidirectional optical intents (ONOS-2055).
Removed dead code.
Bugfix in device resource store.

Change-Id: Ic81e0b6985813d8dd696440610bee967a9fc2fc7
diff --git a/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/OpticalCircuitIntentCompiler.java b/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/OpticalCircuitIntentCompiler.java
index 4da6d4f..fc62b25 100644
--- a/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/OpticalCircuitIntentCompiler.java
+++ b/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/OpticalCircuitIntentCompiler.java
@@ -136,15 +136,23 @@
                     .src(srcCP)
                     .dst(dstCP)
                     .signalType(OduSignalType.ODU4)
+                    .bidirectional(intent.isBidirectional())
                     .build();
             intents.add(connIntent);
         }
 
         // Create optical circuit intent
-        circuitIntent = new FlowRuleIntent(
-                appId,
-                createRules(src, connIntent.getSrc(), dst, connIntent.getDst()),
-                intent.resources());
+        List<FlowRule> rules = new LinkedList<>();
+        rules.add(connectPorts(src, connIntent.getSrc()));
+        rules.add(connectPorts(connIntent.getDst(), dst));
+
+        // Create flow rules for reverse path
+        if (intent.isBidirectional()) {
+            rules.add(connectPorts(connIntent.getSrc(), src));
+            rules.add(connectPorts(dst, connIntent.getDst()));
+        }
+
+        circuitIntent = new FlowRuleIntent(appId, rules, intent.resources());
 
         // Save circuit to connectivity intent mapping
         deviceResourceService.requestMapping(connIntent.id(), circuitIntent.id());
@@ -236,25 +244,25 @@
     }
 
     /**
-     * Builds flow rules for mapping between ODU and OCh ports.
+     * Builds flow rule for mapping between two ports.
      *
-     * @param srcOdu
-     * @param dstOdu
-     * @return
+     * @param src source port
+     * @param dst destination port
+     * @return flow rules
      */
-    private List<FlowRule> createRules(ConnectPoint srcOdu, ConnectPoint srcOch,
-                                       ConnectPoint dstOdu, ConnectPoint dstOch) {
+    private FlowRule connectPorts(ConnectPoint src, ConnectPoint dst) {
+        checkArgument(src.deviceId().equals(dst.deviceId()));
+
         TrafficSelector.Builder selectorBuilder = DefaultTrafficSelector.builder();
         TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
 
-        // Source flow rule
-        selectorBuilder.matchInPort(srcOdu.port());
+        selectorBuilder.matchInPort(src.port());
         //selectorBuilder.add(Criteria.matchCltSignalType)
-        treatmentBuilder.setOutput(srcOch.port());
+        treatmentBuilder.setOutput(dst.port());
         //treatmentBuilder.add(Instructions.modL1OduSignalType)
 
-        FlowRule srcRule = DefaultFlowRule.builder()
-                .forDevice(srcOdu.deviceId())
+        FlowRule flowRule = DefaultFlowRule.builder()
+                .forDevice(src.deviceId())
                 .withSelector(selectorBuilder.build())
                 .withTreatment(treatmentBuilder.build())
                 .withPriority(100)
@@ -262,21 +270,6 @@
                 .makePermanent()
                 .build();
 
-        // Destination flow rule
-        selectorBuilder.matchInPort(dstOch.port());
-        //selectorBuilder.add(Criteria.matchOduSignalType)
-        treatmentBuilder.setOutput(dstOdu.port());
-        //treatmentBuilder.add(Instructions.modL1CltSignalType)
-
-        FlowRule dstRule = DefaultFlowRule.builder()
-                .forDevice(dstOdu.deviceId())
-                .withSelector(selectorBuilder.build())
-                .withTreatment(treatmentBuilder.build())
-                .withPriority(100)
-                .fromApp(appId)
-                .makePermanent()
-                .build();
-
-        return Arrays.<FlowRule>asList(srcRule, dstRule);
+        return flowRule;
     }
 }
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 144f2df..13a2b6b 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
@@ -144,6 +144,7 @@
                     .path(path)
                     .lambda(ochSignal)
                     .signalType(signalType)
+                    .bidirectional(intent.isBidirectional())
                     .build();
 
             return ImmutableList.of(newIntent);
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 e7e0562..4cc93bb 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
@@ -15,6 +15,7 @@
  */
 package org.onosproject.net.intent.impl.compiler;
 
+import com.google.common.collect.Lists;
 import org.apache.felix.scr.annotations.Activate;
 import org.apache.felix.scr.annotations.Component;
 import org.apache.felix.scr.annotations.Deactivate;
@@ -79,10 +80,21 @@
                                 Set<LinkResourceAllocations> resources) {
         log.debug("Compiling optical path intent between {} and {}", intent.src(), intent.dst());
 
-        return Collections.singletonList(
-                new FlowRuleIntent(appId, createRules(intent), intent.resources()));
+        // Create rules for forward and reverse path
+        List<FlowRule> rules = createRules(intent);
+        if (intent.isBidirectional()) {
+            rules.addAll(createReverseRules(intent));
+        }
+
+        return Collections.singletonList(new FlowRuleIntent(appId, createRules(intent), intent.resources()));
     }
 
+    /**
+     * Create rules for the forward path of the intent.
+     *
+     * @param intent the intent
+     * @return list of flow rules
+     */
     private List<FlowRule> createRules(OpticalPathIntent intent) {
         TrafficSelector.Builder selectorBuilder = DefaultTrafficSelector.builder();
         selectorBuilder.matchInPort(intent.src().port());
@@ -128,4 +140,56 @@
 
         return rules;
     }
+
+    /**
+     * Create rules for the reverse path of the intent.
+     *
+     * @param intent the intent
+     * @return list of flow rules
+     */
+    private List<FlowRule> createReverseRules(OpticalPathIntent intent) {
+        TrafficSelector.Builder selectorBuilder = DefaultTrafficSelector.builder();
+        selectorBuilder.matchInPort(intent.dst().port());
+
+        List<FlowRule> rules = new LinkedList<>();
+        ConnectPoint current = intent.dst();
+
+        for (Link link : Lists.reverse(intent.path().links())) {
+            TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
+            treatmentBuilder.add(Instructions.modL0Lambda(intent.lambda()));
+            treatmentBuilder.setOutput(link.dst().port());
+
+            FlowRule rule = DefaultFlowRule.builder()
+                    .forDevice(current.deviceId())
+                    .withSelector(selectorBuilder.build())
+                    .withTreatment(treatmentBuilder.build())
+                    .withPriority(100)
+                    .fromApp(appId)
+                    .makePermanent()
+                    .build();
+
+            rules.add(rule);
+
+            current = link.src();
+            selectorBuilder.matchInPort(link.src().port());
+            selectorBuilder.add(Criteria.matchLambda(intent.lambda()));
+            selectorBuilder.add(Criteria.matchOchSignalType(intent.signalType()));
+        }
+
+        // Build the egress ROADM rule
+        TrafficTreatment.Builder treatmentLast = DefaultTrafficTreatment.builder();
+        treatmentLast.setOutput(intent.src().port());
+
+        FlowRule rule = new DefaultFlowRule.Builder()
+                .forDevice(intent.src().deviceId())
+                .withSelector(selectorBuilder.build())
+                .withTreatment(treatmentLast.build())
+                .withPriority(100)
+                .fromApp(appId)
+                .makePermanent()
+                .build();
+        rules.add(rule);
+
+        return rules;
+    }
 }