Adding device driver inheritance mechanism.
Change-Id: I9c883d32ce0c39f961eddd5c4624dc23f794fe4d
diff --git a/core/api/src/main/java/org/onosproject/net/driver/DefaultDriver.java b/core/api/src/main/java/org/onosproject/net/driver/DefaultDriver.java
index 84da212..5c6a08b 100644
--- a/core/api/src/main/java/org/onosproject/net/driver/DefaultDriver.java
+++ b/core/api/src/main/java/org/onosproject/net/driver/DefaultDriver.java
@@ -19,6 +19,7 @@
import com.google.common.collect.Maps;
import java.util.Map;
+import java.util.Objects;
import java.util.Set;
import static com.google.common.base.MoreObjects.toStringHelper;
@@ -32,6 +33,7 @@
public class DefaultDriver implements Driver {
private final String name;
+ private final Driver parent;
private final String manufacturer;
private final String hwVersion;
@@ -40,22 +42,23 @@
private final Map<Class<? extends Behaviour>, Class<? extends Behaviour>> behaviours;
private final Map<String, String> properties;
-
/**
* Creates a driver with the specified name.
*
* @param name driver name
+ * @param parent optional parent driver
* @param manufacturer device manufacturer
* @param hwVersion device hardware version
* @param swVersion device software version
* @param behaviours device behaviour classes
* @param properties properties for configuration of device behaviour classes
*/
- public DefaultDriver(String name, String manufacturer,
+ public DefaultDriver(String name, Driver parent, String manufacturer,
String hwVersion, String swVersion,
Map<Class<? extends Behaviour>, Class<? extends Behaviour>> behaviours,
Map<String, String> properties) {
this.name = checkNotNull(name, "Name cannot be null");
+ this.parent = parent;
this.manufacturer = checkNotNull(manufacturer, "Manufacturer cannot be null");
this.hwVersion = checkNotNull(hwVersion, "HW version cannot be null");
this.swVersion = checkNotNull(swVersion, "SW version cannot be null");
@@ -65,6 +68,9 @@
@Override
public Driver merge(Driver other) {
+ checkArgument(parent == null || Objects.equals(parent, other.parent()),
+ "Parent drivers are not the same");
+
// Merge the behaviours.
Map<Class<? extends Behaviour>, Class<? extends Behaviour>>
behaviours = Maps.newHashMap();
@@ -75,7 +81,7 @@
ImmutableMap.Builder<String, String> properties = ImmutableMap.builder();
properties.putAll(this.properties).putAll(other.properties());
- return new DefaultDriver(name, manufacturer, hwVersion, swVersion,
+ return new DefaultDriver(name, other.parent(), manufacturer, hwVersion, swVersion,
ImmutableMap.copyOf(behaviours), properties.build());
}
@@ -100,6 +106,11 @@
}
@Override
+ public Driver parent() {
+ return parent;
+ }
+
+ @Override
public Set<Class<? extends Behaviour>> behaviours() {
return behaviours.keySet();
}
@@ -111,19 +122,32 @@
@Override
public boolean hasBehaviour(Class<? extends Behaviour> behaviourClass) {
- return behaviours.containsKey(behaviourClass);
+ return behaviours.containsKey(behaviourClass) ||
+ (parent != null && parent.hasBehaviour(behaviourClass));
}
@Override
public <T extends Behaviour> T createBehaviour(DriverData data,
Class<T> behaviourClass) {
- return createBehaviour(data, null, behaviourClass);
+ T behaviour = createBehaviour(data, null, behaviourClass);
+ if (behaviour != null) {
+ return behaviour;
+ } else if (parent != null) {
+ return parent.createBehaviour(data, behaviourClass);
+ }
+ throw new IllegalArgumentException(behaviourClass.getName() + " not supported");
}
@Override
public <T extends Behaviour> T createBehaviour(DriverHandler handler,
Class<T> behaviourClass) {
- return createBehaviour(handler.data(), handler, behaviourClass);
+ T behaviour = createBehaviour(handler.data(), handler, behaviourClass);
+ if (behaviour != null) {
+ return behaviour;
+ } else if (parent != null) {
+ return parent.createBehaviour(handler, behaviourClass);
+ }
+ throw new IllegalArgumentException(behaviourClass.getName() + " not supported");
}
// Creates an instance of behaviour primed with the specified driver data.
@@ -134,17 +158,18 @@
// Locate the implementation of the requested behaviour.
Class<? extends Behaviour> implementation = behaviours.get(behaviourClass);
- checkArgument(implementation != null, "{} not supported", behaviourClass.getName());
+ if (implementation != null) {
+ // Create an instance of the behaviour and apply data as its context.
+ T behaviour = createBehaviour(behaviourClass, implementation);
+ behaviour.setData(data);
- // Create an instance of the behaviour and apply data as its context.
- T behaviour = createBehaviour(behaviourClass, implementation);
- behaviour.setData(data);
-
- // If this is a handler behaviour, also apply handler as its context.
- if (handler != null) {
- ((HandlerBehaviour) behaviour).setHandler(handler);
+ // If this is a handler behaviour, also apply handler as its context.
+ if (handler != null) {
+ ((HandlerBehaviour) behaviour).setHandler(handler);
+ }
+ return behaviour;
}
- return behaviour;
+ return null;
}
@SuppressWarnings("unchecked")
@@ -177,6 +202,7 @@
public String toString() {
return toStringHelper(this)
.add("name", name)
+ .add("parent", parent)
.add("manufacturer", manufacturer)
.add("hwVersion", hwVersion)
.add("swVersion", swVersion)
diff --git a/core/api/src/main/java/org/onosproject/net/driver/Driver.java b/core/api/src/main/java/org/onosproject/net/driver/Driver.java
index 8c13f36..50611b1 100644
--- a/core/api/src/main/java/org/onosproject/net/driver/Driver.java
+++ b/core/api/src/main/java/org/onosproject/net/driver/Driver.java
@@ -35,6 +35,14 @@
String name();
/**
+ * Returns the parent driver from which this driver inherits behaviours
+ * and properties.
+ *
+ * @return parent driver; null if driver has no parent
+ */
+ Driver parent();
+
+ /**
* Returns the device manufacturer name.
*
* @return manufacturer name
@@ -57,6 +65,7 @@
/**
* Returns the set of behaviours supported by this driver.
+ * It reflects behaviours of only this driver and not its parent.
*
* @return set of device driver behaviours
*/
@@ -64,6 +73,7 @@
/**
* Returns the implementation class for the specified behaviour.
+ * It reflects behaviours of only this driver and not its parent.
*
* @param behaviour behaviour interface
* @return implementation class
@@ -71,8 +81,8 @@
Class<? extends Behaviour> implementation(Class<? extends Behaviour> behaviour);
/**
- * Indicates whether or not the driver supports the specified class
- * of behaviour.
+ * Indicates whether or not the driver, or any of its parents, support
+ * the specified class of behaviour. It
*
* @param behaviourClass behaviour class
* @return true if behaviour is supported
@@ -81,6 +91,8 @@
/**
* Creates an instance of behaviour primed with the specified driver data.
+ * If the current driver does not support the specified behaviour and the
+ * driver has parent, the request is delegated to the parent driver.
*
* @param data driver data context
* @param behaviourClass driver behaviour class
@@ -91,6 +103,8 @@
/**
* Creates an instance of behaviour primed with the specified driver data.
+ * If the current driver does not support the specified behaviour and the
+ * driver has parent, the request is delegated to the parent driver.
*
* @param handler driver handler context
* @param behaviourClass driver behaviour class
diff --git a/core/api/src/main/java/org/onosproject/net/driver/DriverResolver.java b/core/api/src/main/java/org/onosproject/net/driver/DriverResolver.java
new file mode 100644
index 0000000..094c710
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/driver/DriverResolver.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.net.driver;
+
+/**
+ * Entity capable of resolving a driver using its name.
+ */
+public interface DriverResolver {
+
+ /**
+ * Returns the specified driver.
+ *
+ * @param driverName driver name
+ * @return driver
+ * @throws org.onlab.util.ItemNotFoundException if driver with the given
+ * name is not found
+ */
+ Driver getDriver(String driverName);
+
+}
diff --git a/core/api/src/main/java/org/onosproject/net/driver/DriverService.java b/core/api/src/main/java/org/onosproject/net/driver/DriverService.java
index fa37f1b..1a74255 100644
--- a/core/api/src/main/java/org/onosproject/net/driver/DriverService.java
+++ b/core/api/src/main/java/org/onosproject/net/driver/DriverService.java
@@ -22,7 +22,7 @@
/**
* Service for obtaining drivers and driver behaviour implementations.
*/
-public interface DriverService {
+public interface DriverService extends DriverResolver {
/**
* Returns the overall set of drivers being provided.
@@ -40,16 +40,6 @@
Set<Driver> getDrivers(Class<? extends Behaviour> withBehaviour);
/**
- * Returns the specified driver.
- *
- * @param driverName driver name
- * @return driver
- * @throws org.onlab.util.ItemNotFoundException if driver with the given
- * name is not found
- */
- Driver getDriver(String driverName);
-
- /**
* Returns the driver that matches the specified primordial device
* discovery information.
*
diff --git a/core/api/src/main/java/org/onosproject/net/driver/XmlDriverLoader.java b/core/api/src/main/java/org/onosproject/net/driver/XmlDriverLoader.java
index c3bb7ac..fc5e04a 100644
--- a/core/api/src/main/java/org/onosproject/net/driver/XmlDriverLoader.java
+++ b/core/api/src/main/java/org/onosproject/net/driver/XmlDriverLoader.java
@@ -16,6 +16,7 @@
package org.onosproject.net.driver;
import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Maps;
import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.configuration.HierarchicalConfiguration;
import org.apache.commons.configuration.XMLConfiguration;
@@ -51,6 +52,7 @@
private static final String PROPERTY = "property";
private static final String NAME = "[@name]";
+ private static final String EXTENDS = "[@extends]";
private static final String MFG = "[@manufacturer]";
private static final String HW = "[@hwVersion]";
private static final String SW = "[@swVersion]";
@@ -59,6 +61,8 @@
private final ClassLoader classLoader;
+ private Map<String, Driver> drivers = Maps.newHashMap();
+
/**
* Creates a new driver loader capable of loading drivers from the supplied
* class loader.
@@ -74,18 +78,20 @@
* produce a ready-to-register driver provider.
*
* @param driversStream stream containing the drivers definitions
+ * @param resolver driver resolver
* @return driver provider
* @throws java.io.IOException if issues are encountered reading the stream
* or parsing the driver definitions within
*/
- public DefaultDriverProvider loadDrivers(InputStream driversStream) throws IOException {
+ public DefaultDriverProvider loadDrivers(InputStream driversStream,
+ DriverResolver resolver) throws IOException {
try {
XMLConfiguration cfg = new XMLConfiguration();
cfg.setRootElementName(DRIVERS);
cfg.setAttributeSplittingDisabled(true);
cfg.load(driversStream);
- return loadDrivers(cfg);
+ return loadDrivers(cfg, resolver);
} catch (ConfigurationException e) {
throw new IOException("Unable to load drivers", e);
}
@@ -95,13 +101,18 @@
* Loads a driver provider from the supplied hierarchical configuration.
*
* @param driversCfg hierarchical configuration containing the drivers definitions
+ * @param resolver driver resolver
* @return driver provider
*/
- public DefaultDriverProvider loadDrivers(HierarchicalConfiguration driversCfg) {
+ public DefaultDriverProvider loadDrivers(HierarchicalConfiguration driversCfg,
+ DriverResolver resolver) {
DefaultDriverProvider provider = new DefaultDriverProvider();
for (HierarchicalConfiguration cfg : driversCfg.configurationsAt(DRIVER)) {
- provider.addDriver(loadDriver(cfg));
+ DefaultDriver driver = loadDriver(cfg, resolver);
+ drivers.put(driver.name(), driver);
+ provider.addDriver(driver);
}
+ drivers.clear();
return provider;
}
@@ -109,19 +120,30 @@
* Loads a driver from the supplied hierarchical configuration.
*
* @param driverCfg hierarchical configuration containing the driver definition
+ * @param resolver driver resolver
* @return driver
*/
- public DefaultDriver loadDriver(HierarchicalConfiguration driverCfg) {
+ public DefaultDriver loadDriver(HierarchicalConfiguration driverCfg,
+ DriverResolver resolver) {
String name = driverCfg.getString(NAME);
+ String parentName = driverCfg.getString(EXTENDS);
String manufacturer = driverCfg.getString(MFG, "");
String hwVersion = driverCfg.getString(HW, "");
String swVersion = driverCfg.getString(SW, "");
- return new DefaultDriver(name, manufacturer, hwVersion, swVersion,
+ Driver parent = parentName != null ? resolve(parentName, resolver) : null;
+ return new DefaultDriver(name, parent, manufacturer, hwVersion, swVersion,
parseBehaviours(driverCfg),
parseProperties(driverCfg));
}
+ // Resolves the driver by name locally at first and then using the specified resolver.
+ private Driver resolve(String parentName, DriverResolver resolver) {
+ Driver driver = drivers.get(parentName);
+ return driver != null ? driver :
+ (resolver != null ? resolver.getDriver(parentName) : null);
+ }
+
// Parses the behaviours section.
private Map<Class<? extends Behaviour>, Class<? extends Behaviour>>
parseBehaviours(HierarchicalConfiguration driverCfg) {