ONOS-3650 Device driver multiple inheritance

Change-Id: Ib7b72d44533d4e63c4122662b50485243562aa21
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 b7a9f2b..f1d1fb4 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
@@ -16,8 +16,11 @@
 package org.onosproject.net.driver;
 
 import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
+import org.slf4j.Logger;
 
+import java.util.List;
 import java.util.Map;
 import java.util.Objects;
 import java.util.Set;
@@ -26,14 +29,17 @@
 import static com.google.common.base.Preconditions.checkArgument;
 import static com.google.common.base.Preconditions.checkNotNull;
 import static com.google.common.collect.ImmutableMap.copyOf;
+import static org.slf4j.LoggerFactory.getLogger;
 
 /**
  * Default implementation of extensible driver.
  */
 public class DefaultDriver implements Driver {
 
+    private final Logger log = getLogger(getClass());
+
     private final String name;
-    private final Driver parent;
+    private final List<Driver> parents;
 
     private final String manufacturer;
     private final String hwVersion;
@@ -53,12 +59,37 @@
      * @param behaviours   device behaviour classes
      * @param properties   properties for configuration of device behaviour classes
      */
+    @Deprecated
     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.parents = parent == null ? null : Lists.newArrayList(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");
+        this.behaviours = copyOf(checkNotNull(behaviours, "Behaviours cannot be null"));
+        this.properties = copyOf(checkNotNull(properties, "Properties cannot be null"));
+    }
+
+    /**
+     * Creates a driver with the specified name.
+     *
+     * @param name         driver name
+     * @param parents      optional parent drivers
+     * @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, List<Driver> parents, 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.parents = parents == null || parents.isEmpty() ? null : parents;
         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");
@@ -68,7 +99,7 @@
 
     @Override
     public Driver merge(Driver other) {
-        checkArgument(parent == null || Objects.equals(parent, other.parent()),
+        checkArgument(parents == null || Objects.equals(parent(), other.parent()),
                       "Parent drivers are not the same");
 
         // Merge the behaviours.
@@ -81,7 +112,8 @@
         ImmutableMap.Builder<String, String> properties = ImmutableMap.builder();
         properties.putAll(this.properties).putAll(other.properties());
 
-        return new DefaultDriver(name, other.parent(), manufacturer, hwVersion, swVersion,
+        return new DefaultDriver(name, other.parents(),
+                                 manufacturer, hwVersion, swVersion,
                                  ImmutableMap.copyOf(behaviours), properties.build());
     }
 
@@ -107,7 +139,12 @@
 
     @Override
     public Driver parent() {
-        return parent;
+        return parents == null ? null : parents.get(0);
+    }
+
+    @Override
+    public List<Driver> parents() {
+        return parents;
     }
 
     @Override
@@ -123,7 +160,8 @@
     @Override
     public boolean hasBehaviour(Class<? extends Behaviour> behaviourClass) {
         return behaviours.containsKey(behaviourClass) ||
-                (parent != null && parent.hasBehaviour(behaviourClass));
+                (parents != null && parents.stream()
+                        .filter(parent -> parent.hasBehaviour(behaviourClass)).count() > 0);
     }
 
     @Override
@@ -132,8 +170,14 @@
         T behaviour = createBehaviour(data, null, behaviourClass);
         if (behaviour != null) {
             return behaviour;
-        } else if (parent != null) {
-            return parent.createBehaviour(data, behaviourClass);
+        } else if (parents != null) {
+            for (Driver parent : Lists.reverse(parents)) {
+                try {
+                    return parent.createBehaviour(data, behaviourClass);
+                } catch (IllegalArgumentException e) {
+                    log.debug("Parent {} does not support behaviour {}", parent, behaviourClass);
+                }
+            }
         }
         throw new IllegalArgumentException(behaviourClass.getName() + " not supported");
     }
@@ -144,8 +188,14 @@
         T behaviour = createBehaviour(handler.data(), handler, behaviourClass);
         if (behaviour != null) {
             return behaviour;
-        } else if (parent != null) {
-            return parent.createBehaviour(handler, behaviourClass);
+        } else if (parents != null && !parents.isEmpty()) {
+            for (Driver parent : Lists.reverse(parents)) {
+                try {
+                    return parent.createBehaviour(handler, behaviourClass);
+                } catch (IllegalArgumentException e) {
+                    log.debug("Parent {} does not support behaviour {}", parent, behaviourClass);
+                }
+            }
         }
         throw new IllegalArgumentException(behaviourClass.getName() + " not supported");
     }
@@ -202,7 +252,7 @@
     public String toString() {
         return toStringHelper(this)
                 .add("name", name)
-                .add("parent", parent)
+                .add("parents", parents)
                 .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 50611b1..3dc0fdb0 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
@@ -17,6 +17,7 @@
 
 import org.onosproject.net.Annotations;
 
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
@@ -40,9 +41,18 @@
      *
      * @return parent driver; null if driver has no parent
      */
+    @Deprecated
     Driver parent();
 
     /**
+     * Returns all the parent drivers from which this driver inherits behaviours
+     * and properties.
+     *
+     * @return list of parent drivers; null if driver has no parent
+     */
+    List<Driver> parents();
+
+    /**
      * Returns the device manufacturer name.
      *
      * @return manufacturer name
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 fc5e04a..af79ba6 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.Lists;
 import com.google.common.collect.Maps;
 import org.apache.commons.configuration.ConfigurationException;
 import org.apache.commons.configuration.HierarchicalConfiguration;
@@ -23,7 +24,10 @@
 
 import java.io.IOException;
 import java.io.InputStream;
+import java.util.Arrays;
+import java.util.List;
 import java.util.Map;
+import java.util.stream.Collectors;
 
 /**
  * Utility capable of reading driver configuration XML resources and producing
@@ -126,13 +130,22 @@
     public DefaultDriver loadDriver(HierarchicalConfiguration driverCfg,
                                     DriverResolver resolver) {
         String name = driverCfg.getString(NAME);
-        String parentName = driverCfg.getString(EXTENDS);
+        String parentsString = driverCfg.getString(EXTENDS, "");
+        List<Driver> parents = Lists.newArrayList();
+        if (!parentsString.equals("")) {
+            List<String> parentsNames;
+            if (parentsString.contains(",")) {
+                parentsNames = Arrays.asList(parentsString.replace(" ", "").split(","));
+            } else {
+                parentsNames = Lists.newArrayList(parentsString);
+            }
+            parents = parentsNames.stream().map(parent -> (parent != null) ?
+                    resolve(parent, resolver) : null).collect(Collectors.toList());
+        }
         String manufacturer = driverCfg.getString(MFG, "");
         String hwVersion = driverCfg.getString(HW, "");
         String swVersion = driverCfg.getString(SW, "");
-
-        Driver parent = parentName != null ? resolve(parentName, resolver) : null;
-        return new DefaultDriver(name, parent, manufacturer, hwVersion, swVersion,
+        return new DefaultDriver(name, parents, manufacturer, hwVersion, swVersion,
                                  parseBehaviours(driverCfg),
                                  parseProperties(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 e3d6910..883c8ab 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
@@ -20,6 +20,8 @@
 import org.junit.Test;
 import org.onosproject.net.DeviceId;
 
+import java.util.ArrayList;
+
 import static org.junit.Assert.*;
 import static org.onosproject.net.DeviceId.deviceId;
 
@@ -32,7 +34,7 @@
 
     @Before
     public void setUp() {
-        ddc = new DefaultDriver("foo.bar", null, "Circus", "lux", "1.2a",
+        ddc = new DefaultDriver("foo.bar", new ArrayList<>(), "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 717cda2..5e4552d 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
@@ -19,6 +19,8 @@
 import org.junit.Before;
 import org.junit.Test;
 
+import java.util.ArrayList;
+
 import static org.junit.Assert.assertSame;
 import static org.junit.Assert.assertTrue;
 
@@ -30,7 +32,7 @@
 
     @Before
     public void setUp() {
-        ddc = new DefaultDriver("foo.bar", null, "Circus", "lux", "1.2a",
+        ddc = new DefaultDriver("foo.bar", new ArrayList<>(), "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 4568fd9..5c9f5e0 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
@@ -18,6 +18,7 @@
 import com.google.common.collect.ImmutableMap;
 import org.junit.Test;
 
+import java.util.ArrayList;
 import java.util.Set;
 
 import static com.google.common.collect.ImmutableSet.of;
@@ -28,15 +29,15 @@
     @Test
     public void basics() {
         DefaultDriverProvider ddp = new DefaultDriverProvider();
-        DefaultDriver one = new DefaultDriver("foo.bar", null, "Circus", "lux", "1.2a",
+        DefaultDriver one = new DefaultDriver("foo.bar", new ArrayList<>(), "Circus", "lux", "1.2a",
                                               ImmutableMap.of(TestBehaviour.class,
                                                               TestBehaviourImpl.class),
                                               ImmutableMap.of("foo", "bar"));
-        DefaultDriver two = new DefaultDriver("foo.bar", null, "", "", "",
+        DefaultDriver two = new DefaultDriver("foo.bar", new ArrayList<>(), "", "", "",
                                               ImmutableMap.of(TestBehaviourTwo.class,
                                                               TestBehaviourTwoImpl.class),
                                               ImmutableMap.of("goo", "wee"));
-        DefaultDriver three = new DefaultDriver("goo.foo", null, "BigTop", "better", "2.2",
+        DefaultDriver three = new DefaultDriver("goo.foo", new ArrayList<>(), "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 01cc7a1..9e7adc3 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
@@ -18,6 +18,8 @@
 import com.google.common.collect.ImmutableMap;
 import org.junit.Test;
 
+import java.util.ArrayList;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 import static org.onosproject.net.driver.DefaultDriverDataTest.DEVICE_ID;
@@ -26,7 +28,7 @@
 
     @Test
     public void basics() {
-        DefaultDriver ddp = new DefaultDriver("foo.base", null, "Circus", "lux", "1.2a",
+        DefaultDriver ddp = new DefaultDriver("foo.base", new ArrayList<>(), "Circus", "lux", "1.2a",
                                               ImmutableMap.of(TestBehaviour.class,
                                                               TestBehaviourImpl.class,
                                                               TestBehaviourTwo.class,
@@ -62,12 +64,12 @@
 
     @Test
     public void merge() {
-        DefaultDriver one = new DefaultDriver("foo.bar", null, "Circus", "lux", "1.2a",
+        DefaultDriver one = new DefaultDriver("foo.bar", new ArrayList<>(), "Circus", "lux", "1.2a",
                                               ImmutableMap.of(TestBehaviour.class,
                                                               TestBehaviourImpl.class),
                                               ImmutableMap.of("foo", "bar"));
         Driver ddc =
-                one.merge(new DefaultDriver("foo.bar", null, "", "", "",
+                one.merge(new DefaultDriver("foo.bar", new ArrayList<>(), "", "", "",
                                             ImmutableMap.of(TestBehaviourTwo.class,
                                                             TestBehaviourTwoImpl.class),
                                             ImmutableMap.of("goo", "wee")));
diff --git a/core/api/src/test/java/org/onosproject/net/driver/TestBehaviourImpl2.java b/core/api/src/test/java/org/onosproject/net/driver/TestBehaviourImpl2.java
new file mode 100644
index 0000000..5661033
--- /dev/null
+++ b/core/api/src/test/java/org/onosproject/net/driver/TestBehaviourImpl2.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2016 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;
+
+/**
+ * Test behaviour.
+ */
+public class TestBehaviourImpl2 extends AbstractHandlerBehaviour implements TestBehaviour {
+}
diff --git a/core/api/src/test/java/org/onosproject/net/driver/TestBehaviourThree.java b/core/api/src/test/java/org/onosproject/net/driver/TestBehaviourThree.java
new file mode 100644
index 0000000..ca45b75
--- /dev/null
+++ b/core/api/src/test/java/org/onosproject/net/driver/TestBehaviourThree.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2016 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;
+
+/**
+ * Test behaviour.
+ */
+public interface TestBehaviourThree extends HandlerBehaviour {
+}
diff --git a/core/api/src/test/java/org/onosproject/net/driver/TestBehaviourThreeImpl.java b/core/api/src/test/java/org/onosproject/net/driver/TestBehaviourThreeImpl.java
new file mode 100644
index 0000000..4b4c4e2
--- /dev/null
+++ b/core/api/src/test/java/org/onosproject/net/driver/TestBehaviourThreeImpl.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2016 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;
+
+/**
+ * Test behaviour.
+ */
+public class TestBehaviourThreeImpl extends AbstractHandlerBehaviour implements TestBehaviourThree {
+}
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 15abc2b..e82d559 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
@@ -16,6 +16,7 @@
 package org.onosproject.net.driver;
 
 import org.junit.Test;
+import org.onosproject.net.DeviceId;
 
 import java.io.IOException;
 import java.io.InputStream;
@@ -77,4 +78,38 @@
         driver.createBehaviour(new DefaultDriverData(driver, DEVICE_ID), TestBehaviour.class);
     }
 
