Fix to reinstall flow rules when they are missing in FlowRuleService.

Change-Id: I1e7e0d62e27012cd090f3a72eb92eadc85afafdf
(cherry picked from commit 5c7fe3acf43bf1304038a7be55a5fd45e5805396)
diff --git a/apps/virtual/app/src/main/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkFlowRuleManager.java b/apps/virtual/app/src/main/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkFlowRuleManager.java
index 012f3b6..e2e743a 100644
--- a/apps/virtual/app/src/main/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkFlowRuleManager.java
+++ b/apps/virtual/app/src/main/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkFlowRuleManager.java
@@ -134,6 +134,11 @@
     }
 
     @Override
+    public FlowEntry getFlowEntry(FlowRule flowRule) {
+        return store.getFlowEntry(networkId(), flowRule);
+    }
+
+    @Override
     public Iterable<FlowEntry> getFlowEntries(DeviceId deviceId) {
         return store.getFlowEntries(networkId(), deviceId);
     }
diff --git a/core/api/src/main/java/org/onosproject/net/flow/FlowRuleService.java b/core/api/src/main/java/org/onosproject/net/flow/FlowRuleService.java
index 2b29504..9cada03 100644
--- a/core/api/src/main/java/org/onosproject/net/flow/FlowRuleService.java
+++ b/core/api/src/main/java/org/onosproject/net/flow/FlowRuleService.java
@@ -64,6 +64,14 @@
     }
 
     /**
+     * Returns the stored flow.
+     *
+     * @param rule the rule to look for
+     * @return a flow rule
+     */
+    FlowEntry getFlowEntry(FlowRule rule);
+
+    /**
      * Returns the collection of flow entries applied on the specified device.
      * This will include flow rules which may not yet have been applied to
      * the device.
diff --git a/core/api/src/test/java/org/onosproject/net/flow/FlowRuleServiceAdapter.java b/core/api/src/test/java/org/onosproject/net/flow/FlowRuleServiceAdapter.java
index 4f53b96..1ccbbc8 100644
--- a/core/api/src/test/java/org/onosproject/net/flow/FlowRuleServiceAdapter.java
+++ b/core/api/src/test/java/org/onosproject/net/flow/FlowRuleServiceAdapter.java
@@ -29,6 +29,11 @@
     }
 
     @Override
+    public FlowEntry getFlowEntry(FlowRule rule) {
+        return null;
+    }
+
+    @Override
     public Iterable<FlowEntry> getFlowEntries(DeviceId deviceId) {
         return null;
     }
diff --git a/core/net/src/main/java/org/onosproject/net/flow/impl/FlowRuleManager.java b/core/net/src/main/java/org/onosproject/net/flow/impl/FlowRuleManager.java
index ac97636..9dc92d1 100644
--- a/core/net/src/main/java/org/onosproject/net/flow/impl/FlowRuleManager.java
+++ b/core/net/src/main/java/org/onosproject/net/flow/impl/FlowRuleManager.java
@@ -295,6 +295,13 @@
     }
 
     @Override
+    public FlowEntry getFlowEntry(FlowRule rule) {
+        checkPermission(FLOWRULE_READ);
+        checkNotNull(rule, FLOW_RULE_NULL);
+        return store.getFlowEntry(rule);
+    }
+
+    @Override
     public Iterable<FlowEntry> getFlowEntries(DeviceId deviceId) {
         checkPermission(FLOWRULE_READ);
         checkNotNull(deviceId, DEVICE_ID_NULL);
diff --git a/core/net/src/main/java/org/onosproject/net/intent/impl/installer/FlowRuleIntentInstaller.java b/core/net/src/main/java/org/onosproject/net/intent/impl/installer/FlowRuleIntentInstaller.java
index b2cdf5a..71cf28c 100644
--- a/core/net/src/main/java/org/onosproject/net/intent/impl/installer/FlowRuleIntentInstaller.java
+++ b/core/net/src/main/java/org/onosproject/net/intent/impl/installer/FlowRuleIntentInstaller.java
@@ -174,6 +174,7 @@
             flowRulesToUninstall = uninstallIntents.stream()
                     .map(FlowRuleIntent::flowRules)
                     .flatMap(Collection::stream)
+                    .filter(flowRule -> flowRuleService.getFlowEntry(flowRule) != null)
                     .collect(Collectors.toList());
         } else {
             // No flow rules to be uninstalled.
diff --git a/core/net/src/test/java/org/onosproject/net/flow/impl/FlowRuleManagerTest.java b/core/net/src/test/java/org/onosproject/net/flow/impl/FlowRuleManagerTest.java
index 3801388..300b023 100644
--- a/core/net/src/test/java/org/onosproject/net/flow/impl/FlowRuleManagerTest.java
+++ b/core/net/src/test/java/org/onosproject/net/flow/impl/FlowRuleManagerTest.java
@@ -207,7 +207,7 @@
         FlowRule rule = flowRule(hval, hval);
         service.applyFlowRules(rule);
 
-        assertNotNull("rule should be found", service.getFlowEntries(DID));
+        assertNotNull("rule should be found", service.getFlowEntry(rule));
         return rule;
     }
 
@@ -234,6 +234,24 @@
     }
 
     @Test
+    public void getFlowEntry() {
+        assertTrue("store should be empty",
+                Sets.newHashSet(service.getFlowEntries(DID)).isEmpty());
+        FlowRule f1 = addFlowRule(1);
+        FlowRule f2 = addFlowRule(2);
+
+        FlowEntry fe1 = new DefaultFlowEntry(f1);
+        FlowEntry fe2 = new DefaultFlowEntry(f2);
+        assertEquals("2 rules should exist", 2, flowCount());
+
+        FlowEntry actual1 = service.getFlowEntry(f1);
+        FlowEntry actual2 = service.getFlowEntry(f2);
+
+        assertEquals(fe1, actual1);
+        assertEquals(fe2, actual2);
+    }
+
+    @Test
     public void getFlowEntries() {
         assertTrue("store should be empty",
                    Sets.newHashSet(service.getFlowEntries(DID)).isEmpty());
diff --git a/core/net/src/test/java/org/onosproject/net/intent/impl/installer/FlowRuleIntentInstallerTest.java b/core/net/src/test/java/org/onosproject/net/intent/impl/installer/FlowRuleIntentInstallerTest.java
index 712f8bf..5c00a83 100644
--- a/core/net/src/test/java/org/onosproject/net/intent/impl/installer/FlowRuleIntentInstallerTest.java
+++ b/core/net/src/test/java/org/onosproject/net/intent/impl/installer/FlowRuleIntentInstallerTest.java
@@ -26,10 +26,13 @@
 import org.onlab.packet.VlanId;
 import org.onosproject.cfg.ComponentConfigService;
 import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.DeviceId;
 import org.onosproject.net.NetworkResource;
+import org.onosproject.net.flow.DefaultFlowEntry;
 import org.onosproject.net.flow.DefaultFlowRule;
 import org.onosproject.net.flow.DefaultTrafficSelector;
 import org.onosproject.net.flow.DefaultTrafficTreatment;
+import org.onosproject.net.flow.FlowEntry;
 import org.onosproject.net.flow.FlowRule;
 import org.onosproject.net.flow.FlowRuleOperation;
 import org.onosproject.net.flow.FlowRuleOperations;
@@ -141,6 +144,8 @@
         IntentInstallationContext context = new IntentInstallationContext(toUninstall, toInstall);
         operationContext = new IntentOperationContext(intentsToUninstall, intentsToInstall, context);
 
+        flowRuleService.load(operationContext.intentsToUninstall());
+
         installer.apply(operationContext);
 
         IntentOperationContext successContext = intentInstallCoordinator.successContext;
@@ -156,6 +161,36 @@
     }
 
     /**
+     * Uninstalls Intents only, no Intents to be install.  However, the flow rules do not exist
+     * in the FlowRuleService.
+     */
+    @Test
+    public void testUninstallOnlyMissing() {
+        List<Intent> intentsToInstall = Lists.newArrayList();
+        List<Intent> intentsToUninstall = createFlowRuleIntents();
+
+        IntentData toInstall = null;
+        IntentData toUninstall = new IntentData(createP2PIntent(),
+                IntentState.WITHDRAWING,
+                new WallClockTimestamp());
+        toUninstall = IntentData.compiled(toUninstall, intentsToUninstall);
+
+
+        IntentOperationContext<FlowRuleIntent> operationContext;
+        IntentInstallationContext context = new IntentInstallationContext(toUninstall, toInstall);
+        operationContext = new IntentOperationContext(intentsToUninstall, intentsToInstall, context);
+
+        installer.apply(operationContext);
+
+        IntentOperationContext successContext = intentInstallCoordinator.successContext;
+        assertEquals(successContext, operationContext);
+
+        assertEquals(0, flowRuleService.flowRulesRemove.size());
+        assertEquals(0, flowRuleService.flowRulesAdd.size());
+        assertEquals(0, flowRuleService.flowRulesModify.size());
+    }
+
+    /**
      * Do both install and uninstall Intents with different flow rules.
      */
     @Test
