Sketching out device driver subsystem to allow extensible device management functions to be made available to applications.
Revising some implementations and adding tests.
Removing fingerprint and extension concept for now.

Change-Id: Id50faf29e4590b08e0c2b385ae8d4bb0c453f37e
diff --git a/core/api/pom.xml b/core/api/pom.xml
index 540003a..e02bb78 100644
--- a/core/api/pom.xml
+++ b/core/api/pom.xml
@@ -37,6 +37,15 @@
             <artifactId>joda-time</artifactId>
         </dependency>
         <dependency>
+            <groupId>commons-configuration</groupId>
+            <artifactId>commons-configuration</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>commons-collections</groupId>
+            <artifactId>commons-collections</artifactId>
+            <version>3.2.1</version>
+        </dependency>
+        <dependency>
             <groupId>com.google.guava</groupId>
             <artifactId>guava-testlib</artifactId>
             <scope>test</scope>
diff --git a/core/api/src/main/java/org/onosproject/net/AbstractAnnotated.java b/core/api/src/main/java/org/onosproject/net/AbstractAnnotated.java
index d90c9da..2a8b856 100644
--- a/core/api/src/main/java/org/onosproject/net/AbstractAnnotated.java
+++ b/core/api/src/main/java/org/onosproject/net/AbstractAnnotated.java
@@ -16,14 +16,13 @@
 package org.onosproject.net;
 
 import static com.google.common.base.Preconditions.checkArgument;
