Refactored PI-ECMP app to use action profiles of basic.p4

Also removed obsolete ecmp.p4-related code.

Change-Id: Idaca90becfff5fc312de2530bf7924ccd502e076
diff --git a/apps/pi-demo/common/src/main/java/org/onosproject/pi/demo/app/common/AbstractUpgradableFabricApp.java b/apps/pi-demo/common/src/main/java/org/onosproject/pi/demo/app/common/AbstractUpgradableFabricApp.java
index 60c0e38..7c91bf3 100644
--- a/apps/pi-demo/common/src/main/java/org/onosproject/pi/demo/app/common/AbstractUpgradableFabricApp.java
+++ b/apps/pi-demo/common/src/main/java/org/onosproject/pi/demo/app/common/AbstractUpgradableFabricApp.java
@@ -16,7 +16,6 @@
 
 package org.onosproject.pi.demo.app.common;
 
-import com.google.common.base.MoreObjects;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;
@@ -43,6 +42,7 @@
 import org.onosproject.net.flow.FlowRule;
 import org.onosproject.net.flow.FlowRuleOperations;
 import org.onosproject.net.flow.FlowRuleService;
+import org.onosproject.net.group.GroupService;
 import org.onosproject.net.host.HostService;
 import org.onosproject.net.pi.model.PiPipeconf;
 import org.onosproject.net.pi.model.PiPipeconfId;
@@ -55,6 +55,7 @@
 import org.onosproject.net.topology.TopologyVertex;
 import org.slf4j.Logger;
 
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.List;
 import java.util.Map;