@@ -176,6 +211,8 @@
         IntentInstallationContext context = new IntentInstallationContext(toUninstall, toInstall);
         operationContext = new IntentOperationContext(intentsToUninstall, intentsToInstall, context);
 
+        flowRuleService.load(operationContext.intentsToUninstall());
+
         installer.apply(operationContext);
 
         IntentOperationContext successContext = intentInstallCoordinator.successContext;
@@ -199,6 +236,46 @@
     }
 
     /**
+     * Do both install and uninstall Intents with different flow rules.  However, the flow rules do not exist
+     * in the FlowRuleService.
+     */
+    @Test
+    public void testUninstallAndInstallMissing() {
+        List<Intent> intentsToInstall = createAnotherFlowRuleIntents();
+        List<Intent> intentsToUninstall = createFlowRuleIntents();
+
+        IntentData toInstall = new IntentData(createP2PIntent(),
+                IntentState.INSTALLING,
+                new WallClockTimestamp());
+        toInstall = IntentData.compiled(toInstall, intentsToInstall);
+        IntentData toUninstall = new IntentData(createP2PIntent(),
+                IntentState.INSTALLED,
+                new WallClockTimestamp());
+        toUninstall = IntentData.compiled(toUninstall, intentsToUninstall);
+
+        IntentOperationContext<FlowRuleIntent> operationContext;
+        IntentInstallationContext context = new IntentInstallationContext(toUninstall, toInstall);
+        operationContext = new IntentOperationContext(intentsToUninstall, intentsToInstall, context);
+
+        installer.apply(operationContext);
+
+        IntentOperationContext successContext = intentInstallCoordinator.successContext;
+        assertEquals(successContext, operationContext);
+
+        Set<FlowRule> expectedFlowRules = Sets.newHashSet();
+
+        assertEquals(expectedFlowRules, flowRuleService.flowRulesRemove);
+
+        expectedFlowRules = intentsToInstall.stream()
+                .map(intent -> (FlowRuleIntent) intent)
+                .map(FlowRuleIntent::flowRules)
+                .flatMap(Collection::stream)
+                .collect(Collectors.toSet());
+
+        assertEquals(expectedFlowRules, flowRuleService.flowRulesAdd);
+    }
+
+    /**
      * Do both install and uninstall Intents with same flow rules.
      */
     @Test
