implemented annotation merging on SimpleDeviceStore.
- Added annotation support to PortsDescriptions
Change-Id: I157e4fb93b8f387b405722b8d004501d993decda
diff --git a/core/store/trivial/src/main/java/org/onlab/onos/store/trivial/impl/SimpleDeviceStore.java b/core/store/trivial/src/main/java/org/onlab/onos/store/trivial/impl/SimpleDeviceStore.java
index bc0a055..0b0ae37 100644
--- a/core/store/trivial/src/main/java/org/onlab/onos/store/trivial/impl/SimpleDeviceStore.java
+++ b/core/store/trivial/src/main/java/org/onlab/onos/store/trivial/impl/SimpleDeviceStore.java
@@ -9,6 +9,8 @@
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
import org.apache.felix.scr.annotations.Service;
+import org.onlab.onos.net.Annotations;
+import org.onlab.onos.net.DefaultAnnotations;
import org.onlab.onos.net.DefaultDevice;
import org.onlab.onos.net.DefaultPort;
import org.onlab.onos.net.Device;
@@ -16,6 +18,9 @@
import org.onlab.onos.net.DeviceId;
import org.onlab.onos.net.Port;
import org.onlab.onos.net.PortNumber;
+import org.onlab.onos.net.SparseAnnotations;
+import org.onlab.onos.net.device.DefaultDeviceDescription;
+import org.onlab.onos.net.device.DefaultPortDescription;
import org.onlab.onos.net.device.DeviceDescription;
import org.onlab.onos.net.device.DeviceEvent;
import org.onlab.onos.net.device.DeviceStore;
@@ -45,6 +50,7 @@
import static org.onlab.onos.net.device.DeviceEvent.Type.*;
import static org.slf4j.LoggerFactory.getLogger;
import static org.apache.commons.lang3.concurrent.ConcurrentUtils.createIfAbsentUnchecked;
+import static org.onlab.onos.net.DefaultAnnotations.merge;
// TODO: synchronization should be done in more fine-grained manner.
/**
@@ -112,8 +118,8 @@
= createIfAbsentUnchecked(providerDescs, providerId,
new InitDeviceDescs(deviceDescription));
+ // update description
descs.putDeviceDesc(deviceDescription);
-
Device newDevice = composeDevice(deviceId, providerDescs);
if (oldDevice == null) {
@@ -144,7 +150,8 @@
// We allow only certain attributes to trigger update
if (!Objects.equals(oldDevice.hwVersion(), newDevice.hwVersion()) ||
- !Objects.equals(oldDevice.swVersion(), newDevice.swVersion())) {
+ !Objects.equals(oldDevice.swVersion(), newDevice.swVersion()) ||
+ !isAnnotationsEqual(oldDevice.annotations(), newDevice.annotations())) {
synchronized (this) {
devices.replace(newDevice.id(), oldDevice, newDevice);
@@ -203,7 +210,7 @@
PortNumber number = portDescription.portNumber();
Port oldPort = ports.get(number);
// update description
- descs.putPortDesc(number, portDescription);
+ descs.putPortDesc(portDescription);
Port newPort = composePort(device, number, descsMap);
events.add(oldPort == null ?
@@ -225,12 +232,14 @@
return new DeviceEvent(PORT_ADDED, device, newPort);
}
- // CHecks if the specified port requires update and if so, it replaces the
+ // Checks if the specified port requires update and if so, it replaces the
// existing entry in the map and returns corresponding event.
private DeviceEvent updatePort(Device device, Port oldPort,
Port newPort,
ConcurrentMap<PortNumber, Port> ports) {
- if (oldPort.isEnabled() != newPort.isEnabled()) {
+ if (oldPort.isEnabled() != newPort.isEnabled() ||
+ !isAnnotationsEqual(oldPort.annotations(), newPort.annotations())) {
+
ports.put(oldPort.number(), newPort);
return new DeviceEvent(PORT_UPDATED, device, newPort);
}
@@ -272,17 +281,17 @@
checkArgument(descsMap != null, DEVICE_NOT_FOUND, deviceId);
DeviceDescriptions descs = descsMap.get(providerId);
+ // assuming all providers must to give DeviceDescription
checkArgument(descs != null,
"Device description for Device ID %s from Provider %s was not found",
deviceId, providerId);
- // TODO: implement multi-provider
synchronized (this) {
ConcurrentMap<PortNumber, Port> ports = getPortMap(deviceId);
final PortNumber number = portDescription.portNumber();
Port oldPort = ports.get(number);
// update description
- descs.putPortDesc(number, portDescription);
+ descs.putPortDesc(portDescription);
Port newPort = composePort(device, number, descsMap);
if (oldPort == null) {
return createPort(device, newPort, ports);
@@ -321,6 +330,26 @@
}
}
+ private static boolean isAnnotationsEqual(Annotations lhs, Annotations rhs) {
+ if (lhs == rhs) {
+ return true;
+ }
+ if (lhs == null || rhs == null) {
+ return false;
+ }
+
+ if (!lhs.keys().equals(rhs.keys())) {
+ return false;
+ }
+
+ for (String key : lhs.keys()) {
+ if (!lhs.value(key).equals(rhs.value(key))) {
+ return false;
+ }
+ }
+ return true;
+ }
+
/**
* Returns a Device, merging description given from multiple Providers.
*
@@ -336,46 +365,67 @@
ProviderId primary = pickPrimaryPID(providerDescs);
DeviceDescriptions desc = providerDescs.get(primary);
+
+ // base
Type type = desc.getDeviceDesc().type();
String manufacturer = desc.getDeviceDesc().manufacturer();
String hwVersion = desc.getDeviceDesc().hwVersion();
String swVersion = desc.getDeviceDesc().swVersion();
String serialNumber = desc.getDeviceDesc().serialNumber();
+ DefaultAnnotations annotations = DefaultAnnotations.builder().build();
+ annotations = merge(annotations, desc.getDeviceDesc().annotations());
for (Entry<ProviderId, DeviceDescriptions> e : providerDescs.entrySet()) {
if (e.getKey().equals(primary)) {
continue;
}
- // FIXME: implement attribute merging once we have K-V attributes
+ // TODO: should keep track of Description timestamp
+ // and only merge conflicting keys when timestamp is newer
+ // Currently assuming there will never be a key conflict between
+ // providers
+
+ // annotation merging. not so efficient, should revisit later
+ annotations = merge(annotations, e.getValue().getDeviceDesc().annotations());
}
- return new DefaultDevice(primary, deviceId , type, manufacturer, hwVersion, swVersion, serialNumber);
+ return new DefaultDevice(primary, deviceId , type, manufacturer,
+ hwVersion, swVersion, serialNumber, annotations);
}
- // probably want composePorts
+ // probably want composePort"s" also
private Port composePort(Device device, PortNumber number,
ConcurrentMap<ProviderId, DeviceDescriptions> providerDescs) {
ProviderId primary = pickPrimaryPID(providerDescs);
DeviceDescriptions primDescs = providerDescs.get(primary);
+ // if no primary, assume not enabled
+ // TODO: revisit this default port enabled/disabled behavior
+ boolean isEnabled = false;
+ DefaultAnnotations annotations = DefaultAnnotations.builder().build();
+
final PortDescription portDesc = primDescs.getPortDesc(number);
- boolean isEnabled;
if (portDesc != null) {
isEnabled = portDesc.isEnabled();
- } else {
- // if no primary, assume not enabled
- // TODO: revisit this port enabled/disabled behavior
- isEnabled = false;
+ annotations = merge(annotations, portDesc.annotations());
}
for (Entry<ProviderId, DeviceDescriptions> e : providerDescs.entrySet()) {
if (e.getKey().equals(primary)) {
continue;
}
- // FIXME: implement attribute merging once we have K-V attributes
+ // TODO: should keep track of Description timestamp
+ // and only merge conflicting keys when timestamp is newer
+ // Currently assuming there will never be a key conflict between
+ // providers
+
+ // annotation merging. not so efficient, should revisit later
+ final PortDescription otherPortDesc = e.getValue().getPortDesc(number);
+ if (otherPortDesc != null) {
+ annotations = merge(annotations, otherPortDesc.annotations());
+ }
}
- return new DefaultPort(device, number, isEnabled);
+ return new DefaultPort(device, number, isEnabled, annotations);
}
/**
@@ -428,7 +478,7 @@
private final ConcurrentMap<PortNumber, PortDescription> portDescs;
public DeviceDescriptions(DeviceDescription desc) {
- this.deviceDesc = new AtomicReference<>(desc);
+ this.deviceDesc = new AtomicReference<>(checkNotNull(desc));
this.portDescs = new ConcurrentHashMap<>();
}
@@ -444,12 +494,38 @@
return Collections.unmodifiableCollection(portDescs.values());
}
- public DeviceDescription putDeviceDesc(DeviceDescription newDesc) {
- return deviceDesc.getAndSet(newDesc);
+ /**
+ * Puts DeviceDescription, merging annotations as necessary.
+ *
+ * @param newDesc new DeviceDescription
+ * @return previous DeviceDescription
+ */
+ public synchronized DeviceDescription putDeviceDesc(DeviceDescription newDesc) {
+ DeviceDescription oldOne = deviceDesc.get();
+ DeviceDescription newOne = newDesc;
+ if (oldOne != null) {
+ SparseAnnotations merged = merge(oldOne.annotations(),
+ newDesc.annotations());
+ newOne = new DefaultDeviceDescription(newOne, merged);
+ }
+ return deviceDesc.getAndSet(newOne);
}
- public PortDescription putPortDesc(PortNumber number, PortDescription newDesc) {
- return portDescs.put(number, newDesc);
+ /**
+ * Puts PortDescription, merging annotations as necessary.
+ *
+ * @param newDesc new PortDescription
+ * @return previous PortDescription
+ */
+ public synchronized PortDescription putPortDesc(PortDescription newDesc) {
+ PortDescription oldOne = portDescs.get(newDesc.portNumber());
+ PortDescription newOne = newDesc;
+ if (oldOne != null) {
+ SparseAnnotations merged = merge(oldOne.annotations(),
+ newDesc.annotations());
+ newOne = new DefaultPortDescription(newOne, merged);
+ }
+ return portDescs.put(newOne.portNumber(), newOne);
}
}
}