+import static org.onosproject.net.DefaultAnnotations.EMPTY;
 
 /**
  * Base abstraction of an annotated entity.
  */
 public abstract class AbstractAnnotated implements Annotated {
 
-    private static final Annotations EMPTY = DefaultAnnotations.builder().build();
-
     private final Annotations annotations;
 
     // For serialization
diff --git a/core/api/src/main/java/org/onosproject/net/DefaultAnnotations.java b/core/api/src/main/java/org/onosproject/net/DefaultAnnotations.java
index 514152e..a0ed261 100644
--- a/core/api/src/main/java/org/onosproject/net/DefaultAnnotations.java
+++ b/core/api/src/main/java/org/onosproject/net/DefaultAnnotations.java
@@ -29,6 +29,8 @@
  */
 public final class DefaultAnnotations implements SparseAnnotations {
 
+    public static final Annotations EMPTY = DefaultAnnotations.builder().build();
+
     private final Map<String, String> map;
 
     // For serialization
diff --git a/core/api/src/main/java/org/onosproject/net/MutableAnnotations.java b/core/api/src/main/java/org/onosproject/net/MutableAnnotations.java
new file mode 100644
index 0000000..c2ea09e
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/MutableAnnotations.java
@@ -0,0 +1,40 @@
+/*
+ * 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;
+
+/**
+ * Represents an mutable set of simple key/value string annotations.
+ */
+public interface MutableAnnotations extends Annotations {
+
+    /**
+     * Returns the value of the specified annotation.
+     *
+     * @param key   annotation key
+     * @param value annotation value
+     * @return self
+     */
+    public MutableAnnotations set(String key, String value);
+
+    /**
+     * Clears the specified keys or the all keys if none were specified.
+     *
+     * @param keys keys to be cleared
+     * @return self
+     */
+    public MutableAnnotations clear(String... keys);
+
+}
diff --git a/core/api/src/main/java/org/onosproject/net/driver/AbstractBehaviour.java b/core/api/src/main/java/org/onosproject/net/driver/AbstractBehaviour.java
new file mode 100644
index 0000000..eb6a302
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/driver/AbstractBehaviour.java
@@ -0,0 +1,29 @@
+/*
+ * 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;
+
+/**
+ * Base implementation of device driver behaviour.
+ */
+public class AbstractBehaviour implements Behaviour {
+
+    private DriverData data;
+
+    @Override
+    public void setData(DriverData data) {
+        this.data = data;
+    }
+}
diff --git a/core/api/src/main/java/org/onosproject/net/driver/Behaviour.java b/core/api/src/main/java/org/onosproject/net/driver/Behaviour.java
new file mode 100644
index 0000000..7257eed
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/driver/Behaviour.java
@@ -0,0 +1,32 @@
+/*
+ * 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;
+
+/**
+ * Representation of a facet of device behaviour that can be used to talk about
+ * a device (in context of {@link DriverData}) or to a device (in context of
+ * {@link DriverHandler}).
+ */
+public interface Behaviour {
+
+    /**
+     * Sets the driver data context on this this behaviour should operate.
+     *
+     * @param data driver data
+     */
+    void setData(DriverData data);
+
+}
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
new file mode 100644
index 0000000..e95ddca
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/driver/DefaultDriver.java
@@ -0,0 +1,179 @@
+/*
+ * 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;
+
+import com.google.common.collect.ImmutableMap;
+
+import java.util.Map;
+import java.util.Set;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.collect.ImmutableMap.copyOf;
+
+/**
+ * Default implementation of extensible driver.
+ */
+public class DefaultDriver implements Driver {
+
+    private final String name;
+
+    private final String manufacturer;
+    private final String hwVersion;
+    private final String swVersion;
+
+    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 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,
+                         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.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"));
+    }
+
+    /**
+     * Merges the two drivers while giving preference to this driver when
+     * dealing with conflicts.
+     *
+     * @param other other driver
+     * @return new driver
+     */
+    DefaultDriver merge(DefaultDriver other) {
+        // Merge the behaviours.
+        ImmutableMap.Builder<Class<? extends Behaviour>, Class<? extends Behaviour>>
+                behaviours = ImmutableMap.builder();
+        behaviours.putAll(other.behaviours).putAll(this.behaviours);
+
+        // Merge the properties.
+        ImmutableMap.Builder<String, String> properties = ImmutableMap.builder();
+        properties.putAll(other.properties).putAll(this.properties);
+
+        return new DefaultDriver(name, manufacturer, hwVersion, swVersion,
+                                 behaviours.build(), properties.build());
+    }
+
+    @Override
+    public String name() {
+        return name;
+    }
+
+    @Override
+    public String manufacturer() {
+        return manufacturer;
+    }
+
+    @Override
+    public String hwVersion() {
+        return hwVersion;
+    }
+
+    @Override
+    public String swVersion() {
+        return swVersion;
+    }
+
+    @Override
+    public Set<Class<? extends Behaviour>> behaviours() {
+        return behaviours.keySet();
+    }
+
+    @Override
+    public boolean hasBehaviour(Class<? extends Behaviour> behaviourClass) {
+        return behaviours.containsKey(behaviourClass);
+    }
+
+    /**
+     * Creates an instance of behaviour primed with the specified driver data.
+     *
+     * @param data           driver data context
+     * @param behaviourClass driver behaviour class
+     * @param handler        indicates behaviour is intended for handler context
+     * @param <T>            type of behaviour
+     * @return behaviour instance
+     */
+    public <T extends Behaviour> T createBehaviour(DriverData data,
+                                                   Class<T> behaviourClass,
+                                                   boolean handler) {
+        checkArgument(handler || !HandlerBehaviour.class.isAssignableFrom(behaviourClass),
+                      "{} is applicable only to handler context", behaviourClass.getName());
+
+        // Locate the implementation of the requested behaviour.
+        Class<? extends Behaviour> implementation = behaviours.get(behaviourClass);
+        checkArgument(implementation != null, "{} not supported", behaviourClass.getName());
+
+        // Create an instance of the behaviour and apply data as its context.
+        T behaviour = createBehaviour(behaviourClass, implementation);
+        behaviour.setData(data);
+        return behaviour;
+    }
+
+    @SuppressWarnings("unchecked")
+    private <T extends Behaviour> T createBehaviour(Class<T> behaviourClass,
+                                                    Class<? extends Behaviour> implementation) {
+        try {
+            return (T) implementation.newInstance();
+        } catch (InstantiationException | IllegalAccessException e) {
+            // TODO: add a specific unchecked exception
+            throw new IllegalArgumentException("Unable to create behaviour", e);
+        }
+    }
+
+    @Override
+    public Set<String> keys() {
+        return properties.keySet();
+    }
+
+    @Override
+    public String value(String key) {
+        return properties.get(key);
+    }
+
+    @Override
+    public Map<String, String> properties() {
+        return properties;
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper(this)
+                .add("name", name)
+                .add("manufacturer", manufacturer)
+                .add("hwVersion", hwVersion)
+                .add("swVersion", swVersion)
+                .add("behaviours", behaviours)
+                .add("properties", properties)
+                .toString();
+    }
+
+}
diff --git a/core/api/src/main/java/org/onosproject/net/driver/DefaultDriverData.java b/core/api/src/main/java/org/onosproject/net/driver/DefaultDriverData.java
new file mode 100644
index 0000000..e83afe8
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/driver/DefaultDriverData.java
@@ -0,0 +1,91 @@
+/*
+ * 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;
+
+import com.google.common.collect.ImmutableSet;
+import org.onosproject.net.MutableAnnotations;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+
+/**
+ * Default implementation of driver data descriptor.
+ */
+public class DefaultDriverData implements DriverData {
+
+    private final Driver type;
+    private final Map<String, String> properties;
+
+    /**
+     * Creates new driver data.
+     *
+     * @param type parent driver type
+     */
+    public DefaultDriverData(Driver type) {
+        this.type = type;
+        this.properties = new HashMap<>();
+    }
+
+    @Override
+    public Driver type() {
+        return type;
+    }
+
+    @Override
+    public <T extends Behaviour> T behaviour(Class<T> behaviourClass) {
+        return type.createBehaviour(this, behaviourClass, false);
+    }
+
+    @Override
+    public MutableAnnotations set(String key, String value) {
+        properties.put(key, value);
+        return this;
+    }
+
+    @Override
+    public MutableAnnotations clear(String... keys) {
+        if (keys.length == 0) {
+            properties.clear();
+        } else {
+            for (String key : keys) {
+                properties.remove(key);
+            }
+        }
+        return this;
+    }
+
+    @Override
+    public Set<String> keys() {
+        return ImmutableSet.copyOf(properties.keySet());
+    }
+
+    @Override
+    public String value(String key) {
+        return properties.get(key);
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper(this)
+                .add("type", type)
+                .add("properties", properties)
+                .toString();
+    }
+
+}
diff --git a/core/api/src/main/java/org/onosproject/net/driver/DefaultDriverHandler.java b/core/api/src/main/java/org/onosproject/net/driver/DefaultDriverHandler.java
new file mode 100644
index 0000000..247ccec
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/driver/DefaultDriverHandler.java
@@ -0,0 +1,53 @@
+/*
+ * 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;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+
+/**
+ * Default implementation of driver handler.
+ */
+public class DefaultDriverHandler implements DriverHandler {
+
+    private final DefaultDriverData data;
+
+    /**
+     * Creates new driver handler with the attached driver data.
+     *
+     * @param data driver data to attach
+     */
+    public DefaultDriverHandler(DefaultDriverData data) {
+        this.data = data;
+    }
+
+    @Override
+    public DriverData data() {
+        return data;
+    }
+
+    @Override
+    public <T extends Behaviour> T behaviour(Class<T> behaviourClass) {
+        return data.type().createBehaviour(this.data, behaviourClass, true);
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper(this)
+                .add("data", data)
+                .toString();
+    }
+
+}
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
new file mode 100644
index 0000000..3110dc8
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/driver/DefaultDriverProvider.java
@@ -0,0 +1,69 @@
+/*
+ * 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;
+
+import com.google.common.collect.ImmutableSet;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+
+/**
+ * Default driver provider implementation.
+ */
+public class DefaultDriverProvider implements DriverProvider {
+
+    private final Map<String, DefaultDriver> drivers = new HashMap<>();
+
+    @Override
+    public Set<Driver> getDrivers() {
+        return ImmutableSet.copyOf(drivers.values());
+    }
+
+    /**
+     * Adds the specified driver to be provided.
+     *
+     * @param driverClasses driver to be provided
+     */
+    public void addDrivers(Set<DefaultDriver> driverClasses) {
+        for (DefaultDriver driverClass : driverClasses) {
+            addDriver(driverClass);
+        }
+    }
+
+    /**
+     * Adds the specified driver to be provided.
+     *
+     * @param driverClass driver to be provided
+     */
+    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));
+        }
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper(this).add("drivers", drivers).toString();
+    }
+}
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
new file mode 100644
index 0000000..a6883d5
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/driver/Driver.java
@@ -0,0 +1,93 @@
+/*
+ * 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;
+
+import org.onosproject.net.Annotations;
+
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Representation of a specific family of device drivers. Behaviour configuration
+ * data is stored using {@link org.onosproject.net.Annotations}.
+ */
+public interface Driver extends Annotations {
+
+    /**
+     * Returns the driver name. This is expected to be a reverse-DNS,
+     * Java package-like name.
+     *
+     * @return driver name
+     */
+    String name();
+
+    /**
+     * Returns the device manufacturer name.
+     *
+     * @return manufacturer name
+     */
+    String manufacturer();
+
+    /**
+     * Returns the device hardware version.
+     *
+     * @return hardware version
+     */
+    String hwVersion();
+
+    /**
+     * Returns the device software version.
+     *
+     * @return software version
+     */
+    String swVersion();
+
+    /**
+     * Returns the set of behaviours supported by this driver.
+     *
+     * @return set of device driver behaviours
+     */
+    Set<Class<? extends Behaviour>> behaviours();
+
+    /**
+     * Indicates whether or not the driver supports the specified class
+     * of behaviour.
+     *
+     * @param behaviourClass behaviour class
+     * @return true if behaviour is supported
+     */
+    boolean hasBehaviour(Class<? extends Behaviour> behaviourClass);
+
+    /**
+     * Creates an instance of behaviour primed with the specified driver data.
+     *
+     * @param data           driver data context
+     * @param behaviourClass driver behaviour class
+     * @param handler        indicates behaviour is intended for handler context
+     * @param <T>            type of behaviour
+     * @return behaviour instance
+     */
+    <T extends Behaviour> T createBehaviour(DriverData data, Class<T> behaviourClass,
+                                            boolean handler);
+
+    /**
+     * Returns the set of annotations as map of key/value properties.
+     *
+     * @return map of properties
+     */
+    Map<String, String> properties();
+
+}
diff --git a/core/api/src/main/java/org/onosproject/net/driver/DriverAdminService.java b/core/api/src/main/java/org/onosproject/net/driver/DriverAdminService.java
new file mode 100644
index 0000000..e7fa138
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/driver/DriverAdminService.java
@@ -0,0 +1,46 @@
+/*
+ * 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;
+
+import java.util.Set;
+
+/**
+ * Service for managing drivers and driver behaviour implementations.
+ */
+public interface DriverAdminService extends DriverService {
+
+    /**
+     * Returns the set of driver providers currently registered.
+     *
+     * @return registered driver providers
+     */
+    Set<DriverProvider> getProviders();
+
+    /**
+     * Registers the specified driver provider.
+     *
+     * @param provider driver provider to register
+     */
+    void registerProvider(DriverProvider provider);
+
+    /**
+     * Unregisters the specified driver provider.
+     *
+     * @param provider driver provider to unregister
+     */
+    void unregisterProvider(DriverProvider provider);
+
+}
diff --git a/core/api/src/main/java/org/onosproject/net/driver/DriverConnect.java b/core/api/src/main/java/org/onosproject/net/driver/DriverConnect.java
new file mode 100644
index 0000000..1d51091
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/driver/DriverConnect.java
@@ -0,0 +1,36 @@
+/*
+ * 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;
+
+/**
+ * Abstraction of handler behaviour used to set-up and tear-down driver
+ * connection with a device.
+ */
+public interface DriverConnect extends HandlerBehaviour {
+
+    /**
+     * Connects to the device.
+     *
+     * @param credentials optional login credentials in string form
+     */
+    void connect(String... credentials);
+
+    /**
+     * Disconnects from the device.
+     */
+    void disconnect();
+
+}
diff --git a/core/api/src/main/java/org/onosproject/net/driver/DriverData.java b/core/api/src/main/java/org/onosproject/net/driver/DriverData.java
new file mode 100644
index 0000000..ff4d622
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/driver/DriverData.java
@@ -0,0 +1,42 @@
+/*
+ * 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;
+
+import org.onosproject.net.MutableAnnotations;
+
+/**
+ * Container for data about a device. Data is stored using
+ * {@link org.onosproject.net.MutableAnnotations}.
+ */
+public interface DriverData extends MutableAnnotations {
+
+    /**
+     * Returns the parent device driver.
+     *
+     * @return device driver
+     */
+    Driver type();
+
+    /**
+     * Returns the specified facet of behaviour to access the device data.
+     *
+     * @param behaviourClass behaviour class
+     * @param <T>            type of behaviour
+     * @return requested behaviour or null if not supported
+     */
+    <T extends Behaviour> T behaviour(Class<T> behaviourClass);
+
+}
diff --git a/core/api/src/main/java/org/onosproject/net/driver/DriverHandler.java b/core/api/src/main/java/org/onosproject/net/driver/DriverHandler.java
new file mode 100644
index 0000000..0fb46aa
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/driver/DriverHandler.java
@@ -0,0 +1,39 @@
+/*
+ * 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;
+
+/**
+ * Representation of context for interacting with a device.
+ */
+public interface DriverHandler {
+
+    /**
+     * Returns the device driver data.
+     *
+     * @return device driver data
+     */
+    DriverData data();
+
+    /**
+     * Returns the specified facet of behaviour to interact with the device.
+     *
+     * @param behaviourClass behaviour class
+     * @param <T>            type of behaviour
+     * @return behaviour
+     */
+    <T extends Behaviour> T behaviour(Class<T> behaviourClass);
+
+}
diff --git a/core/api/src/main/java/org/onosproject/net/driver/DriverProvider.java b/core/api/src/main/java/org/onosproject/net/driver/DriverProvider.java
new file mode 100644
index 0000000..354d93e
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/driver/DriverProvider.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;
+
+import java.util.Set;
+
+/**
+ * Represents entity capable of providing device drivers and their
+ * behaviours.
+ */
+public interface DriverProvider {
+
+    /**
+     * Returns the set of driver types and behaviour implementations to be
+     * made available by this provider.
+     *
+     * @return set of driver types and their behaviours
+     */
+    Set<Driver> getDrivers();
+
+}
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
new file mode 100644
index 0000000..5d6d464
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/driver/DriverService.java
@@ -0,0 +1,77 @@
+/*
+ * 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;
+
+import org.onosproject.net.DeviceId;
+
+import java.util.Set;
+
+/**
+ * Service for obtaining drivers and driver behaviour implementations.
+ */
+public interface DriverService {
+
+    /**
+     * Returns the overall set of drivers being provided, optionally
+     * filtered to only those that support all specified behaviours.
+     *
+     * @param withBehaviours optional behaviour classes to query by
+     * @return provided drivers
+     */
+    Set<Driver> getDrivers(Class<? extends Behaviour>... withBehaviours);
+
+    /**
+     * Returns the specified driver.
+     *
+     * @param driverName driver name
+     * @return driver
+     */
+    Driver getDriver(String driverName);
+
+    /**
+     * Returns the driver that matches the specified primordial device
+     * discovery information.
+     *
+     * @param mfr device manufacturer
+     * @param hw  device hardware name/version
+     * @param sw  device software version
+     * @return driver or null of no matching one is found
+     */
+    Driver getDriver(String mfr, String hw, String sw);
+
+    /**
+     * Creates a new driver handler for the specified driver.
+     *
+     * @param driverName  driver name
+     * @param deviceId    device identifier
+     * @param credentials optional login credentials in string form
+     * @return driver handler
+     */
+    DriverHandler createHandler(String driverName, DeviceId deviceId,
+                                String... credentials);
+
+    /**
+     * Creates a new driver handler for the specified driver data.
+     *
+     * @param data        driver data
+     * @param deviceId    device identifier
+     * @param credentials optional login credentials in string form
+     * @return driver handler
+     */
+    DriverHandler createHandler(DriverData data, DeviceId deviceId,
+                                String... credentials);
+
+}
diff --git a/core/api/src/main/java/org/onosproject/net/driver/HandlerBehaviour.java b/core/api/src/main/java/org/onosproject/net/driver/HandlerBehaviour.java
new file mode 100644
index 0000000..7e3f78d
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/driver/HandlerBehaviour.java
@@ -0,0 +1,23 @@
+/*
+ * 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;
+
+/**
+ * Representation of a facet of device behaviour that can be used to interact
+ * with a device (in context of {@link org.onosproject.net.driver.DriverHandler}).
+ */
+public interface HandlerBehaviour extends Behaviour {
+}
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
new file mode 100644
index 0000000..c3bb7ac
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/driver/XmlDriverLoader.java
@@ -0,0 +1,154 @@
+/*
+ * 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;
+
+import com.google.common.collect.ImmutableMap;
+import org.apache.commons.configuration.ConfigurationException;
+import org.apache.commons.configuration.HierarchicalConfiguration;
+import org.apache.commons.configuration.XMLConfiguration;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Map;
+
+/**
+ * Utility capable of reading driver configuration XML resources and producing
+ * a device driver provider as a result.
+ * <p>
+ * The drivers stream structure is as follows:
+ * </p>
+ * <pre>
+ *     &lt;drivers&gt;
+ *         &lt;driver name=“...” [manufacturer="..." hwVersion="..." swVersion="..."]&gt;
+ *             &lt;behaviour api="..." impl="..."/&gt;
+ *             ...
+ *             [&lt;property name=“key”&gt;value&lt;/key&gt;]
+ *             ...
+ *         &lt;/driver&gt;
+ *         ...
+ *     &lt;/drivers&gt;
+ * </pre>
+ */
+public class XmlDriverLoader {
+
+    private static final String DRIVERS = "drivers";
+    private static final String DRIVER = "driver";
+
+    private static final String BEHAVIOUR = "behaviour";
+    private static final String PROPERTY = "property";
+
+    private static final String NAME = "[@name]";
+    private static final String MFG = "[@manufacturer]";
+    private static final String HW = "[@hwVersion]";
+    private static final String SW = "[@swVersion]";
+    private static final String API = "[@api]";
+    private static final String IMPL = "[@impl]";
+
+    private final ClassLoader classLoader;
+
+    /**
+     * Creates a new driver loader capable of loading drivers from the supplied
+     * class loader.
+     *
+     * @param classLoader class loader to use
+     */
+    public XmlDriverLoader(ClassLoader classLoader) {
+        this.classLoader = classLoader;
+    }
+
+    /**
+     * Loads the specified drivers resource as an XML stream and parses it to
+     * produce a ready-to-register driver provider.
+     *
+     * @param driversStream stream containing the drivers definitions
+     * @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 {
+        try {
+            XMLConfiguration cfg = new XMLConfiguration();
+            cfg.setRootElementName(DRIVERS);
+            cfg.setAttributeSplittingDisabled(true);
+
+            cfg.load(driversStream);
+            return loadDrivers(cfg);
+        } catch (ConfigurationException e) {
+            throw new IOException("Unable to load drivers", e);
+        }
+    }
+
+    /**
+     * Loads a driver provider from the supplied hierarchical configuration.
+     *
+     * @param driversCfg hierarchical configuration containing the drivers definitions
+     * @return driver provider
+     */
+    public DefaultDriverProvider loadDrivers(HierarchicalConfiguration driversCfg) {
+        DefaultDriverProvider provider = new DefaultDriverProvider();
+        for (HierarchicalConfiguration cfg : driversCfg.configurationsAt(DRIVER)) {
+            provider.addDriver(loadDriver(cfg));
+        }
+        return provider;
+    }
+
+    /**
+     * Loads a driver from the supplied hierarchical configuration.
+     *
+     * @param driverCfg hierarchical configuration containing the driver definition
+     * @return driver
+     */
+    public DefaultDriver loadDriver(HierarchicalConfiguration driverCfg) {
+        String name = driverCfg.getString(NAME);
+        String manufacturer = driverCfg.getString(MFG, "");
+        String hwVersion = driverCfg.getString(HW, "");
+        String swVersion = driverCfg.getString(SW, "");
+
+        return new DefaultDriver(name, manufacturer, hwVersion, swVersion,
+                                 parseBehaviours(driverCfg),
+                                 parseProperties(driverCfg));
+    }
+
+    // Parses the behaviours section.
+    private Map<Class<? extends Behaviour>, Class<? extends Behaviour>>
+    parseBehaviours(HierarchicalConfiguration driverCfg) {
+        ImmutableMap.Builder<Class<? extends Behaviour>,
+                Class<? extends Behaviour>> behaviours = ImmutableMap.builder();
+        for (HierarchicalConfiguration b : driverCfg.configurationsAt(BEHAVIOUR)) {
+            behaviours.put(getClass(b.getString(API)), getClass(b.getString(IMPL)));
+        }
+        return behaviours.build();
+    }
+
+    // Parses the properties section.
+    private Map<String, String> parseProperties(HierarchicalConfiguration driverCfg) {
+        ImmutableMap.Builder<String, String> properties = ImmutableMap.builder();
+        for (HierarchicalConfiguration b : driverCfg.configurationsAt(PROPERTY)) {
+            properties.put(b.getString(NAME), (String) b.getRootNode().getValue());
+        }
+        return properties.build();
+    }
+
+    @SuppressWarnings("unchecked")
+    private Class<? extends Behaviour> getClass(String className) {
+        try {
+            return (Class<? extends Behaviour>) classLoader.loadClass(className);
+        } catch (ClassNotFoundException e) {
+            throw new IllegalArgumentException("Unable to load class " + className, e);
+        }
+    }
+
+}
diff --git a/core/api/src/main/java/org/onosproject/net/driver/package-info.java b/core/api/src/main/java/org/onosproject/net/driver/package-info.java
new file mode 100644
index 0000000..fbc39a8
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/driver/package-info.java
@@ -0,0 +1,68 @@
+/*
+ * 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.
+ */
+
+/**
+ * Set of facilities to allow the platform to be extended with
+ * device specific behaviours and to allow modeling device behaviours while
+ * hiding details of specific device driver implementations.
+ * <p>
+ * {@link org.onosproject.net.driver.Driver} is a representation of a
+ * specific family of devices supports set of
+ * {@link org.onosproject.net.driver.Behaviour behaviour classes}. Default
+ * implementation is provided by the platform and allows DriverProviders to
+ * add different behaviour implementations via DriverService.
+ * </p>
+ * <p>
+ * {@link org.onosproject.net.driver.DriverData} is a container for data
+ * learned about a device. It is associated with a specific
+ * {@link org.onosproject.net.driver.Driver}
+ * and provides set of {@link org.onosproject.net.driver.Behaviour behaviours}
+ * for talking about a device. A default
+ * implementation provided by platform and has mutable key/value store for use by
+ * implementations of {@link org.onosproject.net.driver.Behaviour behaviours}.
+ * </p>
+ * <p>
+ * {@link org.onosproject.net.driver.DriverHandler} is an entity used as a
+ * context to interact with a device. It has a peer
+ * {@link org.onosproject.net.driver.DriverData} instance, which is used to
+ * store information learned about a device. It also
+ * provides set of {@link org.onosproject.net.driver.Behaviour behaviours}
+ * for talking to a device.
+ * </p>
+ * <p>
+ * {@link org.onosproject.net.driver.DriverService} can be used to query the
+ * inventory of device drivers and their behaviours, while the
+ * {@link org.onosproject.net.driver.DriverAdminService} allows adding/removing
+ * drivers and managing behaviour implementations.
+ * {@link org.onosproject.net.driver.DriverProvider} is an entity capable
+ * of add/removing drivers and supplying and managing behaviour
+ * implementations. A default implementation is provided by the framework along
+ * with a {@link org.onosproject.net.driver.XmlDriverLoader loader utility} to
+ * create a driver provider from an XML file structured as follows:
+ * <pre>
+ *     &lt;drivers&gt;
+ *         &lt;driver name=“...” [manufacturer="..." hwVersion="..." swVersion="..."]&gt;
+ *             &lt;behaviour api="..." impl="..."/&gt;
+ *             ...
+ *             [&lt;property name=“key”&gt;value&lt;/key&gt;]
+ *             ...
+ *         &lt;/driver&gt;
+ *         ...
+ *     &lt;/drivers&gt;
+ * </pre>
+ *
+ */
+package org.onosproject.net.driver;
\ No newline at end of file
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
new file mode 100644
index 0000000..40e9bb1
--- /dev/null
+++ b/core/api/src/test/java/org/onosproject/net/driver/DefaultDriverDataTest.java
@@ -0,0 +1,73 @@
+/*
+ * 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;
+
+import com.google.common.collect.ImmutableMap;
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+public class DefaultDriverDataTest {
+
+    DefaultDriver ddc;
+    DefaultDriverData data;
+
+    @Before
+    public void setUp() {
+        ddc = new DefaultDriver("foo.bar", "Circus", "lux", "1.2a",
+                                ImmutableMap.of(TestBehaviour.class,
+                                                TestBehaviourImpl.class),
+                                ImmutableMap.of("foo", "bar"));
+        data = new DefaultDriverData(ddc);
+    }
+
+    @Test
+    public void basics() {
+        assertSame("incorrect type", ddc, data.type());
+        assertTrue("incorrect toString", data.toString().contains("foo.bar"));
+    }
+
+    @Test
+    public void behaviour() {
+        TestBehaviour behaviour = data.behaviour(TestBehaviour.class);
+        assertTrue("incorrect behaviour", behaviour instanceof TestBehaviourImpl);
+    }
+
+    @Test
+    public void setAndClearAnnotations() {
+        data.set("croc", "aqua");
+        data.set("roo", "mars");
+        data.set("dingo", "bat");
+        assertEquals("incorrect property", "bat", data.value("dingo"));
+        data.clear("dingo", "roo");
+        assertNull("incorrect property", data.value("dingo"));
+        assertNull("incorrect property", data.value("root"));
+        assertEquals("incorrect property", "aqua", data.value("croc"));
+        assertEquals("incorrect properties", 1, data.keys().size());
+    }
+
+    @Test
+    public void clearAllAnnotations() {
+        data.set("croc", "aqua");
+        data.set("roo", "mars");
+        data.set("dingo", "bat");
+        assertEquals("incorrect property", "bat", data.value("dingo"));
+        data.clear();
+        assertEquals("incorrect properties", 0, data.keys().size());
+    }
+
+}
\ No newline at end of file
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
new file mode 100644
index 0000000..e9a6165
--- /dev/null
+++ b/core/api/src/test/java/org/onosproject/net/driver/DefaultDriverHandlerTest.java
@@ -0,0 +1,55 @@
+/*
+ * 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;
+
+import com.google.common.collect.ImmutableMap;
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+
+public class DefaultDriverHandlerTest {
+
+    DefaultDriver ddc;
+    DefaultDriverData data;
+    DefaultDriverHandler handler;
+
+    @Before
+    public void setUp() {
+        ddc = new DefaultDriver("foo.bar", "Circus", "lux", "1.2a",
+                                ImmutableMap.of(TestBehaviour.class,
+                                                TestBehaviourImpl.class,
+                                                TestBehaviourTwo.class,
+                                                TestBehaviourTwoImpl.class),
+                                ImmutableMap.of("foo", "bar"));
+        data = new DefaultDriverData(ddc);
+        handler = new DefaultDriverHandler(data);
+    }
+
+    @Test
+    public void basics() {
+        assertSame("incorrect data", data, handler.data());
+        assertTrue("incorrect toString", handler.toString().contains("1.2a"));
+    }
+
+    @Test
+    public void behaviour() {
+        TestBehaviourTwo behaviour = handler.behaviour(TestBehaviourTwo.class);
+        assertTrue("incorrect behaviour", behaviour instanceof TestBehaviourTwoImpl);
+    }
+
+}
\ No newline at end of file
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
new file mode 100644
index 0000000..adfa486
--- /dev/null
+++ b/core/api/src/test/java/org/onosproject/net/driver/DefaultDriverProviderTest.java
@@ -0,0 +1,49 @@
+/*
+ * 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;
+
+import com.google.common.collect.ImmutableMap;
+import org.junit.Test;
+
+import java.util.Set;
+
+import static com.google.common.collect.ImmutableSet.of;
+import static org.junit.Assert.assertEquals;
+
+public class DefaultDriverProviderTest {
+
+    @Test
+    public void basics() {
+        DefaultDriverProvider ddp = new DefaultDriverProvider();
+        DefaultDriver one = new DefaultDriver("foo.bar", "Circus", "lux", "1.2a",
+                                              ImmutableMap.of(TestBehaviour.class,
+                                                              TestBehaviourImpl.class),
+                                              ImmutableMap.of("foo", "bar"));
+        DefaultDriver two = new DefaultDriver("foo.bar", "", "", "",
+                                              ImmutableMap.of(TestBehaviourTwo.class,
+                                                              TestBehaviourTwoImpl.class),
+                                              ImmutableMap.of("goo", "wee"));
+        DefaultDriver three = new DefaultDriver("goo.foo", "BigTop", "better", "2.2",
+                                                ImmutableMap.of(TestBehaviourTwo.class,
+                                                                TestBehaviourTwoImpl.class),
+                                                ImmutableMap.of("goo", "gee"));
+
+        ddp.addDrivers(of(one, two, three));
+
+        Set<Driver> drivers = ddp.getDrivers();
+        assertEquals("incorrect types", 2, drivers.size());
+    }
+}
\ No newline at end of file
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
new file mode 100644
index 0000000..f10602a
--- /dev/null
+++ b/core/api/src/test/java/org/onosproject/net/driver/DefaultDriverTest.java
@@ -0,0 +1,73 @@
+/*
+ * 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;
+
+import com.google.common.collect.ImmutableMap;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+public class DefaultDriverTest {
+
+    @Test
+    public void basics() {
+        DefaultDriver ddc = new DefaultDriver("foo.bar", "Circus", "lux", "1.2a",
+                                              ImmutableMap.of(TestBehaviour.class,
+                                                              TestBehaviourImpl.class),
+                                              ImmutableMap.of("foo", "bar"));
+        assertEquals("incorrect name", "foo.bar", ddc.name());
+        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());
+        assertTrue("incorrect behaviour", ddc.hasBehaviour(TestBehaviour.class));
+
+        assertEquals("incorrect property count", 1, ddc.properties().size());
+        assertEquals("incorrect key count", 1, ddc.keys().size());
+        assertEquals("incorrect property", "bar", ddc.value("foo"));
+
+        assertTrue("incorrect toString", ddc.toString().contains("lux"));
+    }
+
+    @Test
+    public void merge() {
+        DefaultDriver one = new DefaultDriver("foo.bar", "Circus", "lux", "1.2a",
+                                              ImmutableMap.of(TestBehaviour.class,
+                                                              TestBehaviourImpl.class),
+                                              ImmutableMap.of("foo", "bar"));
+        DefaultDriver ddc =
+                one.merge(new DefaultDriver("foo.bar", "", "", "",
+                                            ImmutableMap.of(TestBehaviourTwo.class,
+                                                            TestBehaviourTwoImpl.class),
+                                            ImmutableMap.of("goo", "wee")));
+
+        assertEquals("incorrect name", "foo.bar", ddc.name());
+        assertEquals("incorrect mfr", "Circus", ddc.manufacturer());
+        assertEquals("incorrect hw", "lux", ddc.hwVersion());
+        assertEquals("incorrect sw", "1.2a", ddc.swVersion());
+
+        assertEquals("incorrect behaviour count", 2, ddc.behaviours().size());
+        assertTrue("incorrect behaviour", ddc.hasBehaviour(TestBehaviourTwo.class));
+
+        assertEquals("incorrect property count", 2, ddc.properties().size());
+        assertEquals("incorrect key count", 2, ddc.keys().size());
+        assertEquals("incorrect property", "wee", ddc.value("goo"));
+
+        assertTrue("incorrect toString", ddc.toString().contains("Circus"));
+    }
+}
\ No newline at end of file
diff --git a/core/api/src/test/java/org/onosproject/net/driver/TestBehaviour.java b/core/api/src/test/java/org/onosproject/net/driver/TestBehaviour.java
new file mode 100644
index 0000000..632fae1
--- /dev/null
+++ b/core/api/src/test/java/org/onosproject/net/driver/TestBehaviour.java
@@ -0,0 +1,22 @@
+/*
+ * 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;
+
+/**
+ * Test behaviour.
+ */
+public interface TestBehaviour extends Behaviour {
+}
diff --git a/core/api/src/test/java/org/onosproject/net/driver/TestBehaviourImpl.java b/core/api/src/test/java/org/onosproject/net/driver/TestBehaviourImpl.java
new file mode 100644
index 0000000..ec5c66b
--- /dev/null
+++ b/core/api/src/test/java/org/onosproject/net/driver/TestBehaviourImpl.java
@@ -0,0 +1,22 @@
+/*
+ * 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;
+
+/**
+ * Test behaviour.
+ */
+public class TestBehaviourImpl extends AbstractBehaviour implements TestBehaviour {
+}
diff --git a/core/api/src/test/java/org/onosproject/net/driver/TestBehaviourNoConstructorImpl.java b/core/api/src/test/java/org/onosproject/net/driver/TestBehaviourNoConstructorImpl.java
new file mode 100644
index 0000000..2045236
--- /dev/null
+++ b/core/api/src/test/java/org/onosproject/net/driver/TestBehaviourNoConstructorImpl.java
@@ -0,0 +1,26 @@
+/*
+ * 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;
+
+/**
+ * Bad test behaviour.
+ */
+public final class TestBehaviourNoConstructorImpl
+        extends AbstractBehaviour implements TestBehaviour {
+    private TestBehaviourNoConstructorImpl() {
+
+    }
+}
diff --git a/core/api/src/test/java/org/onosproject/net/driver/TestBehaviourTwo.java b/core/api/src/test/java/org/onosproject/net/driver/TestBehaviourTwo.java
new file mode 100644
index 0000000..3399f00
--- /dev/null
+++ b/core/api/src/test/java/org/onosproject/net/driver/TestBehaviourTwo.java
@@ -0,0 +1,22 @@
+/*
+ * 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;
+
+/**
+ * Test behaviour.
+ */
+public interface TestBehaviourTwo extends HandlerBehaviour {
+}
diff --git a/core/api/src/test/java/org/onosproject/net/driver/TestBehaviourTwoImpl.java b/core/api/src/test/java/org/onosproject/net/driver/TestBehaviourTwoImpl.java
new file mode 100644
index 0000000..502d385
--- /dev/null
+++ b/core/api/src/test/java/org/onosproject/net/driver/TestBehaviourTwoImpl.java
@@ -0,0 +1,22 @@
+/*
+ * 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;
+
+/**
+ * Test behaviour.
+ */
+public class TestBehaviourTwoImpl extends AbstractBehaviour implements TestBehaviourTwo {
+}
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
new file mode 100644
index 0000000..2ad64f5
--- /dev/null
+++ b/core/api/src/test/java/org/onosproject/net/driver/XmlDriverLoaderTest.java
@@ -0,0 +1,73 @@
+/*
+ * 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;
+
+import org.junit.Test;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Tests of the XML driver loader implementation.
+ */
+public class XmlDriverLoaderTest {
+
+    @Test
+    public void basics() throws IOException {
+        XmlDriverLoader loader = new XmlDriverLoader(getClass().getClassLoader());
+        InputStream stream = getClass().getResourceAsStream("drivers.1.xml");
+        DriverProvider provider = loader.loadDrivers(stream);
+        System.out.println(provider);
+        assertEquals("incorrect driver count", 1, provider.getDrivers().size());
+
+        Driver driver = provider.getDrivers().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());
+        assertTrue("incorrect driver behaviour", driver.hasBehaviour(TestBehaviour.class));
+
+        assertEquals("incorrect driver properties", 2, driver.properties().size());
+        assertTrue("incorrect driver property", driver.properties().containsKey("p1"));
+    }
+
+    @Test(expected = IOException.class)
+    public void badXML() throws IOException {
+        XmlDriverLoader loader = new XmlDriverLoader(getClass().getClassLoader());
+        loader.loadDrivers(getClass().getResourceAsStream("drivers.bad.xml"));
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void noClass() throws IOException {
+        XmlDriverLoader loader = new XmlDriverLoader(getClass().getClassLoader());
+        loader.loadDrivers(getClass().getResourceAsStream("drivers.noclass.xml"));
+    }
+
+    @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);
+        Driver driver = provider.getDrivers().iterator().next();
+        driver.createBehaviour(new DefaultDriverData(driver), TestBehaviour.class, false);
+    }
+
+}
\ No newline at end of file
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
new file mode 100644
index 0000000..24b4cf8
--- /dev/null
+++ b/core/api/src/test/resources/org/onosproject/net/driver/drivers.1.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ 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.
+  -->
+<drivers>
+    <driver name="foo.1" 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"/>
+
+        <property name="p1">v1</property>
+        <property name="p2">v2</property>
+    </driver>
+</drivers>
\ No newline at end of file
diff --git a/core/api/src/test/resources/org/onosproject/net/driver/drivers.bad.xml b/core/api/src/test/resources/org/onosproject/net/driver/drivers.bad.xml
new file mode 100644
index 0000000..5815ba3
--- /dev/null
+++ b/core/api/src/test/resources/org/onosproject/net/driver/drivers.bad.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ 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.
+  -->
+<drivers>
+    <driver name="foo.1" manufacturer="Circus" hwVersion="1.2a" swVersion="2.2">
+        <behaviour api="org.onosproject.net.driver.TestBehaviour"
+                   impl="org.onosproject.net.driver.TestBehaviourImpl"/>
+    </driverXXXXX> <!-- intentional to test handling malformed XML -->
+</drivers>
\ No newline at end of file
diff --git a/core/api/src/test/resources/org/onosproject/net/driver/drivers.noclass.xml b/core/api/src/test/resources/org/onosproject/net/driver/drivers.noclass.xml
new file mode 100644
index 0000000..e46b42e
--- /dev/null
+++ b/core/api/src/test/resources/org/onosproject/net/driver/drivers.noclass.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ 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.
+  -->
+<drivers>
+    <driver name="foo.1" manufacturer="Circus" hwVersion="1.2a" swVersion="2.2">
+        <behaviour api="org.onosproject.net.driver.TestBehaviourXX"
+                   impl="org.onosproject.net.driver.TestBehaviourImpl"/>
+    </driver>
+</drivers>
\ No newline at end of file
diff --git a/core/api/src/test/resources/org/onosproject/net/driver/drivers.noconstructor.xml b/core/api/src/test/resources/org/onosproject/net/driver/drivers.noconstructor.xml
new file mode 100644
index 0000000..873656d
--- /dev/null
+++ b/core/api/src/test/resources/org/onosproject/net/driver/drivers.noconstructor.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ 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.
+  -->
+<drivers>
+    <driver name="foo.1" manufacturer="Circus" hwVersion="1.2a" swVersion="2.2">
+        <behaviour api="org.onosproject.net.driver.TestBehaviour"
+                   impl="org.onosproject.net.driver.TestBehaviourNoConstructorImpl"/>
+    </driver>
+</drivers>
\ No newline at end of file
diff --git a/features/features.xml b/features/features.xml
index cbf4352..865e51b 100644
--- a/features/features.xml
+++ b/features/features.xml
@@ -51,6 +51,9 @@
         <bundle>mvn:com.fasterxml.jackson.core/jackson-annotations/2.4.2</bundle>
         <bundle>mvn:com.fasterxml.jackson.core/jackson-databind/2.4.2</bundle>
 