@@ -219,6 +296,8 @@
         IntentInstallationContext context = new IntentInstallationContext(toUninstall, toInstall);
         operationContext = new IntentOperationContext(intentsToUninstall, intentsToInstall, context);
 
+        flowRuleService.load(operationContext.intentsToUninstall());
+
         installer.apply(operationContext);
 
         IntentOperationContext successContext = intentInstallCoordinator.successContext;
@@ -230,6 +309,38 @@
     }
 
     /**
+     * Do both install and uninstall Intents with same flow rules.  However, the flow rules do not exist
+     * in the FlowRuleService.
+     */
+    @Test
+    public void testUninstallAndInstallUnchangedMissing() {
+        List<Intent> intentsToInstall = createFlowRuleIntents();
+        List<Intent> intentsToUninstall = createFlowRuleIntents();
+
+        IntentData toInstall = new IntentData(createP2PIntent(),
+                IntentState.INSTALLING,
+                new WallClockTimestamp());
+        toInstall = IntentData.compiled(toInstall, intentsToInstall);
+        IntentData toUninstall = new IntentData(createP2PIntent(),
+                IntentState.INSTALLED,
+                new WallClockTimestamp());
+        toUninstall = IntentData.compiled(toUninstall, intentsToUninstall);
+
+        IntentOperationContext<FlowRuleIntent> operationContext;
+        IntentInstallationContext context = new IntentInstallationContext(toUninstall, toInstall);
+        operationContext = new IntentOperationContext(intentsToUninstall, intentsToInstall, context);
+
+        installer.apply(operationContext);
+
+        IntentOperationContext successContext = intentInstallCoordinator.successContext;
+        assertEquals(successContext, operationContext);
+
+        assertEquals(0, flowRuleService.flowRulesRemove.size());
+        assertEquals(1, flowRuleService.flowRulesAdd.size());
+        assertEquals(0, flowRuleService.flowRulesModify.size());
+    }
+
+    /**
      * Do both install and uninstall Intents with same flow rule Intent.
      */
     @Test