+    @Test
+    public void multipleDrivers() throws IOException {
+        XmlDriverLoader loader = new XmlDriverLoader(getClass().getClassLoader());
+        InputStream stream = getClass().getResourceAsStream("drivers.multipleInheritance.xml");
+        DriverProvider provider = loader.loadDrivers(stream, null);
+        Iterator<Driver> iterator = provider.getDrivers().iterator();
+        Driver driver;
+        do {
+            driver = iterator.next();
+        } while (!driver.name().equals("foo.2"));
+        assertTrue("incorrect multiple behaviour inheritance", driver.hasBehaviour(TestBehaviour.class));
+        assertTrue("incorrect multiple behaviour inheritance", driver.hasBehaviour(TestBehaviourTwo.class));
+    }
+
+    @Test
+    public void multipleDriversSameBehaviors() throws IOException {
+        XmlDriverLoader loader = new XmlDriverLoader(getClass().getClassLoader());
+        InputStream stream = getClass().getResourceAsStream("drivers.sameMultipleInheritance.xml");
+        DriverProvider provider = loader.loadDrivers(stream, null);
+        Iterator<Driver> iterator = provider.getDrivers().iterator();
+        Driver driver;
+        do {
+            driver = iterator.next();
+        } while (!driver.name().equals("foo.2"));
+        assertTrue("incorrect multiple behaviour inheritance", driver.hasBehaviour(TestBehaviour.class));
+        Behaviour b2 = driver.createBehaviour(new DefaultDriverHandler(
+                                                      new DefaultDriverData(
+                                                              driver, DeviceId.deviceId("test_device"))),
+                                              TestBehaviour.class);
+        assertTrue("incorrect multiple same behaviour inheritance", b2.getClass()
+                .getSimpleName().equals("TestBehaviourImpl2"));
+        assertTrue("incorrect multiple behaviour inheritance", driver.hasBehaviour(TestBehaviourTwo.class));
+    }
+
 }
