ONOS-6031 Fixing class loading problem when adding FullMeatersAvailable to corsa-v39 driver

Change-Id: I7c89f8bb85942f4a6e04034be010416752e2924e
diff --git a/cli/src/main/java/org/onosproject/cli/net/DriversListCommand.java b/cli/src/main/java/org/onosproject/cli/net/DriversListCommand.java
index d18a2db..b4b5046 100644
--- a/cli/src/main/java/org/onosproject/cli/net/DriversListCommand.java
+++ b/cli/src/main/java/org/onosproject/cli/net/DriversListCommand.java
@@ -15,15 +15,18 @@
  */
 package org.onosproject.cli.net;
 
-import java.util.Set;
-
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.google.common.collect.ImmutableList;
 import org.apache.karaf.shell.commands.Argument;
 import org.apache.karaf.shell.commands.Command;
 import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.net.driver.Behaviour;
 import org.onosproject.net.driver.Driver;
 import org.onosproject.net.driver.DriverAdminService;
-
-import com.fasterxml.jackson.databind.node.ArrayNode;
+import java.util.List;
+import java.util.Optional;
+import java.util.Set;
+import java.util.stream.Collectors;
 
 /**
  * Lists device drivers.
@@ -45,12 +48,12 @@
         DriverAdminService service = get(DriverAdminService.class);
 
         if (driverName != null) {
-            printDriver(service.getDriver(driverName));
+            printDriver(service.getDriver(driverName), true);
         } else {
             if (outputJson()) {
                 json(service.getDrivers());
             } else {
-                service.getDrivers().forEach(this::printDriver);
+                service.getDrivers().forEach(d -> printDriver(d, true));
             }
         }
     }
@@ -65,24 +68,34 @@
         print("%s", result.toString());
     }
 
-    private void printDriver(Driver driver) {
+    private void printDriver(Driver driver, boolean first) {
         if (outputJson()) {
             json(driver);
-        } else if (driver.parents() != null) {
-            driver.parents().forEach(parent -> {
-                print(FMT, driver.name(), parent != null ? parent.name() : "none",
-                           driver.manufacturer(), driver.hwVersion(), driver.swVersion());
-                driver.behaviours().forEach(b -> print(FMT_B, b.getCanonicalName(),
-                                                       driver.implementation(b).getCanonicalName()));
-                driver.properties().forEach((k, v) -> print(FMT_P, k, v));
-            });
-        } else if (driver.parents() == null) {
-            print(FMT, driver.name(), "none", driver.manufacturer(),
-                    driver.hwVersion(), driver.swVersion());
-            driver.behaviours().forEach(b -> print(FMT_B, b.getCanonicalName(),
-                    driver.implementation(b).getCanonicalName()));
+        } else {
+
+            List<Driver> parents = Optional.ofNullable(driver.parents())
+                    .orElse(ImmutableList.of());
+
+            List<String> parentsNames = parents.stream()
+                    .map(Driver::name).collect(Collectors.toList());
+
+            if (first) {
+                print(FMT, driver.name(), parentsNames,
+                      driver.manufacturer(), driver.hwVersion(), driver.swVersion());
+            } else {
+                print("   Inherited from %s", driver.name());
+            }
+
+            driver.behaviours().forEach(b -> printBehaviour(b, driver));
+            //recursion call to print each parent
+            parents.stream().forEach(parent -> printDriver(parent, false));
             driver.properties().forEach((k, v) -> print(FMT_P, k, v));
         }
     }
 
+    private void printBehaviour(Class<? extends Behaviour> behaviour, Driver driver) {
+        print(FMT_B, behaviour.getCanonicalName(),
+              driver.implementation(behaviour).getCanonicalName());
+    }
+
 }
diff --git a/drivers/corsa/src/main/resources/corsa-drivers.xml b/drivers/corsa/src/main/resources/corsa-drivers.xml
index 93f4858..377a30e 100644
--- a/drivers/corsa/src/main/resources/corsa-drivers.xml
+++ b/drivers/corsa/src/main/resources/corsa-drivers.xml
@@ -41,7 +41,7 @@
         <behaviour api="org.onosproject.openflow.controller.driver.OpenFlowSwitchDriver"
                    impl="org.onosproject.drivers.corsa.CorsaSwitchHandshaker"/>
     </driver>
-    <driver name="corsa-v39"
+    <driver name="corsa-v39" extends="abstract"
             manufacturer="Corsa" hwVersion="CDP6420-A00" swVersion="corsa-ovs-datapath 1.4.97">
         <behaviour api="org.onosproject.net.behaviour.Pipeliner"
                    impl="org.onosproject.drivers.corsa.CorsaPipelineV39"/>
diff --git a/drivers/default/src/main/resources/onos-drivers.xml b/drivers/default/src/main/resources/onos-drivers.xml
index c9411b9..c1842db 100644
--- a/drivers/default/src/main/resources/onos-drivers.xml
+++ b/drivers/default/src/main/resources/onos-drivers.xml
@@ -230,5 +230,17 @@
         <behaviour api="org.onosproject.net.behaviour.Pipeliner"
                    impl="org.onosproject.driver.pipeline.HpPipeline"/>
     </driver>
+    <!-- The abstract driver is meant as a base driver containing classes that are
+       ~ present in the default drivers module. These classes are needed by other
+       ~ drivers but not loaded by any of the base ones.
+       ~ The abstract driver is NOT meant to be used by itself with any device.
+       ~ Policies will be put in place in the DriverManager so that this driver
+       ~ is not assigned to any device from the southbound or the net-cfg.
+    -->
+    <driver name="abstract"
+            manufacturer="abstract" hwVersion="abstract" swVersion="abstract">
+        <behaviour api="org.onosproject.net.behaviour.MeterQuery"
+                   impl="org.onosproject.driver.query.FullMetersAvailable"/>
+    </driver>
 </drivers>