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 | + } | ||
276 | 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 | + } | ||
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