diff --git a/core/api/src/test/resources/org/onosproject/net/driver/drivers.multipleInheritance.xml b/core/api/src/test/resources/org/onosproject/net/driver/drivers.multipleInheritance.xml
new file mode 100644
index 0000000..23a6102
--- /dev/null
+++ b/core/api/src/test/resources/org/onosproject/net/driver/drivers.multipleInheritance.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Copyright 2016 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.
+  -->
+<drivers>
+    <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.TestBehaviourTwo"
+                   impl="org.onosproject.net.driver.TestBehaviourTwoImpl"/>
+
+        <property name="p1">v1</property>
+        <property name="p2">v2</property>
+    </driver>
+
+    <driver name="foo.2" extends="foo.0,foo.1" manufacturer="Circus" hwVersion="1.2" swVersion="2.0">
+        <behaviour api="org.onosproject.net.driver.TestBehaviourThree"
+                   impl="org.onosproject.net.driver.TestBehaviourThreeImpl"/>
+    </driver>
+</drivers>
\ No newline at end of file
diff --git a/core/api/src/test/resources/org/onosproject/net/driver/drivers.sameMultipleInheritance.xml b/core/api/src/test/resources/org/onosproject/net/driver/drivers.sameMultipleInheritance.xml
new file mode 100644
index 0000000..726db11
--- /dev/null
+++ b/core/api/src/test/resources/org/onosproject/net/driver/drivers.sameMultipleInheritance.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Copyright 2016 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.
+  -->
+<drivers>
+    <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.TestBehaviourImpl2"/>
+        <behaviour api="org.onosproject.net.driver.TestBehaviourTwo"
+                   impl="org.onosproject.net.driver.TestBehaviourTwoImpl"/>
+
+        <property name="p1">v1</property>
+        <property name="p2">v2</property>
+    </driver>
+
+    <driver name="foo.2" extends="foo.0,foo.1" manufacturer="Circus" hwVersion="1.2" swVersion="2.0">
+        <behaviour api="org.onosproject.net.driver.TestBehaviourThree"
+                   impl="org.onosproject.net.driver.TestBehaviourThreeImpl"/>
+    </driver>
+</drivers>
\ No newline at end of file
diff --git a/core/common/src/test/java/org/onosproject/codec/impl/DriverCodecTest.java b/core/common/src/test/java/org/onosproject/codec/impl/DriverCodecTest.java
index a1c9517..d12129a 100644
--- a/core/common/src/test/java/org/onosproject/codec/impl/DriverCodecTest.java
+++ b/core/common/src/test/java/org/onosproject/codec/impl/DriverCodecTest.java
@@ -16,6 +16,7 @@
 package org.onosproject.codec.impl;
 
 
