Device driver framework enhancements and CLI.

Change-Id: I5dea67620259797eff89a985718934034a86d63e
diff --git a/core/api/src/main/java/org/onosproject/net/driver/DefaultDriver.java b/core/api/src/main/java/org/onosproject/net/driver/DefaultDriver.java
index e95ddca..e7cd89e 100644
--- a/core/api/src/main/java/org/onosproject/net/driver/DefaultDriver.java
+++ b/core/api/src/main/java/org/onosproject/net/driver/DefaultDriver.java
@@ -69,15 +69,17 @@
      * @param other other driver
      * @return new driver
      */
-    DefaultDriver merge(DefaultDriver other) {
+    @Override
+    public Driver merge(Driver other) {
         // Merge the behaviours.
         ImmutableMap.Builder<Class<? extends Behaviour>, Class<? extends Behaviour>>
                 behaviours = ImmutableMap.builder();
-        behaviours.putAll(other.behaviours).putAll(this.behaviours);
+        behaviours.putAll(this.behaviours);
+        other.behaviours().forEach(b -> behaviours.put(b, other.implementation(b)));
 
         // Merge the properties.
         ImmutableMap.Builder<String, String> properties = ImmutableMap.builder();
-        properties.putAll(other.properties).putAll(this.properties);
+        properties.putAll(this.properties).putAll(other.properties());
 
         return new DefaultDriver(name, manufacturer, hwVersion, swVersion,
                                  behaviours.build(), properties.build());
@@ -109,6 +111,11 @@
     }
 
     @Override
+    public Class<? extends Behaviour> implementation(Class<? extends Behaviour> behaviour) {
+        return behaviours.get(behaviour);
+    }
+
+    @Override
     public boolean hasBehaviour(Class<? extends Behaviour> behaviourClass) {
         return behaviours.containsKey(behaviourClass);
     }
diff --git a/core/api/src/main/java/org/onosproject/net/driver/DefaultDriverProvider.java b/core/api/src/main/java/org/onosproject/net/driver/DefaultDriverProvider.java
index 3110dc8..b2b5281 100644
--- a/core/api/src/main/java/org/onosproject/net/driver/DefaultDriverProvider.java
+++ b/core/api/src/main/java/org/onosproject/net/driver/DefaultDriverProvider.java
@@ -16,8 +16,8 @@
 package org.onosproject.net.driver;
 
 import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Maps;
 
-import java.util.HashMap;
 import java.util.Map;
 import java.util.Set;
 
@@ -28,7 +28,7 @@
  */
 public class DefaultDriverProvider implements DriverProvider {
 
-    private final Map<String, DefaultDriver> drivers = new HashMap<>();
+    protected final Map<String, Driver> drivers = Maps.newConcurrentMap();
 
     @Override
     public Set<Driver> getDrivers() {
@@ -36,30 +36,47 @@
     }
 
     /**
-     * Adds the specified driver to be provided.
+     * Adds the specified drivers to the provider.
      *
-     * @param driverClasses driver to be provided
+     * @param drivers drivers to be added
      */
-    public void addDrivers(Set<DefaultDriver> driverClasses) {
-        for (DefaultDriver driverClass : driverClasses) {
-            addDriver(driverClass);
+    public void addDrivers(Set<Driver> drivers) {
+        drivers.forEach(this::addDriver);
+    }
+
+    /**
+     * Adds the specified driver to the provider.
+     *
+     * @param driver driver to be provided
+     */
+    public void addDriver(Driver driver) {
+        Driver ddc = drivers.get(driver.name());
+        if (ddc == null) {
+            // If we don't have the driver yet, just use the new one.
+            drivers.put(driver.name(), driver);
+        } else {
+            // Otherwise merge the existing driver with the new one and rebind.
+            drivers.put(driver.name(), ddc.merge(driver));
         }
     }
 
     /**
-     * Adds the specified driver to be provided.
+     * Removes the specified drivers from the provider.
      *
-     * @param driverClass driver to be provided
+     * @param drivers drivers to be removed
      */
-    public void addDriver(DefaultDriver driverClass) {
-        DefaultDriver ddc = drivers.get(driverClass.name());
-        if (ddc == null) {
-            // If we don't have the driver yet, just use the new one.
-            drivers.put(driverClass.name(), driverClass);
-        } else {
-            // Otherwise merge the existing driver with the new one and rebind.
-            drivers.put(driverClass.name(), ddc.merge(driverClass));
-        }
+    public void removeDrivers(Set<Driver> drivers) {
+        drivers.forEach(this::removeDriver);
+    }
+
+    /**
+     * Removes the specified driver from the provider.
+     *
+     * @param driver driver to be removed
+     */
+    public void removeDriver(Driver driver) {
+        // TODO: make selective if possible
+        drivers.remove(driver.name());
     }
 
     @Override
diff --git a/core/api/src/main/java/org/onosproject/net/driver/Driver.java b/core/api/src/main/java/org/onosproject/net/driver/Driver.java
index a6883d5..c8d6134 100644
--- a/core/api/src/main/java/org/onosproject/net/driver/Driver.java
+++ b/core/api/src/main/java/org/onosproject/net/driver/Driver.java
@@ -63,6 +63,14 @@
     Set<Class<? extends Behaviour>> behaviours();
 
     /**
+     * Returns the implementation class for the specified behaviour.
+     *
+     * @param behaviour behaviour interface
+     * @return implementation class
+     */
+    Class<? extends Behaviour> implementation(Class<? extends Behaviour> behaviour);
+
+    /**
      * Indicates whether or not the driver supports the specified class
      * of behaviour.
      *
@@ -90,4 +98,13 @@
      */
     Map<String, String> properties();
 
+    /**
+     * Merges the specified driver behaviours and properties into this one,
+     * giving preference to the other driver when dealing with conflicts.
+     *
+     * @param other other driver
+     * @return merged driver
+     */
+    Driver merge(Driver other);
+
 }
diff --git a/core/api/src/main/java/org/onosproject/net/driver/DriverService.java b/core/api/src/main/java/org/onosproject/net/driver/DriverService.java
index ffb7c93..fa37f1b 100644
--- a/core/api/src/main/java/org/onosproject/net/driver/DriverService.java
+++ b/core/api/src/main/java/org/onosproject/net/driver/DriverService.java
@@ -25,13 +25,19 @@
 public interface DriverService {
 
     /**
-     * Returns the overall set of drivers being provided, optionally
-     * filtered to only those that support all specified behaviours.
+     * Returns the overall set of drivers being provided.
      *
-     * @param withBehaviours optional behaviour classes to query by
      * @return provided drivers
      */
-    Set<Driver> getDrivers(Class<? extends Behaviour>... withBehaviours);
+    Set<Driver> getDrivers();
+
+    /**
+     * Returns the set of drivers which support the specified behaviour.
+     *
+     * @param withBehaviour behaviour class to query by
+     * @return provided drivers
+     */
+    Set<Driver> getDrivers(Class<? extends Behaviour> withBehaviour);
 
     /**
      * Returns the specified driver.