Adding device driver inheritance mechanism.

Change-Id: I9c883d32ce0c39f961eddd5c4624dc23f794fe4d
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 fd4c96c..2450390 100644
--- a/cli/src/main/java/org/onosproject/cli/net/DriversListCommand.java
+++ b/cli/src/main/java/org/onosproject/cli/net/DriversListCommand.java
@@ -28,7 +28,7 @@
         description = "Lists device drivers")
 public class DriversListCommand extends AbstractShellCommand {
 
-    private static final String FMT = "driver=%s, mfr=%s, hw=%s, sw=%s";
+    private static final String FMT = "driver=%s, extends=%s, mfr=%s, hw=%s, sw=%s";
     private static final String FMT_B = "   %s via %s";
     private static final String FMT_P = "   %s=%s";
 
@@ -48,8 +48,9 @@
     }
 
     private void printDriver(Driver driver) {
-        print(FMT, driver.name(), driver.manufacturer(),
-              driver.hwVersion(), driver.swVersion());
+        Driver parent = driver.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));
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 84da212..5c6a08b 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
@@ -19,6 +19,7 @@
 import com.google.common.collect.Maps;
 
 import java.util.Map;
+import java.util.Objects;
 import java.util.Set;
 
 import static com.google.common.base.MoreObjects.toStringHelper;