+import java.util.ArrayList;
 import java.util.Map;
 
 import org.junit.Test;
@@ -48,7 +49,7 @@
         Map<String, String> properties =
                 ImmutableMap.of("key1", "value1", "key2", "value2");
 
-        DefaultDriver parent = new DefaultDriver("parent", null, "Acme",
+        DefaultDriver parent = new DefaultDriver("parent", new ArrayList<>(), "Acme",
                 "HW1.2.3", "SW1.2.3",
                 behaviours,
                 properties);
diff --git a/drivers/src/main/resources/onos-drivers.xml b/drivers/src/main/resources/onos-drivers.xml
index d3d1f98..b64fe34 100644
--- a/drivers/src/main/resources/onos-drivers.xml
+++ b/drivers/src/main/resources/onos-drivers.xml
@@ -46,7 +46,7 @@
                    impl="org.onosproject.driver.query.FullMplsAvailable" />
     </driver>
     <!--This driver is for simulated NETCONF devices through of-config tool on top og OVSDB-->
-    <driver name="ovs-netconf" extends="default"
+    <driver name="ovs-netconf" extends="default,ovs"
             manufacturer="" hwVersion="" swVersion="">
         <behaviour api="org.onosproject.openflow.controller.driver.OpenFlowSwitchDriver"
                    impl="org.onosproject.driver.handshaker.NiciraSwitchHandshaker"/>
diff --git a/drivers/src/test/java/org/onosproject/driver/ovsdb/OvsdbControllerConfigTest.java b/drivers/src/test/java/org/onosproject/driver/ovsdb/OvsdbControllerConfigTest.java
index 4a91efc..74aae4c 100644
--- a/drivers/src/test/java/org/onosproject/driver/ovsdb/OvsdbControllerConfigTest.java
+++ b/drivers/src/test/java/org/onosproject/driver/ovsdb/OvsdbControllerConfigTest.java
@@ -28,6 +28,8 @@
 import org.onosproject.ovsdb.controller.driver.OvsdbClientServiceAdapter;
 import org.onosproject.ovsdb.controller.driver.OvsdbControllerAdapter;
 
+import java.util.ArrayList;
+
 /**
  * Created by Andrea on 10/7/15.
  */
@@ -51,7 +53,7 @@
     public void setUp() {
         controllerConfig = new OvsdbControllerConfig();
 
-        ddc = new DefaultDriver("foo.bar", null, "Circus", "lux", "1.2a",
+        ddc = new DefaultDriver("foo.bar", new ArrayList<>(), "Circus", "lux", "1.2a",
                                 ImmutableMap.of(ControllerConfig.class,
                                                 OvsdbControllerConfig.class),
                                 ImmutableMap.of("foo", "bar"));
diff --git a/protocols/openflow/ctl/src/test/java/org/onosproject/openflow/DriverAdapter.java b/protocols/openflow/ctl/src/test/java/org/onosproject/openflow/DriverAdapter.java
index 57becf9..a070b56 100644
--- a/protocols/openflow/ctl/src/test/java/org/onosproject/openflow/DriverAdapter.java
+++ b/protocols/openflow/ctl/src/test/java/org/onosproject/openflow/DriverAdapter.java
@@ -15,6 +15,7 @@
  */
 package org.onosproject.openflow;
 
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
@@ -39,6 +40,11 @@
     }
 
     @Override
+    public List<Driver> parents() {
+        return null;
+    }
+
+    @Override
     public String manufacturer() {
         return null;
     }