ONOS-4970: Device data for topology view -- WIP.
Change-Id: Ie5a0c65f38b32672570919c50c1f53b14d293d3f
Showing
3 changed files
with
132 additions
and
7 deletions
| ... | @@ -50,7 +50,7 @@ public final class AnnotationKeys { | ... | @@ -50,7 +50,7 @@ public final class AnnotationKeys { |
| 50 | public static final String LATITUDE = "latitude"; | 50 | public static final String LATITUDE = "latitude"; |
| 51 | 51 | ||
| 52 | /** | 52 | /** |
| 53 | - * Annotation key for longitute (e.g. longitude of device). | 53 | + * Annotation key for longitude (e.g. longitude of device). |
| 54 | */ | 54 | */ |
| 55 | public static final String LONGITUDE = "longitude"; | 55 | public static final String LONGITUDE = "longitude"; |
| 56 | 56 | ... | ... |
| ... | @@ -26,6 +26,9 @@ import org.onosproject.cluster.NodeId; | ... | @@ -26,6 +26,9 @@ import org.onosproject.cluster.NodeId; |
| 26 | import org.onosproject.incubator.net.PortStatisticsService; | 26 | import org.onosproject.incubator.net.PortStatisticsService; |
| 27 | import org.onosproject.incubator.net.tunnel.TunnelService; | 27 | import org.onosproject.incubator.net.tunnel.TunnelService; |
| 28 | import org.onosproject.mastership.MastershipService; | 28 | import org.onosproject.mastership.MastershipService; |
| 29 | +import org.onosproject.net.Annotated; | ||
| 30 | +import org.onosproject.net.Annotations; | ||
| 31 | +import org.onosproject.net.Device; | ||
| 29 | import org.onosproject.net.device.DeviceService; | 32 | import org.onosproject.net.device.DeviceService; |
| 30 | import org.onosproject.net.flow.FlowRuleService; | 33 | import org.onosproject.net.flow.FlowRuleService; |
| 31 | import org.onosproject.net.host.HostService; | 34 | import org.onosproject.net.host.HostService; |
| ... | @@ -51,8 +54,11 @@ import java.util.HashSet; | ... | @@ -51,8 +54,11 @@ import java.util.HashSet; |
| 51 | import java.util.List; | 54 | import java.util.List; |
| 52 | import java.util.Map; | 55 | import java.util.Map; |
| 53 | import java.util.Set; | 56 | import java.util.Set; |
| 57 | +import java.util.concurrent.ConcurrentHashMap; | ||
| 54 | 58 | ||
| 55 | import static com.google.common.base.Preconditions.checkNotNull; | 59 | import static com.google.common.base.Preconditions.checkNotNull; |
| 60 | +import static org.onosproject.net.AnnotationKeys.LATITUDE; | ||
| 61 | +import static org.onosproject.net.AnnotationKeys.LONGITUDE; | ||
| 56 | import static org.onosproject.ui.model.topo.UiNode.LAYER_DEFAULT; | 62 | import static org.onosproject.ui.model.topo.UiNode.LAYER_DEFAULT; |
| 57 | 63 | ||
| 58 | /** | 64 | /** |
| ... | @@ -88,6 +94,11 @@ class Topo2Jsonifier { | ... | @@ -88,6 +94,11 @@ class Topo2Jsonifier { |
| 88 | private TunnelService tunnelService; | 94 | private TunnelService tunnelService; |
| 89 | 95 | ||
| 90 | 96 | ||
| 97 | + // NOTE: we'll stick this here for now, but maybe there is a better home? | ||
| 98 | + // (this is not distributed across the cluster) | ||
| 99 | + private static Map<String, ObjectNode> metaUi = new ConcurrentHashMap<>(); | ||
| 100 | + | ||
| 101 | + | ||
| 91 | /** | 102 | /** |
| 92 | * Creates an instance with a reference to the services directory, so that | 103 | * Creates an instance with a reference to the services directory, so that |
| 93 | * additional information about network elements may be looked up on | 104 | * additional information about network elements may be looked up on |
| ... | @@ -263,17 +274,73 @@ class Topo2Jsonifier { | ... | @@ -263,17 +274,73 @@ class Topo2Jsonifier { |
| 263 | .put("master", nullIsEmpty(device.master())) | 274 | .put("master", nullIsEmpty(device.master())) |
| 264 | .put("layer", device.layer()); | 275 | .put("layer", device.layer()); |
| 265 | 276 | ||
| 266 | - // TODO: complete device details | 277 | + Device d = device.backingDevice(); |
| 267 | -// addLabels(node, device); | 278 | + |
| 268 | -// addProps(node, device); | 279 | + addProps(node, d); |
| 269 | -// addGeoLocation(node, device); | 280 | + addGeoLocation(node, d); |
| 270 | -// addMetaUi(node, device); | 281 | + addMetaUi(node, device.idAsString()); |
| 271 | 282 | ||
| 272 | return node; | 283 | return node; |
| 273 | } | 284 | } |
| 274 | 285 | ||
| 275 | - private void addLabels(ObjectNode node, UiDevice device) { | 286 | + private void addProps(ObjectNode node, Device dev) { |
| 287 | + Annotations annot = dev.annotations(); | ||
| 288 | + ObjectNode props = objectNode(); | ||
| 289 | + if (annot != null) { | ||
| 290 | + annot.keys().forEach(k -> props.put(k, annot.value(k))); | ||
| 291 | + } | ||
| 292 | + node.set("props", props); | ||
| 293 | + } | ||
| 294 | + | ||
| 295 | + private void addMetaUi(ObjectNode node, String metaInstanceId) { | ||
| 296 | + ObjectNode meta = metaUi.get(metaInstanceId); | ||
| 297 | + if (meta != null) { | ||
| 298 | + node.set("metaUi", meta); | ||
| 299 | + } | ||
| 300 | + } | ||
| 301 | + | ||
| 302 | + private void addGeoLocation(ObjectNode node, Annotated a) { | ||
| 303 | + List<String> lngLat = getAnnotValues(a, LONGITUDE, LATITUDE); | ||
| 304 | + if (lngLat != null) { | ||
| 305 | + try { | ||
| 306 | + double lng = Double.parseDouble(lngLat.get(0)); | ||
| 307 | + double lat = Double.parseDouble(lngLat.get(1)); | ||
| 308 | + ObjectNode loc = objectNode() | ||
| 309 | + .put("type", "lnglat") | ||
| 310 | + .put("lng", lng) | ||
| 311 | + .put("lat", lat); | ||
| 312 | + node.set("location", loc); | ||
| 313 | + | ||
| 314 | + } catch (NumberFormatException e) { | ||
| 315 | + log.warn("Invalid geo data: longitude={}, latitude={}", | ||
| 316 | + lngLat.get(0), lngLat.get(1)); | ||
| 317 | + } | ||
| 318 | + } else { | ||
| 319 | + log.debug("No geo lng/lat for {}", a); | ||
| 320 | + } | ||
| 321 | + } | ||
| 322 | + | ||
| 323 | + // return list of string values from annotated instance, for given keys | ||
| 324 | + // return null if any keys are not present | ||
| 325 | + List<String> getAnnotValues(Annotated a, String... annotKeys) { | ||
| 326 | + List<String> result = new ArrayList<>(annotKeys.length); | ||
| 327 | + for (String k : annotKeys) { | ||
| 328 | + String v = a.annotations().value(k); | ||
| 329 | + if (v == null) { | ||
| 330 | + return null; | ||
| 331 | + } | ||
| 332 | + result.add(v); | ||
| 333 | + } | ||
| 334 | + return result; | ||
| 335 | + } | ||
| 276 | 336 | ||
| 337 | + // derive JSON object from annotations | ||
| 338 | + private ObjectNode props(Annotations annotations) { | ||
| 339 | + ObjectNode p = objectNode(); | ||
| 340 | + if (annotations != null) { | ||
| 341 | + annotations.keys().forEach(k -> p.put(k, annotations.value(k))); | ||
| 342 | + } | ||
| 343 | + return p; | ||
| 277 | } | 344 | } |
| 278 | 345 | ||
| 279 | private ObjectNode json(UiHost host) { | 346 | private ObjectNode json(UiHost host) { | ... | ... |
| ... | @@ -19,6 +19,8 @@ package org.onosproject.ui.impl.topo; | ... | @@ -19,6 +19,8 @@ package org.onosproject.ui.impl.topo; |
| 19 | import com.google.common.collect.ImmutableList; | 19 | import com.google.common.collect.ImmutableList; |
| 20 | import com.google.common.collect.ImmutableSet; | 20 | import com.google.common.collect.ImmutableSet; |
| 21 | import org.junit.Test; | 21 | import org.junit.Test; |
| 22 | +import org.onosproject.net.Annotated; | ||
| 23 | +import org.onosproject.net.Annotations; | ||
| 22 | import org.onosproject.ui.impl.AbstractUiImplTest; | 24 | import org.onosproject.ui.impl.AbstractUiImplTest; |
| 23 | import org.onosproject.ui.model.topo.UiNode; | 25 | import org.onosproject.ui.model.topo.UiNode; |
| 24 | 26 | ||
| ... | @@ -26,6 +28,7 @@ import java.util.List; | ... | @@ -26,6 +28,7 @@ import java.util.List; |
| 26 | import java.util.Set; | 28 | import java.util.Set; |
| 27 | 29 | ||
| 28 | import static org.junit.Assert.assertEquals; | 30 | import static org.junit.Assert.assertEquals; |
| 31 | +import static org.junit.Assert.assertNull; | ||
| 29 | import static org.onosproject.ui.model.topo.UiNode.LAYER_DEFAULT; | 32 | import static org.onosproject.ui.model.topo.UiNode.LAYER_DEFAULT; |
| 30 | import static org.onosproject.ui.model.topo.UiNode.LAYER_OPTICAL; | 33 | import static org.onosproject.ui.model.topo.UiNode.LAYER_OPTICAL; |
| 31 | import static org.onosproject.ui.model.topo.UiNode.LAYER_PACKET; | 34 | import static org.onosproject.ui.model.topo.UiNode.LAYER_PACKET; |
| ... | @@ -145,4 +148,59 @@ public class Topo2JsonifierTest extends AbstractUiImplTest { | ... | @@ -145,4 +148,59 @@ public class Topo2JsonifierTest extends AbstractUiImplTest { |
| 145 | assertEquals("missing node B", true, def.contains(NODE_B)); | 148 | assertEquals("missing node B", true, def.contains(NODE_B)); |
| 146 | assertEquals("missing node E", true, def.contains(NODE_E)); | 149 | assertEquals("missing node E", true, def.contains(NODE_E)); |
| 147 | } | 150 | } |
| 151 | + | ||
| 152 | + private static final String K1 = "K1"; | ||
| 153 | + private static final String K2 = "K2"; | ||
| 154 | + private static final String K3 = "K3"; | ||
| 155 | + private static final String K4 = "K4"; | ||
| 156 | + | ||
| 157 | + private static final String V1 = "V1"; | ||
| 158 | + private static final String V2 = "V2"; | ||
| 159 | + private static final String V3 = "V3"; | ||
| 160 | + | ||
| 161 | + private static final Annotations ANNOTS = new Annotations() { | ||
| 162 | + @Override | ||
| 163 | + public Set<String> keys() { | ||
| 164 | + return ImmutableSet.of(K1, K2, K3); | ||
| 165 | + } | ||
| 166 | + | ||
| 167 | + @Override | ||
| 168 | + public String value(String key) { | ||
| 169 | + switch (key) { | ||
| 170 | + case K1: | ||
| 171 | + return V1; | ||
| 172 | + case K2: | ||
| 173 | + return V2; | ||
| 174 | + case K3: | ||
| 175 | + return V3; | ||
| 176 | + default: | ||
| 177 | + return null; | ||
| 178 | + } | ||
| 179 | + } | ||
| 180 | + }; | ||
| 181 | + | ||
| 182 | + private static final Annotated THING = () -> ANNOTS; | ||
| 183 | + | ||
| 184 | + private void verifyValues(List<String> vals, String... exp) { | ||
| 185 | + print(vals); | ||
| 186 | + if (exp.length == 0) { | ||
| 187 | + // don't expect any results | ||
| 188 | + assertNull("huh?", vals); | ||
| 189 | + } else { | ||
| 190 | + assertEquals("wrong list len", exp.length, vals.size()); | ||
| 191 | + | ||
| 192 | + for (int i = 0; i < exp.length; i++) { | ||
| 193 | + assertEquals("wrong value " + i, exp[i], vals.get(i)); | ||
| 194 | + } | ||
| 195 | + } | ||
| 196 | + } | ||
| 197 | + | ||
| 198 | + @Test | ||
| 199 | + public void annotValues() { | ||
| 200 | + print("annotValues()"); | ||
| 201 | + verifyValues(t2.getAnnotValues(THING, K1), V1); | ||
| 202 | + verifyValues(t2.getAnnotValues(THING, K3, K1), V3, V1); | ||
| 203 | + verifyValues(t2.getAnnotValues(THING, K1, K2, K3), V1, V2, V3); | ||
| 204 | + verifyValues(t2.getAnnotValues(THING, K1, K4)); | ||
| 205 | + } | ||
| 148 | } | 206 | } | ... | ... |
-
Please register or login to post a comment