@@ -81,17 +82,19 @@
 import static org.slf4j.LoggerFactory.getLogger;
 
 /**
- * Abstract implementation of an app providing fabric connectivity for a 2-stage Clos topology of P4Runtime devices.
+ * Abstract implementation of an app providing fabric connectivity for a 2-stage
+ * Clos topology of P4Runtime devices.
  */
 @Component(immediate = true)
 public abstract class AbstractUpgradableFabricApp {
 
-    private static final Map<String, AbstractUpgradableFabricApp> APP_HANDLES = Maps.newConcurrentMap();
+    private static final Map<String, AbstractUpgradableFabricApp>
+            APP_HANDLES = Maps.newConcurrentMap();
 
     // TOPO_SIZE should be the same of the --size argument when running bmv2-demo.py
     private static final int TOPO_SIZE = 2;
     private static final boolean WITH_IMBALANCED_STRIPING = false;
-    protected static final int HASHED_LINKS = TOPO_SIZE + (WITH_IMBALANCED_STRIPING ? 1 : 0);
+    private static final int HASHED_LINKS = TOPO_SIZE + (WITH_IMBALANCED_STRIPING ? 1 : 0);
 
     private static final int FLOW_PRIORITY = 100;
     private static final int CHECK_TOPOLOGY_INTERVAL_SECONDS = 5;
@@ -122,6 +125,9 @@
     private FlowRuleService flowRuleService;
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected GroupService groupService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     private ApplicationAdminService appService;
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
@@ -137,7 +143,7 @@
     private AbstractUpgradableFabricApp otherApp;
 
     private boolean flowRuleGenerated = false;
-    private ApplicationId appId;
+    protected ApplicationId appId;
 
     private Collection<PiPipeconf> appPipeconfs;
 
@@ -156,7 +162,8 @@
      * @param appName      app name
      * @param appPipeconfs collection of compatible pipeconfs
      */
-    protected AbstractUpgradableFabricApp(String appName, Collection<PiPipeconf> appPipeconfs) {
+    protected AbstractUpgradableFabricApp(String appName,
+                                          Collection<PiPipeconf> appPipeconfs) {
         this.appName = checkNotNull(appName);
         this.appPipeconfs = checkNotNull(appPipeconfs);
         checkArgument(appPipeconfs.size() > 0, "appPipeconfs cannot have size 0");
@@ -171,11 +178,13 @@
 
         if (APP_HANDLES.size() > 0) {
             if (APP_HANDLES.size() > 1) {
-                throw new IllegalStateException("Found more than 1 active app handles");
+                throw new IllegalStateException(
+                        "Found more than 1 active app handles");
             }
             otherAppFound = true;
             otherApp = APP_HANDLES.values().iterator().next();
-            log.info("Found other fabric app active, signaling to freeze to {}...", otherApp.appName);
+            log.info("Found other fabric app active, signaling to freeze to {}...",
+                     otherApp.appName);
             otherApp.setAppFreezed(true);
         }
 
@@ -221,12 +230,12 @@
             pipeconfFlags = Maps.newConcurrentMap();
         }
 
-        /*
-        Schedules a thread that periodically checks the topology, as soon as it corresponds to the expected
-        one, it generates the necessary flow rules and starts the deploy process on each device.
-         */
-        scheduledExecutorService.scheduleAtFixedRate(this::checkTopologyAndGenerateFlowRules,
-                                                     0, CHECK_TOPOLOGY_INTERVAL_SECONDS, TimeUnit.SECONDS);
+        // Schedules a thread that periodically checks the topology, as soon as
+        // it corresponds to the expected one, it generates the necessary flow
+        // rules and starts the deploy process on each device.
+        scheduledExecutorService.scheduleAtFixedRate(
+                this::checkTopologyAndGenerateFlowRules,
+                0, CHECK_TOPOLOGY_INTERVAL_SECONDS, TimeUnit.SECONDS);
     }
 
     private void setAppFreezed(boolean appFreezed) {
@@ -239,7 +248,8 @@
     }
 
     /**
-     * Perform device initialization. Returns true if the operation was successful, false otherwise.
+     * Perform device initialization. Returns true if the operation was
+     * successful, false otherwise.
      *
      * @param deviceId a device id
      * @return a boolean value
@@ -247,8 +257,8 @@
     public abstract boolean initDevice(DeviceId deviceId);
 
     /**
-     * Generates a list of flow rules for the given leaf switch, source host, destination hosts, spine switches and
-     * topology.
+     * Generates a list of flow rules for the given leaf switch, source host,
+     * destination hosts, spine switches and topology.
      *
      * @param leaf     a leaf device id
      * @param srcHost  a source host
@@ -258,12 +268,15 @@
      * @return a list of flow rules
      * @throws FlowRuleGeneratorException if flow rules cannot be generated
      */
-    public abstract List<FlowRule> generateLeafRules(DeviceId leaf, Host srcHost, Collection<Host> dstHosts,
-                                                     Collection<DeviceId> spines, Topology topology)
+    public abstract List<FlowRule> generateLeafRules(DeviceId leaf, Host srcHost,
+                                                     Set<Host> dstHosts,
+                                                     Set<DeviceId> spines,
+                                                     Topology topology)
             throws FlowRuleGeneratorException;
 
     /**
-     * Generates a list of flow rules for the given spine switch, destination hosts and topology.
+     * Generates a list of flow rules for the given spine switch, destination
+     * hosts and topology.
      *
      * @param deviceId a spine device id
      * @param dstHosts a collection of destination hosts
@@ -271,7 +284,9 @@
      * @return a list of flow rules
      * @throws FlowRuleGeneratorException if flow rules cannot be generated
      */
-    public abstract List<FlowRule> generateSpineRules(DeviceId deviceId, Collection<Host> dstHosts, Topology topology)
+    public abstract List<FlowRule> generateSpineRules(DeviceId deviceId,
+                                                      Set<Host> dstHosts,
+                                                      Topology topology)
             throws FlowRuleGeneratorException;
 
     private void deployAllDevices() {
@@ -301,7 +316,7 @@
      *
      * @param device a device
      */
-    public void deployDevice(Device device) {
+    private void deployDevice(Device device) {
 
         DeviceId deviceId = device.id();
 
@@ -317,7 +332,7 @@
                     pipeconfFlags.put(device.id(), true);
                 } else {
                     log.warn("Wrong pipeconf for {}, expecting {}, but found {}, aborting deploy",
-                             deviceId, MoreObjects.toStringHelper(appPipeconfs),
+                             deviceId, Arrays.toString(appPipeconfs.toArray()),
                              piPipeconfService.ofDevice(deviceId).get());
                     return;
                 }
@@ -331,7 +346,8 @@
             // Install rules.
             if (!ruleFlags.getOrDefault(deviceId, false) &&
                     deviceFlowRules.containsKey(deviceId)) {
-                log.info("Installing {} rules for {}...", deviceFlowRules.get(deviceId).size(), deviceId);
+                log.info("Installing {} rules for {}...",
+                         deviceFlowRules.get(deviceId).size(), deviceId);
                 installFlowRules(deviceFlowRules.get(deviceId));
                 ruleFlags.put(deviceId, true);
             }
@@ -352,7 +368,8 @@
     }
 
     /**
-     * Generates flow rules to provide host-to-host connectivity for the given topology and hosts.
+     * Generates flow rules to provide host-to-host connectivity for the given
+     * topology and hosts.
      */
     private synchronized void checkTopologyAndGenerateFlowRules() {
 
@@ -374,7 +391,7 @@
                 .forEach(did -> (isSpine(did, topo) ? spines : leafs).add(did));
 
         if (spines.size() != TOPO_SIZE || leafs.size() != TOPO_SIZE) {
-            log.info("Invalid leaf/spine switches count, aborting... > leafCount={}, spineCount={}",
+            log.info("Invalid leaf/spine count, aborting... > leafCount={}, spineCount={}",
                      spines.size(), leafs.size());
             return;
         }
@@ -383,7 +400,8 @@
             int portCount = deviceService.getPorts(did).size();
             // Expected port count: num leafs + 1 redundant leaf link (if imbalanced)
             if (portCount != HASHED_LINKS) {
-                log.info("Invalid port count for spine, aborting... > deviceId={}, portCount={}", did, portCount);
+                log.info("Invalid port count for spine, aborting... > deviceId={}, portCount={}",
+                         did, portCount);
                 return;
             }
         }
@@ -391,7 +409,8 @@
             int portCount = deviceService.getPorts(did).size();
             // Expected port count: num spines + host port + 1 redundant spine link
             if (portCount != HASHED_LINKS + 1) {
-                log.info("Invalid port count for leaf, aborting... > deviceId={}, portCount={}", did, portCount);
+                log.info("Invalid port count for leaf, aborting... > deviceId={}, portCount={}",
+                         did, portCount);
                 return;
             }
         }
@@ -400,7 +419,8 @@
         Map<DeviceId, Host> hostMap = Maps.newHashMap();
         hosts.forEach(h -> hostMap.put(h.location().deviceId(), h));
         if (hosts.size() != TOPO_SIZE || !leafs.equals(hostMap.keySet())) {
-            log.info("Wrong host configuration, aborting... > hostCount={}, hostMapz={}", hosts.size(), hostMap);
+            log.info("Wrong host configuration, aborting... > hostCount={}, hostMapz={}",
+                     hosts.size(), hostMap);
             return;
         }
 
@@ -409,14 +429,18 @@
         try {
             for (DeviceId deviceId : leafs) {
                 Host srcHost = hostMap.get(deviceId);
-                Set<Host> dstHosts = hosts.stream().filter(h -> h != srcHost).collect(toSet());
-                newFlowRules.addAll(generateLeafRules(deviceId, srcHost, dstHosts, spines, topo));
+                Set<Host> dstHosts = hosts.stream()
+                        .filter(h -> h != srcHost)
+                        .collect(toSet());
+                newFlowRules.addAll(generateLeafRules(deviceId, srcHost,
+                                                      dstHosts, spines, topo));
             }
             for (DeviceId deviceId : spines) {
                 newFlowRules.addAll(generateSpineRules(deviceId, hosts, topo));
             }
         } catch (FlowRuleGeneratorException e) {
-            log.warn("Exception while executing flow rule generator: {}", e.getMessage());
+            log.warn("Exception while executing flow rule generator: {}",
+                     e.getMessage());
             return;
         }
 
@@ -428,12 +452,13 @@
 
         // All good!
         // Divide flow rules per device id...
-        ImmutableMap.Builder<DeviceId, List<FlowRule>> mapBuilder = ImmutableMap.builder();
+        ImmutableMap.Builder<DeviceId, List<FlowRule>> mapBuilder =
+                ImmutableMap.builder();
         concat(spines.stream(), leafs.stream())
-                .map(deviceId -> ImmutableList.copyOf(newFlowRules
-                                                              .stream()
-                                                              .filter(fr -> fr.deviceId().equals(deviceId))
-                                                              .iterator()))
+                .map(deviceId -> ImmutableList.copyOf(
+                        newFlowRules.stream()
+                                .filter(fr -> fr.deviceId().equals(deviceId))
+                                .iterator()))
                 .forEach(frs -> mapBuilder.put(frs.get(0).deviceId(), frs));
         this.deviceFlowRules = mapBuilder.build();
 
@@ -443,7 +468,8 @@
         // Avoid other executions to modify the generated flow rules.
         flowRuleGenerated = true;
 
-        log.info("Generated {} flow rules for {} devices", newFlowRules.size(), spines.size() + leafs.size());
+        log.info("Generated {} flow rules for {} devices",
+                 newFlowRules.size(), spines.size() + leafs.size());
 
         spawnTask(this::deployAllDevices);
     }
@@ -455,11 +481,13 @@
      * @param tableId a table id
      * @return a new flow rule builder
      */
-    protected FlowRule.Builder flowRuleBuilder(DeviceId did, PiTableId tableId) throws FlowRuleGeneratorException {
+    protected FlowRule.Builder flowRuleBuilder(DeviceId did, PiTableId tableId)
+            throws FlowRuleGeneratorException {
 
         final Device device = deviceService.getDevice(did);
         if (!device.is(PiPipelineInterpreter.class)) {
-            throw new FlowRuleGeneratorException(format("Device %s has no PiPipelineInterpreter", did));
+            throw new FlowRuleGeneratorException(format(
+                    "Device %s has no PiPipelineInterpreter", did));
         }
 
         return DefaultFlowRule.builder()
@@ -486,12 +514,13 @@
 
     protected boolean isFabricPort(Port port, Topology topology) {
         // True if the port connects this device to another infrastructure device.
-        return topologyService.isInfrastructure(topology, new ConnectPoint(port.element().id(), port.number()));
+        return topologyService.isInfrastructure(
+                topology, new ConnectPoint(port.element().id(), port.number()));
     }
 
     /**
-     * A listener of device events that executes a device deploy task each time a device is added, updated or
-     * re-connects.
+     * A listener of device events that executes a device deploy task each time
+     * a device is added, updated or re-connects.
      */
     private class InternalDeviceListener implements DeviceListener {
         @Override
@@ -512,12 +541,12 @@
     /**
      * An exception occurred while generating flow rules for this fabric.
      */
-    public class FlowRuleGeneratorException extends Exception {
+    public static class FlowRuleGeneratorException extends Exception {
 
         public FlowRuleGeneratorException() {
         }
 
-        public FlowRuleGeneratorException(String msg) {
+        FlowRuleGeneratorException(String msg) {
             super(msg);
         }
     }