@@ -32,6 +33,7 @@
 public class DefaultDriver implements Driver {
 
     private final String name;
+    private final Driver parent;
 
     private final String manufacturer;
     private final String hwVersion;
@@ -40,22 +42,23 @@
     private final Map<Class<? extends Behaviour>, Class<? extends Behaviour>> behaviours;
     private final Map<String, String> properties;
 
-
     /**
      * Creates a driver with the specified name.
      *
      * @param name         driver name
+     * @param parent       optional parent driver
      * @param manufacturer device manufacturer
      * @param hwVersion    device hardware version
      * @param swVersion    device software version
      * @param behaviours   device behaviour classes
      * @param properties   properties for configuration of device behaviour classes
      */
-    public DefaultDriver(String name, String manufacturer,
+    public DefaultDriver(String name, Driver parent, String manufacturer,
                          String hwVersion, String swVersion,
                          Map<Class<? extends Behaviour>, Class<? extends Behaviour>> behaviours,
                          Map<String, String> properties) {
         this.name = checkNotNull(name, "Name cannot be null");
+        this.parent = parent;
         this.manufacturer = checkNotNull(manufacturer, "Manufacturer cannot be null");
         this.hwVersion = checkNotNull(hwVersion, "HW version cannot be null");
         this.swVersion = checkNotNull(swVersion, "SW version cannot be null");
@@ -65,6 +68,9 @@
 
     @Override
     public Driver merge(Driver other) {
+        checkArgument(parent == null || Objects.equals(parent, other.parent()),
+                      "Parent drivers are not the same");
+
         // Merge the behaviours.
         Map<Class<? extends Behaviour>, Class<? extends Behaviour>>
                 behaviours = Maps.newHashMap();
@@ -75,7 +81,7 @@
         ImmutableMap.Builder<String, String> properties = ImmutableMap.builder();
         properties.putAll(this.properties).putAll(other.properties());
 
-        return new DefaultDriver(name, manufacturer, hwVersion, swVersion,
+        return new DefaultDriver(name, other.parent(), manufacturer, hwVersion, swVersion,
                                  ImmutableMap.copyOf(behaviours), properties.build());
     }
 
@@ -100,6 +106,11 @@
     }
 
     @Override
+    public Driver parent() {
+        return parent;
+    }
+
+    @Override
     public Set<Class<? extends Behaviour>> behaviours() {
         return behaviours.keySet();
     }
@@ -111,19 +122,32 @@
 
     @Override
     public boolean hasBehaviour(Class<? extends Behaviour> behaviourClass) {
-        return behaviours.containsKey(behaviourClass);
+        return behaviours.containsKey(behaviourClass) ||
+                (parent != null && parent.hasBehaviour(behaviourClass));
     }
 
     @Override
     public <T extends Behaviour> T createBehaviour(DriverData data,
                                                    Class<T> behaviourClass) {
-        return createBehaviour(data, null, behaviourClass);
+        T behaviour = createBehaviour(data, null, behaviourClass);
+        if (behaviour != null) {
+            return behaviour;
+        } else if (parent != null) {
+            return parent.createBehaviour(data, behaviourClass);
+        }
+        throw new IllegalArgumentException(behaviourClass.getName() + " not supported");
     }
 
     @Override
     public <T extends Behaviour> T createBehaviour(DriverHandler handler,
                                                    Class<T> behaviourClass) {
-        return createBehaviour(handler.data(), handler, behaviourClass);
+        T behaviour = createBehaviour(handler.data(), handler, behaviourClass);
+        if (behaviour != null) {
+            return behaviour;
+        } else if (parent != null) {
+            return parent.createBehaviour(handler, behaviourClass);
+        }
+        throw new IllegalArgumentException(behaviourClass.getName() + " not supported");
     }
 
     // Creates an instance of behaviour primed with the specified driver data.
@@ -134,17 +158,18 @@
 
         // Locate the implementation of the requested behaviour.
         Class<? extends Behaviour> implementation = behaviours.get(behaviourClass);
-        checkArgument(implementation != null, "{} not supported", behaviourClass.getName());
+        if (implementation != null) {
+            // Create an instance of the behaviour and apply data as its context.
+            T behaviour = createBehaviour(behaviourClass, implementation);
+            behaviour.setData(data);
 
-        // Create an instance of the behaviour and apply data as its context.
-        T behaviour = createBehaviour(behaviourClass, implementation);
-        behaviour.setData(data);
-
-        // If this is a handler behaviour, also apply handler as its context.
-        if (handler != null) {
-            ((HandlerBehaviour) behaviour).setHandler(handler);
+            // If this is a handler behaviour, also apply handler as its context.
+            if (handler != null) {
+                ((HandlerBehaviour) behaviour).setHandler(handler);
+            }
+            return behaviour;
         }
-        return behaviour;
+        return null;
     }
 
     @SuppressWarnings("unchecked")
@@ -177,6 +202,7 @@
     public String toString() {
         return toStringHelper(this)
                 .add("name", name)
+                .add("parent", parent)
                 .add("manufacturer", manufacturer)
                 .add("hwVersion", hwVersion)
                 .add("swVersion", swVersion)
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 8c13f36..50611b1 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
@@ -35,6 +35,14 @@
     String name();
 
     /**
+     * Returns the parent driver from which this driver inherits behaviours
+     * and properties.
+     *
+     * @return parent driver; null if driver has no parent
+     */
+    Driver parent();
+
+    /**
      * Returns the device manufacturer name.
      *
      * @return manufacturer name
@@ -57,6 +65,7 @@
 
     /**
      * Returns the set of behaviours supported by this driver.
+     * It reflects behaviours of only this driver and not its parent.
      *
      * @return set of device driver behaviours
      */
@@ -64,6 +73,7 @@
 
     /**
      * Returns the implementation class for the specified behaviour.
+     * It reflects behaviours of only this driver and not its parent.
      *
      * @param behaviour behaviour interface
      * @return implementation class
@@ -71,8 +81,8 @@
     Class<? extends Behaviour> implementation(Class<? extends Behaviour> behaviour);
 
     /**
-     * Indicates whether or not the driver supports the specified class
-     * of behaviour.
+     * Indicates whether or not the driver, or any of its parents, support
+     * the specified class of behaviour. It
      *
      * @param behaviourClass behaviour class
      * @return true if behaviour is supported
@@ -81,6 +91,8 @@
 
     /**
      * Creates an instance of behaviour primed with the specified driver data.
+     * If the current driver does not support the specified behaviour and the
+     * driver has parent, the request is delegated to the parent driver.
      *
      * @param data           driver data context
      * @param behaviourClass driver behaviour class
@@ -91,6 +103,8 @@
 
     /**
      * Creates an instance of behaviour primed with the specified driver data.
+     * If the current driver does not support the specified behaviour and the
+     * driver has parent, the request is delegated to the parent driver.
      *
      * @param handler        driver handler context
      * @param behaviourClass driver behaviour class
diff --git a/core/api/src/main/java/org/onosproject/net/driver/DriverResolver.java b/core/api/src/main/java/org/onosproject/net/driver/DriverResolver.java
new file mode 100644
index 0000000..094c710
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/driver/DriverResolver.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.net.driver;
+
+/**
+ * Entity capable of resolving a driver using its name.
+ */
+public interface DriverResolver {
+
+    /**
+     * Returns the specified driver.
+     *
+     * @param driverName driver name
+     * @return driver
+     * @throws org.onlab.util.ItemNotFoundException if driver with the given
+     *                                              name is not found
+     */
+    Driver getDriver(String driverName);
+
+}
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 fa37f1b..1a74255 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
@@ -22,7 +22,7 @@
 /**
  * Service for obtaining drivers and driver behaviour implementations.
  */
-public interface DriverService {
+public interface DriverService extends DriverResolver {
 
     /**
      * Returns the overall set of drivers being provided.
@@ -40,16 +40,6 @@
     Set<Driver> getDrivers(Class<? extends Behaviour> withBehaviour);
 
     /**
-     * Returns the specified driver.
-     *
-     * @param driverName driver name
-     * @return driver
-     * @throws org.onlab.util.ItemNotFoundException if driver with the given
-     *                                              name is not found
-     */
-    Driver getDriver(String driverName);
-
-    /**
      * Returns the driver that matches the specified primordial device
      * discovery information.
      *
diff --git a/core/api/src/main/java/org/onosproject/net/driver/XmlDriverLoader.java b/core/api/src/main/java/org/onosproject/net/driver/XmlDriverLoader.java
index c3bb7ac..fc5e04a 100644
--- a/core/api/src/main/java/org/onosproject/net/driver/XmlDriverLoader.java
+++ b/core/api/src/main/java/org/onosproject/net/driver/XmlDriverLoader.java
@@ -16,6 +16,7 @@
 package org.onosproject.net.driver;
 
 import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Maps;
 import org.apache.commons.configuration.ConfigurationException;
 import org.apache.commons.configuration.HierarchicalConfiguration;
 import org.apache.commons.configuration.XMLConfiguration;
@@ -51,6 +52,7 @@
     private static final String PROPERTY = "property";
 
     private static final String NAME = "[@name]";
+    private static final String EXTENDS = "[@extends]";
     private static final String MFG = "[@manufacturer]";
     private static final String HW = "[@hwVersion]";
     private static final String SW = "[@swVersion]";
@@ -59,6 +61,8 @@
 
     private final ClassLoader classLoader;
 
+    private Map<String, Driver> drivers = Maps.newHashMap();
+
     /**
      * Creates a new driver loader capable of loading drivers from the supplied
      * class loader.
@@ -74,18 +78,20 @@
      * produce a ready-to-register driver provider.
      *
      * @param driversStream stream containing the drivers definitions
+     * @param resolver      driver resolver
      * @return driver provider
      * @throws java.io.IOException if issues are encountered reading the stream
      *                             or parsing the driver definitions within
      */
-    public DefaultDriverProvider loadDrivers(InputStream driversStream) throws IOException {
+    public DefaultDriverProvider loadDrivers(InputStream driversStream,
+                                             DriverResolver resolver) throws IOException {
         try {
             XMLConfiguration cfg = new XMLConfiguration();
             cfg.setRootElementName(DRIVERS);
             cfg.setAttributeSplittingDisabled(true);
 
             cfg.load(driversStream);
-            return loadDrivers(cfg);
+            return loadDrivers(cfg, resolver);
         } catch (ConfigurationException e) {
             throw new IOException("Unable to load drivers", e);
         }
@@ -95,13 +101,18 @@
      * Loads a driver provider from the supplied hierarchical configuration.
      *
      * @param driversCfg hierarchical configuration containing the drivers definitions
+     * @param resolver   driver resolver
      * @return driver provider
      */
-    public DefaultDriverProvider loadDrivers(HierarchicalConfiguration driversCfg) {
+    public DefaultDriverProvider loadDrivers(HierarchicalConfiguration driversCfg,
+                                             DriverResolver resolver) {
         DefaultDriverProvider provider = new DefaultDriverProvider();
         for (HierarchicalConfiguration cfg : driversCfg.configurationsAt(DRIVER)) {
-            provider.addDriver(loadDriver(cfg));
+            DefaultDriver driver = loadDriver(cfg, resolver);
+            drivers.put(driver.name(), driver);
+            provider.addDriver(driver);
         }
+        drivers.clear();
         return provider;
     }
 
@@ -109,19 +120,30 @@
      * Loads a driver from the supplied hierarchical configuration.
      *
      * @param driverCfg hierarchical configuration containing the driver definition
+     * @param resolver  driver resolver
      * @return driver
      */
-    public DefaultDriver loadDriver(HierarchicalConfiguration driverCfg) {
+    public DefaultDriver loadDriver(HierarchicalConfiguration driverCfg,
+                                    DriverResolver resolver) {
         String name = driverCfg.getString(NAME);
+        String parentName = driverCfg.getString(EXTENDS);
         String manufacturer = driverCfg.getString(MFG, "");
         String hwVersion = driverCfg.getString(HW, "");
         String swVersion = driverCfg.getString(SW, "");
 
-        return new DefaultDriver(name, manufacturer, hwVersion, swVersion,
+        Driver parent = parentName != null ? resolve(parentName, resolver) : null;
+        return new DefaultDriver(name, parent, manufacturer, hwVersion, swVersion,
                                  parseBehaviours(driverCfg),
                                  parseProperties(driverCfg));
     }
 
+    // Resolves the driver by name locally at first and then using the specified resolver.
+    private Driver resolve(String parentName, DriverResolver resolver) {
+        Driver driver = drivers.get(parentName);
+        return driver != null ? driver :
+                (resolver != null ? resolver.getDriver(parentName) : null);
+    }
+
     // Parses the behaviours section.
     private Map<Class<? extends Behaviour>, Class<? extends Behaviour>>
     parseBehaviours(HierarchicalConfiguration driverCfg) {
diff --git a/core/api/src/test/java/org/onosproject/net/driver/DefaultDriverDataTest.java b/core/api/src/test/java/org/onosproject/net/driver/DefaultDriverDataTest.java
index bf4ad52..006957d 100644
--- a/core/api/src/test/java/org/onosproject/net/driver/DefaultDriverDataTest.java
+++ b/core/api/src/test/java/org/onosproject/net/driver/DefaultDriverDataTest.java
@@ -28,7 +28,7 @@
 
     @Before
     public void setUp() {
-        ddc = new DefaultDriver("foo.bar", "Circus", "lux", "1.2a",
+        ddc = new DefaultDriver("foo.bar", null, "Circus", "lux", "1.2a",
                                 ImmutableMap.of(TestBehaviour.class,
                                                 TestBehaviourImpl.class),
                                 ImmutableMap.of("foo", "bar"));
diff --git a/core/api/src/test/java/org/onosproject/net/driver/DefaultDriverHandlerTest.java b/core/api/src/test/java/org/onosproject/net/driver/DefaultDriverHandlerTest.java
index e9a6165..08a508c 100644
--- a/core/api/src/test/java/org/onosproject/net/driver/DefaultDriverHandlerTest.java
+++ b/core/api/src/test/java/org/onosproject/net/driver/DefaultDriverHandlerTest.java
@@ -30,7 +30,7 @@
 
     @Before
     public void setUp() {
-        ddc = new DefaultDriver("foo.bar", "Circus", "lux", "1.2a",
+        ddc = new DefaultDriver("foo.bar", null, "Circus", "lux", "1.2a",
                                 ImmutableMap.of(TestBehaviour.class,
                                                 TestBehaviourImpl.class,
                                                 TestBehaviourTwo.class,
diff --git a/core/api/src/test/java/org/onosproject/net/driver/DefaultDriverProviderTest.java b/core/api/src/test/java/org/onosproject/net/driver/DefaultDriverProviderTest.java
index adfa486..4568fd9 100644
--- a/core/api/src/test/java/org/onosproject/net/driver/DefaultDriverProviderTest.java
+++ b/core/api/src/test/java/org/onosproject/net/driver/DefaultDriverProviderTest.java
@@ -28,15 +28,15 @@
     @Test
     public void basics() {
         DefaultDriverProvider ddp = new DefaultDriverProvider();
-        DefaultDriver one = new DefaultDriver("foo.bar", "Circus", "lux", "1.2a",
+        DefaultDriver one = new DefaultDriver("foo.bar", null, "Circus", "lux", "1.2a",
                                               ImmutableMap.of(TestBehaviour.class,
                                                               TestBehaviourImpl.class),
                                               ImmutableMap.of("foo", "bar"));
-        DefaultDriver two = new DefaultDriver("foo.bar", "", "", "",
+        DefaultDriver two = new DefaultDriver("foo.bar", null, "", "", "",
                                               ImmutableMap.of(TestBehaviourTwo.class,
                                                               TestBehaviourTwoImpl.class),
                                               ImmutableMap.of("goo", "wee"));
-        DefaultDriver three = new DefaultDriver("goo.foo", "BigTop", "better", "2.2",
+        DefaultDriver three = new DefaultDriver("goo.foo", null, "BigTop", "better", "2.2",
                                                 ImmutableMap.of(TestBehaviourTwo.class,
                                                                 TestBehaviourTwoImpl.class),
                                                 ImmutableMap.of("goo", "gee"));
diff --git a/core/api/src/test/java/org/onosproject/net/driver/DefaultDriverTest.java b/core/api/src/test/java/org/onosproject/net/driver/DefaultDriverTest.java
index 204eb3b..17af6c7 100644
--- a/core/api/src/test/java/org/onosproject/net/driver/DefaultDriverTest.java
+++ b/core/api/src/test/java/org/onosproject/net/driver/DefaultDriverTest.java
@@ -25,18 +25,33 @@
 
     @Test
     public void basics() {
-        DefaultDriver ddc = new DefaultDriver("foo.bar", "Circus", "lux", "1.2a",
+        DefaultDriver ddp = new DefaultDriver("foo.base", null, "Circus", "lux", "1.2a",
                                               ImmutableMap.of(TestBehaviour.class,
-                                                              TestBehaviourImpl.class),
+                                                              TestBehaviourImpl.class,
+                                                              TestBehaviourTwo.class,
+                                                              TestBehaviourTwoImpl.class),
+                                              ImmutableMap.of("foo", "bar"));
+
+        DefaultDriver ddc = new DefaultDriver("foo.bar", ddp, "Circus", "lux", "1.2a",
+                                              ImmutableMap.of(),
                                               ImmutableMap.of("foo", "bar"));
         assertEquals("incorrect name", "foo.bar", ddc.name());
+        assertEquals("incorrect parent", ddp, ddc.parent());
         assertEquals("incorrect mfr", "Circus", ddc.manufacturer());
         assertEquals("incorrect hw", "lux", ddc.hwVersion());
         assertEquals("incorrect sw", "1.2a", ddc.swVersion());
 
-        assertEquals("incorrect behaviour count", 1, ddc.behaviours().size());
+        assertEquals("incorrect behaviour count", 2, ddp.behaviours().size());
+        assertEquals("incorrect behaviour count", 0, ddc.behaviours().size());
         assertTrue("incorrect behaviour", ddc.hasBehaviour(TestBehaviour.class));
 
+        Behaviour b1 = ddc.createBehaviour(new DefaultDriverData(ddc), TestBehaviour.class);
+        assertTrue("incorrect behaviour class", b1 instanceof TestBehaviourImpl);
+
+        Behaviour b2 = ddc.createBehaviour(new DefaultDriverHandler(new DefaultDriverData(ddc)),
+                                           TestBehaviourTwo.class);
+        assertTrue("incorrect behaviour class", b2 instanceof TestBehaviourTwoImpl);
+
         assertEquals("incorrect property count", 1, ddc.properties().size());
         assertEquals("incorrect key count", 1, ddc.keys().size());
         assertEquals("incorrect property", "bar", ddc.value("foo"));
@@ -46,12 +61,12 @@
 
     @Test
     public void merge() {
-        DefaultDriver one = new DefaultDriver("foo.bar", "Circus", "lux", "1.2a",
+        DefaultDriver one = new DefaultDriver("foo.bar", null, "Circus", "lux", "1.2a",
                                               ImmutableMap.of(TestBehaviour.class,
                                                               TestBehaviourImpl.class),
                                               ImmutableMap.of("foo", "bar"));
         Driver ddc =
-                one.merge(new DefaultDriver("foo.bar", "", "", "",
+                one.merge(new DefaultDriver("foo.bar", null, "", "", "",
                                             ImmutableMap.of(TestBehaviourTwo.class,
                                                             TestBehaviourTwoImpl.class),
                                             ImmutableMap.of("goo", "wee")));
diff --git a/core/api/src/test/java/org/onosproject/net/driver/XmlDriverLoaderTest.java b/core/api/src/test/java/org/onosproject/net/driver/XmlDriverLoaderTest.java
index 0d5dc6f..ea77a50 100644
--- a/core/api/src/test/java/org/onosproject/net/driver/XmlDriverLoaderTest.java
+++ b/core/api/src/test/java/org/onosproject/net/driver/XmlDriverLoaderTest.java
@@ -19,6 +19,7 @@
 
 import java.io.IOException;
 import java.io.InputStream;
+import java.util.Iterator;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
@@ -32,17 +33,22 @@
     public void basics() throws IOException {
         XmlDriverLoader loader = new XmlDriverLoader(getClass().getClassLoader());
         InputStream stream = getClass().getResourceAsStream("drivers.1.xml");
-        DriverProvider provider = loader.loadDrivers(stream);
+        DriverProvider provider = loader.loadDrivers(stream, null);
         System.out.println(provider);
-        assertEquals("incorrect driver count", 1, provider.getDrivers().size());
+        assertEquals("incorrect driver count", 2, provider.getDrivers().size());
 
-        Driver driver = provider.getDrivers().iterator().next();
+        Iterator<Driver> iterator = provider.getDrivers().iterator();
+        Driver driver = iterator.next();
+        if (!driver.name().equals("foo.1")) {
+            driver = iterator.next();
+        }
+
         assertEquals("incorrect driver name", "foo.1", driver.name());
         assertEquals("incorrect driver mfg", "Circus", driver.manufacturer());
         assertEquals("incorrect driver hw", "1.2a", driver.hwVersion());
         assertEquals("incorrect driver sw", "2.2", driver.swVersion());
 
-        assertEquals("incorrect driver behaviours", 2, driver.behaviours().size());
+        assertEquals("incorrect driver behaviours", 1, driver.behaviours().size());
         assertTrue("incorrect driver behaviour", driver.hasBehaviour(TestBehaviour.class));
 
         assertEquals("incorrect driver properties", 2, driver.properties().size());
@@ -52,20 +58,20 @@
     @Test(expected = IOException.class)
     public void badXML() throws IOException {
         XmlDriverLoader loader = new XmlDriverLoader(getClass().getClassLoader());
-        loader.loadDrivers(getClass().getResourceAsStream("drivers.bad.xml"));
+        loader.loadDrivers(getClass().getResourceAsStream("drivers.bad.xml"), null);
     }
 
     @Test(expected = IllegalArgumentException.class)
     public void noClass() throws IOException {
         XmlDriverLoader loader = new XmlDriverLoader(getClass().getClassLoader());
-        loader.loadDrivers(getClass().getResourceAsStream("drivers.noclass.xml"));
+        loader.loadDrivers(getClass().getResourceAsStream("drivers.noclass.xml"), null);
     }
 
     @Test(expected = IllegalArgumentException.class)
     public void noConstructor() throws IOException {
         XmlDriverLoader loader = new XmlDriverLoader(getClass().getClassLoader());
         InputStream stream = getClass().getResourceAsStream("drivers.noconstructor.xml");
-        DriverProvider provider = loader.loadDrivers(stream);
+        DriverProvider provider = loader.loadDrivers(stream, null);
         Driver driver = provider.getDrivers().iterator().next();
         driver.createBehaviour(new DefaultDriverData(driver), TestBehaviour.class);
     }
diff --git a/core/api/src/test/resources/org/onosproject/net/driver/drivers.1.xml b/core/api/src/test/resources/org/onosproject/net/driver/drivers.1.xml
index 24b4cf8..e449045 100644
--- a/core/api/src/test/resources/org/onosproject/net/driver/drivers.1.xml
+++ b/core/api/src/test/resources/org/onosproject/net/driver/drivers.1.xml
@@ -15,12 +15,15 @@
   ~ limitations under the License.
   -->
 <drivers>
-    <driver name="foo.1" manufacturer="Circus" hwVersion="1.2a" swVersion="2.2">
+    <driver name="foo.0" manufacturer="Circus" hwVersion="1.2" swVersion="2.0">
+        <behaviour api="org.onosproject.net.driver.TestBehaviour"
+                   impl="org.onosproject.net.driver.TestBehaviourImpl"/>
+    </driver>
+
+    <driver name="foo.1" extends="foo.0" manufacturer="Circus" hwVersion="1.2a" swVersion="2.2">
         <fingerprint>ding</fingerprint>
         <fingerprint>bat</fingerprint>
 
-        <behaviour api="org.onosproject.net.driver.TestBehaviour"
-                   impl="org.onosproject.net.driver.TestBehaviourImpl"/>
         <behaviour api="org.onosproject.net.driver.TestBehaviourTwo"
                    impl="org.onosproject.net.driver.TestBehaviourTwoImpl"/>
 
diff --git a/core/net/src/main/java/org/onosproject/net/driver/impl/DriverManager.java b/core/net/src/main/java/org/onosproject/net/driver/impl/DriverManager.java
index 5f7e2e2..f8bc032 100644
--- a/core/net/src/main/java/org/onosproject/net/driver/impl/DriverManager.java
+++ b/core/net/src/main/java/org/onosproject/net/driver/impl/DriverManager.java
@@ -169,5 +169,4 @@
     private String key(String mfr, String hw, String sw) {
         return String.format("%s-%s-%s", mfr, hw, sw);
     }
-
 }
diff --git a/drivers/src/main/java/org/onosproject/driver/DefaultDrivers.java b/drivers/src/main/java/org/onosproject/driver/DefaultDrivers.java
index 8167467..83adcde 100644
--- a/drivers/src/main/java/org/onosproject/driver/DefaultDrivers.java
+++ b/drivers/src/main/java/org/onosproject/driver/DefaultDrivers.java
@@ -28,7 +28,6 @@
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.io.IOException;
 import java.io.InputStream;
 
 /**
@@ -52,9 +51,10 @@
         ClassLoader classLoader = getClass().getClassLoader();
         try {
             InputStream stream = classLoader.getResourceAsStream(DRIVERS_XML);
-            provider = new XmlDriverLoader(classLoader).loadDrivers(stream);
+            provider = new XmlDriverLoader(classLoader)
+                    .loadDrivers(stream, driverAdminService);
             driverAdminService.registerProvider(provider);
-        } catch (IOException e) {
+        } catch (Exception e) {
             log.error("Unable to load default drivers", e);
         }
         log.info("Started");