@@ -250,6 +361,8 @@
         IntentInstallationContext context = new IntentInstallationContext(toUninstall, toInstall);
         operationContext = new IntentOperationContext(intentsToUninstall, intentsToInstall, context);
 
+        flowRuleService.load(operationContext.intentsToUninstall());
+
         installer.apply(operationContext);
 
         IntentOperationContext successContext = intentInstallCoordinator.successContext;
@@ -261,6 +374,38 @@
     }
 
     /**
+     * Do both install and uninstall Intents with same flow rule Intent. However, the flow rules do not exist
+     * in the FlowRuleService.
+     */
+    @Test
+    public void testUninstallAndInstallSameMissing() {
+        List<Intent> intentsToInstall = createFlowRuleIntents();
+        List<Intent> intentsToUninstall = intentsToInstall;
+
+        IntentData toInstall = new IntentData(createP2PIntent(),
+                IntentState.INSTALLING,
+                new WallClockTimestamp());
+        toInstall = IntentData.compiled(toInstall, intentsToInstall);
+        IntentData toUninstall = new IntentData(createP2PIntent(),
+                IntentState.INSTALLED,
+                new WallClockTimestamp());
+        toUninstall = IntentData.compiled(toUninstall, intentsToUninstall);
+
+        IntentOperationContext<FlowRuleIntent> operationContext;
+        IntentInstallationContext context = new IntentInstallationContext(toUninstall, toInstall);
+        operationContext = new IntentOperationContext(intentsToUninstall, intentsToInstall, context);
+
+        installer.apply(operationContext);
+
+        IntentOperationContext successContext = intentInstallCoordinator.successContext;
+        assertEquals(successContext, operationContext);
+
+        assertEquals(0, flowRuleService.flowRulesRemove.size());
+        assertEquals(1, flowRuleService.flowRulesAdd.size());
+        assertEquals(0, flowRuleService.flowRulesModify.size());
+    }
+
+    /**
      * Nothing to uninstall or install.
      */
     @Test
@@ -327,6 +472,8 @@
         IntentInstallationContext context = new IntentInstallationContext(toUninstall, toInstall);
         operationContext = new IntentOperationContext(intentsToUninstall, intentsToInstall, context);
 
+        flowRuleService.load(operationContext.intentsToUninstall());
+
         installer.apply(operationContext);
 
         IntentOperationContext successContext = intentInstallCoordinator.successContext;
