ONOS-4970: Device data for topology view -- WIP.
Change-Id: Ie5a0c65f38b32672570919c50c1f53b14d293d3f
diff --git a/core/api/src/main/java/org/onosproject/net/AnnotationKeys.java b/core/api/src/main/java/org/onosproject/net/AnnotationKeys.java
index 4235ed1..4b82bf5 100644
--- a/core/api/src/main/java/org/onosproject/net/AnnotationKeys.java
+++ b/core/api/src/main/java/org/onosproject/net/AnnotationKeys.java
@@ -50,7 +50,7 @@
public static final String LATITUDE = "latitude";
/**
- * Annotation key for longitute (e.g. longitude of device).
+ * Annotation key for longitude (e.g. longitude of device).
*/
public static final String LONGITUDE = "longitude";
diff --git a/web/gui/src/main/java/org/onosproject/ui/impl/topo/Topo2Jsonifier.java b/web/gui/src/main/java/org/onosproject/ui/impl/topo/Topo2Jsonifier.java
index a5a344a..6d8ae53 100644
--- a/web/gui/src/main/java/org/onosproject/ui/impl/topo/Topo2Jsonifier.java
+++ b/web/gui/src/main/java/org/onosproject/ui/impl/topo/Topo2Jsonifier.java
@@ -26,6 +26,9 @@
import org.onosproject.incubator.net.PortStatisticsService;
import org.onosproject.incubator.net.tunnel.TunnelService;
import org.onosproject.mastership.MastershipService;
+import org.onosproject.net.Annotated;
+import org.onosproject.net.Annotations;
+import org.onosproject.net.Device;
import org.onosproject.net.device.DeviceService;
import org.onosproject.net.flow.FlowRuleService;
import org.onosproject.net.host.HostService;
@@ -51,8 +54,11 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
import static com.google.common.base.Preconditions.checkNotNull;
+import static org.onosproject.net.AnnotationKeys.LATITUDE;
+import static org.onosproject.net.AnnotationKeys.LONGITUDE;
import static org.onosproject.ui.model.topo.UiNode.LAYER_DEFAULT;
/**
@@ -88,6 +94,11 @@
private TunnelService tunnelService;
+ // NOTE: we'll stick this here for now, but maybe there is a better home?
+ // (this is not distributed across the cluster)
+ private static Map<String, ObjectNode> metaUi = new ConcurrentHashMap<>();
+
+
/**
* Creates an instance with a reference to the services directory, so that
* additional information about network elements may be looked up on
@@ -263,17 +274,73 @@
.put("master", nullIsEmpty(device.master()))
.put("layer", device.layer());
- // TODO: complete device details
-// addLabels(node, device);
-// addProps(node, device);
-// addGeoLocation(node, device);
-// addMetaUi(node, device);
+ Device d = device.backingDevice();
+
+ addProps(node, d);
+ addGeoLocation(node, d);
+ addMetaUi(node, device.idAsString());
return node;
}
- private void addLabels(ObjectNode node, UiDevice device) {
+ private void addProps(ObjectNode node, Device dev) {
+ Annotations annot = dev.annotations();
+ ObjectNode props = objectNode();
+ if (annot != null) {
+ annot.keys().forEach(k -> props.put(k, annot.value(k)));
+ }
+ node.set("props", props);
+ }
+ private void addMetaUi(ObjectNode node, String metaInstanceId) {
+ ObjectNode meta = metaUi.get(metaInstanceId);
+ if (meta != null) {
+ node.set("metaUi", meta);
+ }
+ }
+
+ private void addGeoLocation(ObjectNode node, Annotated a) {
+ List<String> lngLat = getAnnotValues(a, LONGITUDE, LATITUDE);
+ if (lngLat != null) {
+ try {
+ double lng = Double.parseDouble(lngLat.get(0));
+ double lat = Double.parseDouble(lngLat.get(1));
+ ObjectNode loc = objectNode()
+ .put("type", "lnglat")
+ .put("lng", lng)
+ .put("lat", lat);
+ node.set("location", loc);
+
+ } catch (NumberFormatException e) {
+ log.warn("Invalid geo data: longitude={}, latitude={}",
+ lngLat.get(0), lngLat.get(1));
+ }
+ } else {
+ log.debug("No geo lng/lat for {}", a);
+ }
+ }
+
+ // return list of string values from annotated instance, for given keys
+ // return null if any keys are not present
+ List<String> getAnnotValues(Annotated a, String... annotKeys) {
+ List<String> result = new ArrayList<>(annotKeys.length);
+ for (String k : annotKeys) {
+ String v = a.annotations().value(k);
+ if (v == null) {
+ return null;
+ }
+ result.add(v);
+ }
+ return result;
+ }
+
+ // derive JSON object from annotations
+ private ObjectNode props(Annotations annotations) {
+ ObjectNode p = objectNode();
+ if (annotations != null) {
+ annotations.keys().forEach(k -> p.put(k, annotations.value(k)));
+ }
+ return p;
}
private ObjectNode json(UiHost host) {
diff --git a/web/gui/src/test/java/org/onosproject/ui/impl/topo/Topo2JsonifierTest.java b/web/gui/src/test/java/org/onosproject/ui/impl/topo/Topo2JsonifierTest.java
index 1a06c62..ab0cd2d 100644
--- a/web/gui/src/test/java/org/onosproject/ui/impl/topo/Topo2JsonifierTest.java
+++ b/web/gui/src/test/java/org/onosproject/ui/impl/topo/Topo2JsonifierTest.java
@@ -19,6 +19,8 @@
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import org.junit.Test;
+import org.onosproject.net.Annotated;
+import org.onosproject.net.Annotations;
import org.onosproject.ui.impl.AbstractUiImplTest;
import org.onosproject.ui.model.topo.UiNode;
@@ -26,6 +28,7 @@
import java.util.Set;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
import static org.onosproject.ui.model.topo.UiNode.LAYER_DEFAULT;
import static org.onosproject.ui.model.topo.UiNode.LAYER_OPTICAL;
import static org.onosproject.ui.model.topo.UiNode.LAYER_PACKET;
@@ -145,4 +148,59 @@
assertEquals("missing node B", true, def.contains(NODE_B));
assertEquals("missing node E", true, def.contains(NODE_E));
}
+
+ private static final String K1 = "K1";
+ private static final String K2 = "K2";
+ private static final String K3 = "K3";
+ private static final String K4 = "K4";
+
+ private static final String V1 = "V1";
+ private static final String V2 = "V2";
+ private static final String V3 = "V3";
+
+ private static final Annotations ANNOTS = new Annotations() {
+ @Override
+ public Set<String> keys() {
+ return ImmutableSet.of(K1, K2, K3);
+ }
+
+ @Override
+ public String value(String key) {
+ switch (key) {
+ case K1:
+ return V1;
+ case K2:
+ return V2;
+ case K3:
+ return V3;
+ default:
+ return null;
+ }
+ }
+ };
+
+ private static final Annotated THING = () -> ANNOTS;
+
+ private void verifyValues(List<String> vals, String... exp) {
+ print(vals);
+ if (exp.length == 0) {
+ // don't expect any results
+ assertNull("huh?", vals);
+ } else {
+ assertEquals("wrong list len", exp.length, vals.size());
+
+ for (int i = 0; i < exp.length; i++) {
+ assertEquals("wrong value " + i, exp[i], vals.get(i));
+ }
+ }
+ }
+
+ @Test
+ public void annotValues() {
+ print("annotValues()");
+ verifyValues(t2.getAnnotValues(THING, K1), V1);
+ verifyValues(t2.getAnnotValues(THING, K3, K1), V3, V1);
+ verifyValues(t2.getAnnotValues(THING, K1, K2, K3), V1, V2, V3);
+ verifyValues(t2.getAnnotValues(THING, K1, K4));
+ }
}