Adding ability to project device, link and host model as alternate entities.
Change-Id: If23c018b024a3bbe693f0e66888c5f1707e3f66d
diff --git a/core/api/src/main/java/org/onosproject/net/AbstractElement.java b/core/api/src/main/java/org/onosproject/net/AbstractElement.java
index 595e7b9..79170f9 100644
--- a/core/api/src/main/java/org/onosproject/net/AbstractElement.java
+++ b/core/api/src/main/java/org/onosproject/net/AbstractElement.java
@@ -20,7 +20,7 @@
/**
* Base implementation of network elements, i.e. devices or hosts.
*/
-public abstract class AbstractElement extends AbstractModel implements Element {
+public abstract class AbstractElement extends AbstractProjectableModel implements Element {
protected final ElementId id;
diff --git a/core/api/src/main/java/org/onosproject/net/AbstractProjectableModel.java b/core/api/src/main/java/org/onosproject/net/AbstractProjectableModel.java
new file mode 100644
index 0000000..6fee974
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/AbstractProjectableModel.java
@@ -0,0 +1,185 @@
+/*
+ * Copyright 2014-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;
+
+import com.google.common.annotations.Beta;
+import org.onlab.util.ItemNotFoundException;
+import org.onosproject.net.driver.Behaviour;
+import org.onosproject.net.driver.Driver;
+import org.onosproject.net.driver.DriverData;
+import org.onosproject.net.driver.DriverService;
+import org.onosproject.net.driver.Projectable;
+import org.onosproject.net.provider.ProviderId;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Set;
+
+import static com.google.common.base.Preconditions.checkState;
+
+/**
+ * Base model entity, capable of being extended via projection mechanism.
+ */
+@Beta
+public abstract class AbstractProjectableModel extends AbstractModel implements Projectable {
+
+ private static Logger log = LoggerFactory.getLogger(AbstractProjectableModel.class);
+
+ protected static final String NO_DRIVER_SERVICE = "Driver service not bound yet";
+ protected static final String NO_DRIVER = "Driver has not been bound to %s";
+
+ // Static reference to the driver service; injected via setDriverService
+ private static DriverService driverService;
+
+ private Driver driver;
+
+ // For serialization
+ public AbstractProjectableModel() {
+ }
+
+ /**
+ * Creates a model entity attributed to the specified provider and
+ * optionally annotated.
+ *
+ * @param providerId identity of the provider
+ * @param annotations optional key/value annotations
+ */
+ public AbstractProjectableModel(ProviderId providerId, Annotations[] annotations) {
+ super(providerId, annotations);
+ }
+
+ /**
+ * Injects the driver service reference for use during projections into
+ * various behaviours.
+ * <p>
+ * This is a privileged call; unauthorized invocations will result in
+ * illegal state exception
+ *
+ * @param key opaque admin key object
+ * @param driverService injected driver service
+ * @throws IllegalStateException when invoked sans authorization
+ */
+ public static void setDriverService(Object key, DriverService driverService) {
+ // TODO: Rework this once we have means to enforce access to admin services in general
+ checkState(AbstractProjectableModel.driverService == key, "Unauthorized invocation");
+ AbstractProjectableModel.driverService = driverService;
+ }
+
+ /**
+ * Returns the currently bound driver service reference.
+ *
+ * @return driver service
+ */
+ protected static DriverService driverService() {
+ return driverService;
+ }
+
+ /**
+ * Returns the currently bound driver or null of no driver is bound.
+ *
+ * @return bound driver; null if none
+ */
+ protected Driver driver() {
+ return driver;
+ }
+
+ @Override
+ public <B extends Behaviour> B as(Class<B> projectionClass) {
+ checkState(driverService != null, NO_DRIVER_SERVICE);
+ if (driver == null) {
+ driver = locateDriver();
+ }
+ checkState(driver != null, NO_DRIVER, this);
+ return driver.createBehaviour(asData(), projectionClass);
+ }
+
+ @Override
+ public <B extends Behaviour> boolean is(Class<B> projectionClass) {
+ checkState(driverService != null, NO_DRIVER_SERVICE);
+ if (driver == null) {
+ driver = locateDriver();
+ }
+ checkState(driver != null, "Driver has not been bound to %s", this);
+ return driver.hasBehaviour(projectionClass);
+ }
+
+ /**
+ * Locates the driver to be used by this entity.
+ * <p>
+ * The default implementation derives the driver based on the {@code driver}
+ * annotation value.
+ *
+ * @return driver for alternate projections of this model entity or null
+ * if no driver is expected or driver is not found
+ */
+ protected Driver locateDriver() {
+ String driverName = annotations().value(AnnotationKeys.DRIVER);
+ if (driverName != null) {
+ try {
+ return driverService.getDriver(driverName);
+ } catch (ItemNotFoundException e) {
+ log.warn("Driver {} not found.", driverName);
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns self as an immutable driver data instance.
+ *
+ * @return self as driver data
+ */
+ protected DriverData asData() {
+ return new AnnotationDriverData();
+ }
+
+
+ /**
+ * Projection of the parent entity as a driver data entity.
+ */
+ protected class AnnotationDriverData implements DriverData {
+ @Override
+ public Driver driver() {
+ return driver;
+ }
+
+ @Override
+ public DeviceId deviceId() {
+ throw new UnsupportedOperationException("Entity not a device");
+ }
+
+ @Override
+ public MutableAnnotations set(String key, String value) {
+ throw new UnsupportedOperationException("Entity is immutable");
+ }
+
+ @Override
+ public MutableAnnotations clear(String... keys) {
+ throw new UnsupportedOperationException("Entity is immutable");
+ }
+
+ @Override
+ public Set<String> keys() {
+ return annotations().keys();
+ }
+
+ @Override
+ public String value(String key) {
+ return annotations().value(key);
+ }
+ }
+
+}
diff --git a/core/api/src/main/java/org/onosproject/net/DefaultDevice.java b/core/api/src/main/java/org/onosproject/net/DefaultDevice.java
index f3f0fe7..401740a 100644
--- a/core/api/src/main/java/org/onosproject/net/DefaultDevice.java
+++ b/core/api/src/main/java/org/onosproject/net/DefaultDevice.java
@@ -15,12 +15,15 @@
*/
package org.onosproject.net;
-import org.onosproject.net.provider.ProviderId;
import org.onlab.packet.ChassisId;
+import org.onosproject.net.driver.Driver;
+import org.onosproject.net.driver.DriverData;
+import org.onosproject.net.provider.ProviderId;
import java.util.Objects;
import static com.google.common.base.MoreObjects.toStringHelper;
+import static org.onlab.util.Tools.nullIsNotFound;
/**
* Default infrastructure device model implementation.
@@ -105,6 +108,33 @@
return chassisId;
}
+ /**
+ * Returns self as an immutable driver data instance.
+ *
+ * @return self as driver data
+ */
+ protected DriverData asData() {
+ return new DeviceDriverData();
+ }
+
+ @Override
+ protected Driver locateDriver() {
+ Driver driver = super.locateDriver();
+ return driver != null ? driver :
+ nullIsNotFound(driverService().getDriver(manufacturer, hwVersion, swVersion),
+ "Driver not found");
+ }
+
+ /**
+ * Projection of the parent entity as a driver data entity.
+ */
+ protected class DeviceDriverData extends AnnotationDriverData {
+ @Override
+ public DeviceId deviceId() {
+ return id();
+ }
+ }
+
@Override
public int hashCode() {
return Objects.hash(id, type, manufacturer, hwVersion, swVersion, serialNumber);
@@ -136,6 +166,7 @@
.add("hwVersion", hwVersion)
.add("swVersion", swVersion)
.add("serialNumber", serialNumber)
+ .add("driver", driver() != null ? driver().name() : "")
.toString();
}
diff --git a/core/api/src/main/java/org/onosproject/net/DefaultLink.java b/core/api/src/main/java/org/onosproject/net/DefaultLink.java
index 1876db6..5515175 100644
--- a/core/api/src/main/java/org/onosproject/net/DefaultLink.java
+++ b/core/api/src/main/java/org/onosproject/net/DefaultLink.java
@@ -24,11 +24,10 @@
import static org.onosproject.net.DefaultAnnotations.EMPTY;
import static com.google.common.base.Preconditions.checkNotNull;
-
/**
* Default infrastructure link model implementation.
*/
-public class DefaultLink extends AbstractModel implements Link {
+public class DefaultLink extends AbstractProjectableModel implements Link {
private final ConnectPoint src;
private final ConnectPoint dst;
@@ -60,7 +59,7 @@
* @param dst link destination
* @param type link type
* @param state link state
- * @param isExpected indicates if the link is preconfigured
+ * @param isExpected indicates if the link is preconfigured
* @param annotations optional key/value annotations
*/
private DefaultLink(ProviderId providerId, ConnectPoint src, ConnectPoint dst,
diff --git a/core/api/src/main/java/org/onosproject/net/Element.java b/core/api/src/main/java/org/onosproject/net/Element.java
index 6cdab9e..b918ad9 100644
--- a/core/api/src/main/java/org/onosproject/net/Element.java
+++ b/core/api/src/main/java/org/onosproject/net/Element.java
@@ -15,10 +15,12 @@
*/
package org.onosproject.net;
+import org.onosproject.net.driver.Projectable;
+
/**
* Base abstraction of a network element, i.e. an infrastructure device or an end-station host.
*/
-public interface Element extends Annotated, Provided {
+public interface Element extends Annotated, Provided, Projectable {
/**
* Returns the network element identifier.
diff --git a/core/api/src/main/java/org/onosproject/net/Link.java b/core/api/src/main/java/org/onosproject/net/Link.java
index eb09290..9209138 100644
--- a/core/api/src/main/java/org/onosproject/net/Link.java
+++ b/core/api/src/main/java/org/onosproject/net/Link.java
@@ -15,10 +15,12 @@
*/
package org.onosproject.net;
+import org.onosproject.net.driver.Projectable;
+
/**
* Abstraction of a network infrastructure link.
*/
-public interface Link extends Annotated, Provided, NetworkResource {
+public interface Link extends Annotated, Provided, Projectable, NetworkResource {
/**
* Coarse representation of the link type.
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
index 784e6c5..6bb246b 100644
--- a/core/api/src/main/java/org/onosproject/net/driver/AbstractBehaviour.java
+++ b/core/api/src/main/java/org/onosproject/net/driver/AbstractBehaviour.java
@@ -18,7 +18,7 @@
import static com.google.common.base.Preconditions.checkState;
/**
- * Base implementation of device driver behaviour.
+ * Base implementation of a driver behaviour.
*/
public class AbstractBehaviour implements Behaviour {
diff --git a/core/api/src/main/java/org/onosproject/net/driver/AbstractHandlerBehaviour.java b/core/api/src/main/java/org/onosproject/net/driver/AbstractHandlerBehaviour.java
index 66b21ff..2ba8f87 100644
--- a/core/api/src/main/java/org/onosproject/net/driver/AbstractHandlerBehaviour.java
+++ b/core/api/src/main/java/org/onosproject/net/driver/AbstractHandlerBehaviour.java
@@ -18,7 +18,7 @@
import static com.google.common.base.Preconditions.checkState;
/**
- * Base implementation of device driver handler behaviour.
+ * Base implementation of a driver handler behaviour.
*/
public class AbstractHandlerBehaviour
extends AbstractBehaviour implements HandlerBehaviour {
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
index 6e28aa8..49a984e 100644
--- a/core/api/src/main/java/org/onosproject/net/driver/Behaviour.java
+++ b/core/api/src/main/java/org/onosproject/net/driver/Behaviour.java
@@ -16,8 +16,8 @@
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
+ * Representation of a facet of behaviour that can be used to talk about
+ * an entity (in context of {@link DriverData}) or to an entity (in context of
* {@link DriverHandler}).
*/
public interface Behaviour {
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
index 76d7932..3ea3bb9 100644
--- a/core/api/src/main/java/org/onosproject/net/driver/DefaultDriverData.java
+++ b/core/api/src/main/java/org/onosproject/net/driver/DefaultDriverData.java
@@ -57,11 +57,6 @@
}
@Override
- public <T extends Behaviour> T behaviour(Class<T> behaviourClass) {
- return driver.createBehaviour(this, behaviourClass);
- }
-
- @Override
public MutableAnnotations set(String key, String value) {
properties.put(key, value);
return this;
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
index 64f1fd9..8f0eb97 100644
--- a/core/api/src/main/java/org/onosproject/net/driver/DriverData.java
+++ b/core/api/src/main/java/org/onosproject/net/driver/DriverData.java
@@ -19,7 +19,7 @@
import org.onosproject.net.MutableAnnotations;
/**
- * Container for data about a device. Data is stored using
+ * Container for data about an entity, e.g. device, link. Data is stored using
* {@link org.onosproject.net.MutableAnnotations}.
*
* Note that only derivatives of {@link HandlerBehaviour} can expect mutability
@@ -45,10 +45,15 @@
/**
* Returns the specified facet of behaviour to access the device data.
*
+ * Implementations are expected to defer to the backing driver for creation
+ * of the requested behaviour.
+ *
* @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);
+ default <T extends Behaviour> T behaviour(Class<T> behaviourClass) {
+ return driver().createBehaviour(this, behaviourClass);
+ }
}
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
index b5771ac..c3bff33 100644
--- a/core/api/src/main/java/org/onosproject/net/driver/HandlerBehaviour.java
+++ b/core/api/src/main/java/org/onosproject/net/driver/HandlerBehaviour.java
@@ -16,8 +16,8 @@
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}).
+ * Representation of a facet of behaviour that can be used to interact
+ * with an entity (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/Projectable.java b/core/api/src/main/java/org/onosproject/net/driver/Projectable.java
index 02dce7e..9cff6b4 100644
--- a/core/api/src/main/java/org/onosproject/net/driver/Projectable.java
+++ b/core/api/src/main/java/org/onosproject/net/driver/Projectable.java
@@ -38,7 +38,7 @@
* Returns true if this entity is capable of being projected as the
* specified class.
*
- * @param projectionClass projection class
+ * @param projectionClass requested projection class
* @param <B> type of behaviour
* @return true if the requested projection is supported
*/
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
index fbc39a8..8306dfa 100644
--- 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
@@ -16,21 +16,23 @@
/**
* 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.
+ * device specific behaviours and to allow modeling device (and other entity)
+ * behaviours while hiding details of specific driver implementations.
+ * While primarily intended for devices, this subsystem can be used to abstract
+ * behaviours of other entities as well.
* <p>
* {@link org.onosproject.net.driver.Driver} is a representation of a
- * specific family of devices supports set of
+ * specific family of entities (devices, links, etc.) which 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
+ * learned about an entity. 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
+ * for talking about an entity. 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>