+        <bundle>mvn:commons-configuration/commons-configuration/1.10</bundle>
+        <bundle>mvn:commons-collections/commons-collections/3.2.1</bundle>
+
         <!-- FIXME: we should switch to use fasterxml jackson -->
         <bundle>mvn:org.codehaus.jackson/jackson-core-asl/1.9.13</bundle>
         <bundle>mvn:org.codehaus.jackson/jackson-mapper-asl/1.9.13</bundle>
diff --git a/pom.xml b/pom.xml
index 828317b..93818da 100644
--- a/pom.xml
+++ b/pom.xml
@@ -54,7 +54,8 @@
 
     <scm>
         <connection>scm:git:https://gerrit.onosproject.org/onos</connection>
-        <developerConnection>scm:git:https://gerrit.onosproject.org/onos</developerConnection>
+        <developerConnection>scm:git:https://gerrit.onosproject.org/onos
+        </developerConnection>
         <url>http://gerrit.onosproject.org/</url>
     </scm>
 
@@ -166,6 +167,12 @@
             </dependency>
 
             <dependency>
+                <groupId>commons-configuration</groupId>
+                <artifactId>commons-configuration</artifactId>
+                <version>1.10</version>
+            </dependency>
+
+            <dependency>
                 <groupId>org.codehaus.jackson</groupId>
                 <artifactId>jackson-core-asl</artifactId>
                 <version>1.9.13</version>
