Simplified Bmv2 device context service and context handling in demo apps

Change-Id: I2a13ed673902d0616732d43c841f50b1ad38cd4c
diff --git a/apps/bmv2-demo/common/src/main/java/org/onosproject/bmv2/demo/app/common/AbstractUpgradableFabricApp.java b/apps/bmv2-demo/common/src/main/java/org/onosproject/bmv2/demo/app/common/AbstractUpgradableFabricApp.java
index db37d82..4d940e6 100644
--- a/apps/bmv2-demo/common/src/main/java/org/onosproject/bmv2/demo/app/common/AbstractUpgradableFabricApp.java
+++ b/apps/bmv2-demo/common/src/main/java/org/onosproject/bmv2/demo/app/common/AbstractUpgradableFabricApp.java
@@ -56,9 +56,11 @@
 import org.slf4j.Logger;
 
 import java.util.Collection;
+import java.util.Collections;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.concurrent.ConcurrentMap;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 import java.util.concurrent.TimeUnit;
@@ -135,10 +137,13 @@
     private Set<DeviceId> spineSwitches;
 
     private Map<DeviceId, List<FlowRule>> deviceFlowRules;
-    private Map<DeviceId, Boolean> rulesInstalled;
+    private Map<DeviceId, Boolean> contextFlags;
+    private Map<DeviceId, Boolean> ruleFlags;
+
+    private ConcurrentMap<DeviceId, Boolean> deployLocks = Maps.newConcurrentMap();
 
     /**
-     * Creates a new Bmv2 Fabric Component.
+     * Creates a new BMv2 fabric app.
      *
      * @param appName           app name
      * @param configurationName a common name for the P4 program / BMv2 configuration used by this app
@@ -212,7 +217,8 @@
             leafSwitches = Sets.newHashSet();
             spineSwitches = Sets.newHashSet();
             deviceFlowRules = Maps.newConcurrentMap();
-            rulesInstalled = Maps.newConcurrentMap();
+            ruleFlags = Maps.newConcurrentMap();
+            contextFlags = Maps.newConcurrentMap();
         }
 
         // Start flow rules generator...
@@ -266,41 +272,19 @@
 
     private void deployRoutine() {
         if (otherAppFound && otherApp.appActive) {
-            log.info("Starting update routine...");
-            updateRoutine();
+            log.info("Deactivating other app...");
             appService.deactivate(otherApp.appId);
-        } else {
-            Stream.concat(leafSwitches.stream(), spineSwitches.stream())
-                    .map(deviceService::getDevice)
-                    .forEach(device -> spawnTask(() -> deployDevice(device)));
-        }
-    }
-
-    private void updateRoutine() {
-        Stream.concat(leafSwitches.stream(), spineSwitches.stream())
-                .forEach(did -> spawnTask(() -> {
-                    cleanUpDevice(did);
-                    try {
-                        Thread.sleep(CLEANUP_SLEEP);
-                    } catch (InterruptedException e) {
-                        log.warn("Cleanup sleep interrupted!");
-                        Thread.interrupted();
-                    }
-                    deployDevice(deviceService.getDevice(did));
-                }));
-    }
-
-    private void cleanUpDevice(DeviceId deviceId) {
-        List<FlowRule> flowRulesToRemove = Lists.newArrayList();
-        flowRuleService.getFlowEntries(deviceId).forEach(fe -> {
-            if (fe.appId() == otherApp.appId.id()) {
-                flowRulesToRemove.add(fe);
+            try {
+                Thread.sleep(CLEANUP_SLEEP);
+            } catch (InterruptedException e) {
+                log.warn("Cleanup sleep interrupted!");
+                Thread.interrupted();
             }
-        });
-        if (flowRulesToRemove.size() > 0) {
-            log.info("Cleaning {} old flow rules from {}...", flowRulesToRemove.size(), deviceId);
-            removeFlowRules(flowRulesToRemove);
         }
+
+        Stream.concat(leafSwitches.stream(), spineSwitches.stream())
+                .map(deviceService::getDevice)
+                .forEach(device -> spawnTask(() -> deployDevice(device)));
     }
 
     /**
@@ -309,36 +293,35 @@
      * @param device a device
      */
     public void deployDevice(Device device) {
-        // Serialize executions per device ID using a concurrent map.
-        rulesInstalled.compute(device.id(), (did, deployed) -> {
-            Bmv2DeviceContext deviceContext = bmv2ContextService.getContext(device.id());
-            if (deviceContext == null) {
-                log.error("Unable to get context for device {}", device.id());
-                return deployed;
-            } else if (!deviceContext.equals(bmv2Context)) {
-                log.info("Swapping configuration to {} on device {}...", configurationName, device.id());
-                bmv2ContextService.triggerConfigurationSwap(device.id(), bmv2Context);
-                return deployed;
+
+        DeviceId deviceId = device.id();
+
+        // Synchronize executions over the same device.
+        deployLocks.putIfAbsent(deviceId, new Boolean(true));
+        synchronized (deployLocks.get(deviceId)) {
+
+            // Set context if not already done.
+            if (!contextFlags.getOrDefault(deviceId, false)) {
+                log.info("Setting context to {} for {}...", configurationName, deviceId);
+                bmv2ContextService.setContext(deviceId, bmv2Context);
+                contextFlags.put(device.id(), true);
             }
 
-            List<FlowRule> rules = deviceFlowRules.get(device.id());
-            if (initDevice(device.id())) {
-                if (deployed == null && rules != null && rules.size() > 0) {
-                    log.info("Installing rules for {}...", did);
+            // Initialize device.
+            if (!initDevice(deviceId)) {
+                log.warn("Failed to initialize device {}", deviceId);
+            }
+
+            // Install rules.
+            if (!ruleFlags.getOrDefault(deviceId, false)) {
+                List<FlowRule> rules = deviceFlowRules.getOrDefault(deviceId, Collections.emptyList());
+                if (rules.size() > 0) {
+                    log.info("Installing rules for {}...", deviceId);
                     installFlowRules(rules);
-                    return true;
-                }
-            } else {
-                log.warn("Filed to initialize device {}", device.id());
-                if (deployed != null && rules != null && rules.size() > 0) {
-                    log.info("Removing rules for {}...", did);
-                    removeFlowRules(rules);
-                    return null;
+                    ruleFlags.put(deviceId, true);
                 }
             }
-
-            return deployed;
-        });
+        }
     }
 
     private void spawnTask(Runnable task) {