@@ -342,6 +489,42 @@
     }
 
     /**
+     * Test intents with same match rules, should do modify instead of add.  However, the flow rules do not exist
+     * in the FlowRuleService.
+     */
+    @Test
+    public void testRuleModifyMissing() {
+        List<Intent> intentsToInstall = createFlowRuleIntents();
+        List<Intent> intentsToUninstall = createFlowRuleIntentsWithSameMatch();
+
+        IntentData toInstall = new IntentData(createP2PIntent(),
+                IntentState.INSTALLING,
+                new WallClockTimestamp());
+        toInstall = IntentData.compiled(toInstall, intentsToInstall);
+        IntentData toUninstall = new IntentData(createP2PIntent(),
+                IntentState.INSTALLED,
+                new WallClockTimestamp());
+        toUninstall = IntentData.compiled(toUninstall, intentsToUninstall);
+
+        IntentOperationContext<FlowRuleIntent> operationContext;
+        IntentInstallationContext context = new IntentInstallationContext(toUninstall, toInstall);
+        operationContext = new IntentOperationContext(intentsToUninstall, intentsToInstall, context);
+
+        installer.apply(operationContext);
+
+        IntentOperationContext successContext = intentInstallCoordinator.successContext;
+        assertEquals(successContext, operationContext);
+
+        assertEquals(0, flowRuleService.flowRulesRemove.size());
+        assertEquals(1, flowRuleService.flowRulesAdd.size());
+        assertEquals(0, flowRuleService.flowRulesModify.size());
+
+        FlowRuleIntent installedIntent = (FlowRuleIntent) intentsToInstall.get(0);
+        assertEquals(flowRuleService.flowRulesAdd.size(), installedIntent.flowRules().size());
+        assertTrue(flowRuleService.flowRulesAdd.containsAll(installedIntent.flowRules()));
+    }
+
+    /**
      * Testing the non-disruptive reallocation.
      */
     @Test
@@ -690,15 +873,43 @@
         return flowRuleIntents;
     }
 
+
+
     /**
      * The FlowRuleService for test; always success for any flow rule operations.
      */
     class TestFlowRuleService extends FlowRuleServiceAdapter {
 
+        Set<FlowEntry> flowEntries = Sets.newHashSet();
         Set<FlowRule> flowRulesAdd = Sets.newHashSet();
         Set<FlowRule> flowRulesModify = Sets.newHashSet();
         Set<FlowRule> flowRulesRemove = Sets.newHashSet();
 
+        @Override
+        public FlowEntry getFlowEntry(FlowRule flowRule) {
+            for (FlowEntry entry : flowEntries) {
+                if (entry.id().equals(flowRule.id()) && entry.deviceId().equals(flowRule.deviceId())) {
+                    return entry;
+                }
+            }
+            return null;
+        }
+
+        @Override
+        public Iterable<FlowEntry> getFlowEntries(DeviceId deviceId) {
+            return flowEntries.stream()
+                    .filter(flow -> flow.deviceId().equals(deviceId))
+                    .collect(Collectors.toList());
+        }
+
+        public void load(List<FlowRuleIntent> intents) {
+            for (FlowRuleIntent flowRuleIntent : intents) {
+                for (FlowRule flowRule : flowRuleIntent.flowRules()) {
+                    flowEntries.add(new DefaultFlowEntry(flowRule, FlowEntry.FlowEntryState.ADDED));
+                }
+            }
+        }
+
         public void record(FlowRuleOperations ops) {
             flowRulesAdd.clear();
             flowRulesRemove.clear();
@@ -706,12 +917,15 @@
                 stage.forEach(op -> {
                     switch (op.type()) {
                         case ADD:
+                            flowEntries.add(new DefaultFlowEntry(op.rule(), FlowEntry.FlowEntryState.ADDED));
                             flowRulesAdd.add(op.rule());
                             break;
                         case REMOVE:
+                            flowEntries.remove(new DefaultFlowEntry(op.rule(), FlowEntry.FlowEntryState.ADDED));
                             flowRulesRemove.add(op.rule());
                             break;
                         case MODIFY:
+                            flowEntries.add(new DefaultFlowEntry(op.rule(), FlowEntry.FlowEntryState.ADDED));
                             flowRulesModify.add(op.rule());
                         default:
                             break;