@@ -417,7 +424,8 @@
                         <redirectTestOutputToFile>true
                         </redirectTestOutputToFile>
                         <printSummary>true</printSummary>
-                        <excludedGroups>org.onlab.junit.IntegrationTest</excludedGroups>
+                        <excludedGroups>org.onlab.junit.IntegrationTest
+                        </excludedGroups>
                     </configuration>
                 </plugin>
 
@@ -474,20 +482,21 @@
                     </configuration>
                 </plugin>
                 <plugin>
-                  <groupId>org.codehaus.mojo</groupId>
-                  <artifactId>findbugs-maven-plugin</artifactId>
-                  <version>3.0.0</version>
-                  <dependencies>
-                    <dependency>
-                      <groupId>org.onosproject</groupId>
-                      <artifactId>onos-build-conf</artifactId>
-                      <version>1.0</version>
-                    </dependency>
-                  </dependencies>
-                  <configuration>
-                    <effort>Max</effort>
-                    <excludeFilterFile>onos/findbugs-suppressions.xml</excludeFilterFile>
-                  </configuration>
+                    <groupId>org.codehaus.mojo</groupId>
+                    <artifactId>findbugs-maven-plugin</artifactId>
+                    <version>3.0.0</version>
+                    <dependencies>
+                        <dependency>
+                            <groupId>org.onosproject</groupId>
+                            <artifactId>onos-build-conf</artifactId>
+                            <version>1.0</version>
+                        </dependency>
+                    </dependencies>
+                    <configuration>
+                        <effort>Max</effort>
+                        <excludeFilterFile>onos/findbugs-suppressions.xml
+                        </excludeFilterFile>
+                    </configuration>
                 </plugin>
 
                 <!-- TODO: add findbugs plugin for static code analysis; for explicit invocation only -->
@@ -550,8 +559,10 @@
                 </dependencies>
                 <configuration>
                     <!-- begin: workaround for unexpected NullPointerException on Eclipse -->
-                    <sourceDirectory>${project.build.sourceDirectory}</sourceDirectory>
-                    <testSourceDirectory>${project.build.testSourceDirectory}</testSourceDirectory>
+                    <sourceDirectory>${project.build.sourceDirectory}
+                    </sourceDirectory>
+                    <testSourceDirectory>${project.build.testSourceDirectory}
+                    </testSourceDirectory>
                     <!-- end: workaround for unexpected NullPointerException on Eclipse -->
                     <configLocation>onos/checkstyle.xml</configLocation>
                     <suppressionsLocation>onos/suppressions.xml