ONOS-4326: TopoRegions: Implement basic structure of response to 'topo2Start' event.
- this is WIP: still need to extract data from model cache. Change-Id: I5ab843a1c352275a8da89964c886b660e3b8b616
Showing
6 changed files
with
460 additions
and
47 deletions
... | @@ -19,7 +19,7 @@ package org.onosproject.ui.model.topo; | ... | @@ -19,7 +19,7 @@ package org.onosproject.ui.model.topo; |
19 | /** | 19 | /** |
20 | * Represents a node drawn on the topology view (region, device, host). | 20 | * Represents a node drawn on the topology view (region, device, host). |
21 | */ | 21 | */ |
22 | -abstract class UiNode extends UiElement { | 22 | +public abstract class UiNode extends UiElement { |
23 | 23 | ||
24 | /** | 24 | /** |
25 | * Default "layer" tag. | 25 | * Default "layer" tag. | ... | ... |
... | @@ -37,12 +37,19 @@ import org.onosproject.ui.model.topo.UiClusterMember; | ... | @@ -37,12 +37,19 @@ import org.onosproject.ui.model.topo.UiClusterMember; |
37 | import org.onosproject.ui.model.topo.UiDevice; | 37 | import org.onosproject.ui.model.topo.UiDevice; |
38 | import org.onosproject.ui.model.topo.UiHost; | 38 | import org.onosproject.ui.model.topo.UiHost; |
39 | import org.onosproject.ui.model.topo.UiLink; | 39 | import org.onosproject.ui.model.topo.UiLink; |
40 | +import org.onosproject.ui.model.topo.UiNode; | ||
40 | import org.onosproject.ui.model.topo.UiRegion; | 41 | import org.onosproject.ui.model.topo.UiRegion; |
41 | import org.onosproject.ui.model.topo.UiTopoLayout; | 42 | import org.onosproject.ui.model.topo.UiTopoLayout; |
42 | 43 | ||
44 | +import java.util.ArrayList; | ||
45 | +import java.util.HashMap; | ||
46 | +import java.util.HashSet; | ||
43 | import java.util.List; | 47 | import java.util.List; |
48 | +import java.util.Map; | ||
49 | +import java.util.Set; | ||
44 | 50 | ||
45 | import static com.google.common.base.Preconditions.checkNotNull; | 51 | import static com.google.common.base.Preconditions.checkNotNull; |
52 | +import static org.onosproject.ui.model.topo.UiNode.LAYER_DEFAULT; | ||
46 | 53 | ||
47 | /** | 54 | /** |
48 | * Facility for creating JSON messages to send to the topology view in the | 55 | * Facility for creating JSON messages to send to the topology view in the |
... | @@ -50,6 +57,11 @@ import static com.google.common.base.Preconditions.checkNotNull; | ... | @@ -50,6 +57,11 @@ import static com.google.common.base.Preconditions.checkNotNull; |
50 | */ | 57 | */ |
51 | class Topo2Jsonifier { | 58 | class Topo2Jsonifier { |
52 | 59 | ||
60 | + private static final String E_DEF_NOT_LAST = | ||
61 | + "UiNode.LAYER_DEFAULT not last in layer list"; | ||
62 | + private static final String E_UNKNOWN_UI_NODE = | ||
63 | + "Unknown subclass of UiNode: "; | ||
64 | + | ||
53 | private final ObjectMapper mapper = new ObjectMapper(); | 65 | private final ObjectMapper mapper = new ObjectMapper(); |
54 | 66 | ||
55 | private ServiceDirectory directory; | 67 | private ServiceDirectory directory; |
... | @@ -87,7 +99,10 @@ class Topo2Jsonifier { | ... | @@ -87,7 +99,10 @@ class Topo2Jsonifier { |
87 | portStatsService = directory.get(PortStatisticsService.class); | 99 | portStatsService = directory.get(PortStatisticsService.class); |
88 | topologyService = directory.get(TopologyService.class); | 100 | topologyService = directory.get(TopologyService.class); |
89 | tunnelService = directory.get(TunnelService.class); | 101 | tunnelService = directory.get(TunnelService.class); |
102 | + } | ||
90 | 103 | ||
104 | + // for unit testing | ||
105 | + Topo2Jsonifier() { | ||
91 | } | 106 | } |
92 | 107 | ||
93 | private ObjectNode objectNode() { | 108 | private ObjectNode objectNode() { |
... | @@ -156,46 +171,103 @@ class Topo2Jsonifier { | ... | @@ -156,46 +171,103 @@ class Topo2Jsonifier { |
156 | * view. | 171 | * view. |
157 | * | 172 | * |
158 | * @param region the region to transform to JSON | 173 | * @param region the region to transform to JSON |
174 | + * @param subRegions the subregions within this region | ||
159 | * @return a JSON representation of the data | 175 | * @return a JSON representation of the data |
160 | */ | 176 | */ |
161 | - ObjectNode region(UiRegion region) { | 177 | + ObjectNode region(UiRegion region, Set<UiRegion> subRegions) { |
162 | ObjectNode payload = objectNode(); | 178 | ObjectNode payload = objectNode(); |
163 | - | ||
164 | if (region == null) { | 179 | if (region == null) { |
165 | payload.put("note", "no-region"); | 180 | payload.put("note", "no-region"); |
166 | return payload; | 181 | return payload; |
167 | } | 182 | } |
183 | + payload.put("id", region.idAsString()); | ||
184 | + payload.set("subregions", jsonSubRegions(subRegions)); | ||
185 | + | ||
186 | + List<String> layerTags = region.layerOrder(); | ||
187 | + List<Set<UiNode>> splitDevices = splitByLayer(layerTags, region.devices()); | ||
188 | + List<Set<UiNode>> splitHosts = splitByLayer(layerTags, region.hosts()); | ||
189 | + Set<UiLink> links = region.links(); | ||
168 | 190 | ||
169 | - payload.put("id", region.id().toString()); | 191 | + payload.set("devices", jsonGrouped(splitDevices)); |
192 | + payload.set("hosts", jsonGrouped(splitHosts)); | ||
193 | + payload.set("links", jsonLinks(links)); | ||
194 | + payload.set("layerOrder", jsonStrings(layerTags)); | ||
170 | 195 | ||
171 | - ArrayNode layerOrder = arrayNode(); | 196 | + return payload; |
172 | - payload.set("layerOrder", layerOrder); | 197 | + } |
173 | - region.layerOrder().forEach(layerOrder::add); | ||
174 | 198 | ||
175 | - ArrayNode devices = arrayNode(); | 199 | + private ArrayNode jsonSubRegions(Set<UiRegion> subregions) { |
176 | - payload.set("devices", devices); | 200 | + ArrayNode kids = arrayNode(); |
177 | - for (UiDevice device : region.devices()) { | 201 | + if (subregions != null) { |
178 | - devices.add(json(device)); | 202 | + subregions.forEach(s -> kids.add(jsonClosedRegion(s))); |
203 | + } | ||
204 | + return kids; | ||
179 | } | 205 | } |
180 | 206 | ||
181 | - ArrayNode hosts = arrayNode(); | 207 | + private ArrayNode jsonStrings(List<String> strings) { |
182 | - payload.set("hosts", hosts); | 208 | + ArrayNode array = arrayNode(); |
183 | - for (UiHost host : region.hosts()) { | 209 | + strings.forEach(array::add); |
184 | - hosts.add(json(host)); | 210 | + return array; |
185 | } | 211 | } |
186 | 212 | ||
187 | - ArrayNode links = arrayNode(); | 213 | + private ArrayNode jsonLinks(Set<UiLink> links) { |
188 | - payload.set("links", links); | 214 | + ArrayNode result = arrayNode(); |
189 | - for (UiLink link : region.links()) { | 215 | + links.forEach(lnk -> result.add(json(lnk))); |
190 | - links.add(json(link)); | 216 | + return result; |
191 | } | 217 | } |
192 | 218 | ||
219 | + private ArrayNode jsonGrouped(List<Set<UiNode>> groupedNodes) { | ||
220 | + ArrayNode result = arrayNode(); | ||
221 | + groupedNodes.forEach(g -> { | ||
222 | + ArrayNode subset = arrayNode(); | ||
223 | + g.forEach(n -> subset.add(json(n))); | ||
224 | + result.add(subset); | ||
225 | + }); | ||
226 | + return result; | ||
227 | + } | ||
228 | + | ||
229 | + /** | ||
230 | + * Returns a JSON payload that encapsulates the devices, hosts, links that | ||
231 | + * do not belong to any region. | ||
232 | + * | ||
233 | + * @param oDevices orphan devices | ||
234 | + * @param oHosts orphan hosts | ||
235 | + * @param oLinks orphan links | ||
236 | + * @param layerTags layer tags | ||
237 | + * @return a JSON representation of the data | ||
238 | + */ | ||
239 | + ObjectNode orphans(Set<UiDevice> oDevices, Set<UiHost> oHosts, | ||
240 | + Set<UiLink> oLinks, List<String> layerTags) { | ||
241 | + | ||
242 | + ObjectNode payload = objectNode(); | ||
243 | + | ||
244 | + List<Set<UiNode>> splitDevices = splitByLayer(layerTags, oDevices); | ||
245 | + List<Set<UiNode>> splitHosts = splitByLayer(layerTags, oHosts); | ||
246 | + | ||
247 | + payload.set("devices", jsonGrouped(splitDevices)); | ||
248 | + payload.set("hosts", jsonGrouped(splitHosts)); | ||
249 | + payload.set("links", jsonLinks(oLinks)); | ||
250 | + payload.set("layerOrder", jsonStrings(layerTags)); | ||
251 | + | ||
193 | return payload; | 252 | return payload; |
194 | } | 253 | } |
195 | 254 | ||
255 | + private ObjectNode json(UiNode node) { | ||
256 | + if (node instanceof UiRegion) { | ||
257 | + return jsonClosedRegion((UiRegion) node); | ||
258 | + } | ||
259 | + if (node instanceof UiDevice) { | ||
260 | + return json((UiDevice) node); | ||
261 | + } | ||
262 | + if (node instanceof UiHost) { | ||
263 | + return json((UiHost) node); | ||
264 | + } | ||
265 | + throw new IllegalStateException(E_UNKNOWN_UI_NODE + node.getClass()); | ||
266 | + } | ||
267 | + | ||
196 | private ObjectNode json(UiDevice device) { | 268 | private ObjectNode json(UiDevice device) { |
197 | ObjectNode node = objectNode() | 269 | ObjectNode node = objectNode() |
198 | - .put("id", device.id().toString()) | 270 | + .put("id", device.idAsString()) |
199 | .put("type", device.type()) | 271 | .put("type", device.type()) |
200 | .put("online", device.isOnline()) | 272 | .put("online", device.isOnline()) |
201 | .put("master", device.master().toString()) | 273 | .put("master", device.master().toString()) |
... | @@ -216,7 +288,7 @@ class Topo2Jsonifier { | ... | @@ -216,7 +288,7 @@ class Topo2Jsonifier { |
216 | 288 | ||
217 | private ObjectNode json(UiHost host) { | 289 | private ObjectNode json(UiHost host) { |
218 | return objectNode() | 290 | return objectNode() |
219 | - .put("id", host.id().toString()) | 291 | + .put("id", host.idAsString()) |
220 | .put("layer", host.layer()); | 292 | .put("layer", host.layer()); |
221 | // TODO: complete host details | 293 | // TODO: complete host details |
222 | } | 294 | } |
... | @@ -224,9 +296,101 @@ class Topo2Jsonifier { | ... | @@ -224,9 +296,101 @@ class Topo2Jsonifier { |
224 | 296 | ||
225 | private ObjectNode json(UiLink link) { | 297 | private ObjectNode json(UiLink link) { |
226 | return objectNode() | 298 | return objectNode() |
227 | - .put("id", link.id().toString()); | 299 | + .put("id", link.idAsString()); |
228 | // TODO: complete link details | 300 | // TODO: complete link details |
229 | } | 301 | } |
230 | 302 | ||
231 | 303 | ||
304 | + private ObjectNode jsonClosedRegion(UiRegion region) { | ||
305 | + return objectNode() | ||
306 | + .put("id", region.idAsString()); | ||
307 | + // TODO: complete closed-region details | ||
308 | + } | ||
309 | + | ||
310 | + | ||
311 | + /** | ||
312 | + * Returns a JSON array representation of a list of regions. Note that the | ||
313 | + * information about each region is limited to what needs to be used to | ||
314 | + * show the regions as nodes on the view. | ||
315 | + * | ||
316 | + * @param regions the regions | ||
317 | + * @return a JSON representation of the minimal region information | ||
318 | + */ | ||
319 | + public ArrayNode closedRegions(Set<UiRegion> regions) { | ||
320 | + ArrayNode array = arrayNode(); | ||
321 | + for (UiRegion r : regions) { | ||
322 | + array.add(jsonClosedRegion(r)); | ||
323 | + } | ||
324 | + return array; | ||
325 | + } | ||
326 | + | ||
327 | + /** | ||
328 | + * Returns a JSON array representation of a list of devices. | ||
329 | + * | ||
330 | + * @param devices the devices | ||
331 | + * @return a JSON representation of the devices | ||
332 | + */ | ||
333 | + public ArrayNode devices(Set<UiDevice> devices) { | ||
334 | + ArrayNode array = arrayNode(); | ||
335 | + for (UiDevice device : devices) { | ||
336 | + array.add(json(device)); | ||
337 | + } | ||
338 | + return array; | ||
339 | + } | ||
340 | + | ||
341 | + /** | ||
342 | + * Returns a JSON array representation of a list of hosts. | ||
343 | + * | ||
344 | + * @param hosts the hosts | ||
345 | + * @return a JSON representation of the hosts | ||
346 | + */ | ||
347 | + public ArrayNode hosts(Set<UiHost> hosts) { | ||
348 | + ArrayNode array = arrayNode(); | ||
349 | + for (UiHost host : hosts) { | ||
350 | + array.add(json(host)); | ||
351 | + } | ||
352 | + return array; | ||
353 | + } | ||
354 | + | ||
355 | + /** | ||
356 | + * Returns a JSON array representation of a list of links. | ||
357 | + * | ||
358 | + * @param links the links | ||
359 | + * @return a JSON representation of the links | ||
360 | + */ | ||
361 | + public ArrayNode links(Set<UiLink> links) { | ||
362 | + ArrayNode array = arrayNode(); | ||
363 | + for (UiLink link : links) { | ||
364 | + array.add(json(link)); | ||
365 | + } | ||
366 | + return array; | ||
367 | + } | ||
368 | + | ||
369 | + // package-private for unit testing | ||
370 | + List<Set<UiNode>> splitByLayer(List<String> layerTags, | ||
371 | + Set<? extends UiNode> nodes) { | ||
372 | + final int nLayers = layerTags.size(); | ||
373 | + if (!layerTags.get(nLayers - 1).equals(LAYER_DEFAULT)) { | ||
374 | + throw new IllegalArgumentException(E_DEF_NOT_LAST); | ||
375 | + } | ||
376 | + | ||
377 | + List<Set<UiNode>> splitList = new ArrayList<>(layerTags.size()); | ||
378 | + Map<String, Set<UiNode>> byLayer = new HashMap<>(layerTags.size()); | ||
379 | + | ||
380 | + for (String tag : layerTags) { | ||
381 | + Set<UiNode> set = new HashSet<>(); | ||
382 | + byLayer.put(tag, set); | ||
383 | + splitList.add(set); | ||
384 | + } | ||
385 | + | ||
386 | + for (UiNode n : nodes) { | ||
387 | + String which = n.layer(); | ||
388 | + if (!layerTags.contains(which)) { | ||
389 | + which = LAYER_DEFAULT; | ||
390 | + } | ||
391 | + byLayer.get(which).add(n); | ||
392 | + } | ||
393 | + | ||
394 | + return splitList; | ||
395 | + } | ||
232 | } | 396 | } | ... | ... |
... | @@ -17,6 +17,7 @@ | ... | @@ -17,6 +17,7 @@ |
17 | package org.onosproject.ui.impl.topo; | 17 | package org.onosproject.ui.impl.topo; |
18 | 18 | ||
19 | import com.fasterxml.jackson.databind.node.ObjectNode; | 19 | import com.fasterxml.jackson.databind.node.ObjectNode; |
20 | +import com.google.common.collect.ImmutableList; | ||
20 | import com.google.common.collect.ImmutableSet; | 21 | import com.google.common.collect.ImmutableSet; |
21 | import org.onlab.osgi.ServiceDirectory; | 22 | import org.onlab.osgi.ServiceDirectory; |
22 | import org.onosproject.ui.RequestHandler; | 23 | import org.onosproject.ui.RequestHandler; |
... | @@ -24,6 +25,9 @@ import org.onosproject.ui.UiConnection; | ... | @@ -24,6 +25,9 @@ import org.onosproject.ui.UiConnection; |
24 | import org.onosproject.ui.UiMessageHandler; | 25 | import org.onosproject.ui.UiMessageHandler; |
25 | import org.onosproject.ui.impl.UiWebSocket; | 26 | import org.onosproject.ui.impl.UiWebSocket; |
26 | import org.onosproject.ui.model.topo.UiClusterMember; | 27 | import org.onosproject.ui.model.topo.UiClusterMember; |
28 | +import org.onosproject.ui.model.topo.UiDevice; | ||
29 | +import org.onosproject.ui.model.topo.UiHost; | ||
30 | +import org.onosproject.ui.model.topo.UiLink; | ||
27 | import org.onosproject.ui.model.topo.UiRegion; | 31 | import org.onosproject.ui.model.topo.UiRegion; |
28 | import org.onosproject.ui.model.topo.UiTopoLayout; | 32 | import org.onosproject.ui.model.topo.UiTopoLayout; |
29 | import org.slf4j.Logger; | 33 | import org.slf4j.Logger; |
... | @@ -31,6 +35,9 @@ import org.slf4j.LoggerFactory; | ... | @@ -31,6 +35,9 @@ import org.slf4j.LoggerFactory; |
31 | 35 | ||
32 | import java.util.Collection; | 36 | import java.util.Collection; |
33 | import java.util.List; | 37 | import java.util.List; |
38 | +import java.util.Set; | ||
39 | + | ||
40 | +import static org.onosproject.ui.model.topo.UiNode.LAYER_DEFAULT; | ||
34 | 41 | ||
35 | /* | 42 | /* |
36 | NOTES: | 43 | NOTES: |
... | @@ -58,11 +65,14 @@ public class Topo2ViewMessageHandler extends UiMessageHandler { | ... | @@ -58,11 +65,14 @@ public class Topo2ViewMessageHandler extends UiMessageHandler { |
58 | private static final String TOPO2_STOP = "topo2Stop"; | 65 | private static final String TOPO2_STOP = "topo2Stop"; |
59 | 66 | ||
60 | // === Outbound event identifiers | 67 | // === Outbound event identifiers |
68 | + private static final String ALL_INSTANCES = "topo2AllInstances"; | ||
61 | private static final String CURRENT_LAYOUT = "topo2CurrentLayout"; | 69 | private static final String CURRENT_LAYOUT = "topo2CurrentLayout"; |
62 | private static final String CURRENT_REGION = "topo2CurrentRegion"; | 70 | private static final String CURRENT_REGION = "topo2CurrentRegion"; |
63 | - private static final String ALL_INSTANCES = "topo2AllInstances"; | 71 | + private static final String PEER_REGIONS = "topo2PeerRegions"; |
72 | + private static final String ORPHANS = "topo2Orphans"; | ||
64 | private static final String TOPO_START_DONE = "topo2StartDone"; | 73 | private static final String TOPO_START_DONE = "topo2StartDone"; |
65 | 74 | ||
75 | + | ||
66 | private UiTopoSession topoSession; | 76 | private UiTopoSession topoSession; |
67 | private Topo2Jsonifier t2json; | 77 | private Topo2Jsonifier t2json; |
68 | 78 | ||
... | @@ -99,18 +109,36 @@ public class Topo2ViewMessageHandler extends UiMessageHandler { | ... | @@ -99,18 +109,36 @@ public class Topo2ViewMessageHandler extends UiMessageHandler { |
99 | 109 | ||
100 | log.debug("topo2Start: {}", payload); | 110 | log.debug("topo2Start: {}", payload); |
101 | 111 | ||
112 | + // this is the list of ONOS cluster members | ||
102 | List<UiClusterMember> instances = topoSession.getAllInstances(); | 113 | List<UiClusterMember> instances = topoSession.getAllInstances(); |
103 | sendMessage(ALL_INSTANCES, t2json.instances(instances)); | 114 | sendMessage(ALL_INSTANCES, t2json.instances(instances)); |
104 | 115 | ||
116 | + // this is the layout that the user has chosen to display | ||
105 | UiTopoLayout currentLayout = topoSession.currentLayout(); | 117 | UiTopoLayout currentLayout = topoSession.currentLayout(); |
106 | sendMessage(CURRENT_LAYOUT, t2json.layout(currentLayout)); | 118 | sendMessage(CURRENT_LAYOUT, t2json.layout(currentLayout)); |
107 | 119 | ||
120 | + // this is the region that is associated with the current layout | ||
121 | + // this message includes details of the sub-regions, devices, | ||
122 | + // hosts, and links within the region | ||
123 | + // (as well as layer-order hints) | ||
108 | UiRegion region = topoSession.getRegion(currentLayout); | 124 | UiRegion region = topoSession.getRegion(currentLayout); |
109 | - sendMessage(CURRENT_REGION, t2json.region(region)); | 125 | + Set<UiRegion> kids = topoSession.getSubRegions(currentLayout); |
110 | - | 126 | + sendMessage(CURRENT_REGION, t2json.region(region, kids)); |
111 | - // TODO: send information about devices/hosts/links in non-region | 127 | + |
112 | - // TODO: send information about "linked, peer" regions | 128 | + // these are the regions that are siblings to this one |
113 | - | 129 | + Set<UiRegion> peers = topoSession.getPeerRegions(currentLayout); |
130 | + ObjectNode peersPayload = objectNode(); | ||
131 | + peersPayload.set("peers", t2json.closedRegions(peers)); | ||
132 | + sendMessage(PEER_REGIONS, peersPayload); | ||
133 | + | ||
134 | + // return devices, hosts, links belonging to no region | ||
135 | + Set<UiDevice> oDevices = topoSession.getOrphanDevices(); | ||
136 | + Set<UiHost> oHosts = topoSession.getOrphanHosts(); | ||
137 | + Set<UiLink> oLinks = topoSession.getOrphanLinks(); | ||
138 | + List<String> oLayers = getOrphanLayerOrder(); | ||
139 | + sendMessage(ORPHANS, t2json.orphans(oDevices, oHosts, oLinks, oLayers)); | ||
140 | + | ||
141 | + // finally, tell the UI that we are done | ||
114 | sendMessage(TOPO_START_DONE, null); | 142 | sendMessage(TOPO_START_DONE, null); |
115 | 143 | ||
116 | 144 | ||
... | @@ -122,6 +150,16 @@ public class Topo2ViewMessageHandler extends UiMessageHandler { | ... | @@ -122,6 +150,16 @@ public class Topo2ViewMessageHandler extends UiMessageHandler { |
122 | // sendAllHosts(); | 150 | // sendAllHosts(); |
123 | // sendTopoStartDone(); | 151 | // sendTopoStartDone(); |
124 | } | 152 | } |
153 | + | ||
154 | + | ||
155 | + } | ||
156 | + | ||
157 | + // TODO: we need to decide on how this should really get populated. | ||
158 | + // For example, to be "backward compatible", this should really be | ||
159 | + // [ LAYER_OPTICAL, LAYER_PACKET, LAYER_DEFAULT ] | ||
160 | + private List<String> getOrphanLayerOrder() { | ||
161 | + // NOTE that LAYER_DEFAULT must always be last in the array | ||
162 | + return ImmutableList.of(LAYER_DEFAULT); | ||
125 | } | 163 | } |
126 | 164 | ||
127 | private final class Topo2Stop extends RequestHandler { | 165 | private final class Topo2Stop extends RequestHandler { | ... | ... |
... | @@ -22,12 +22,17 @@ import org.onosproject.ui.impl.topo.model.UiModelEvent; | ... | @@ -22,12 +22,17 @@ import org.onosproject.ui.impl.topo.model.UiModelEvent; |
22 | import org.onosproject.ui.impl.topo.model.UiModelListener; | 22 | import org.onosproject.ui.impl.topo.model.UiModelListener; |
23 | import org.onosproject.ui.impl.topo.model.UiSharedTopologyModel; | 23 | import org.onosproject.ui.impl.topo.model.UiSharedTopologyModel; |
24 | import org.onosproject.ui.model.topo.UiClusterMember; | 24 | import org.onosproject.ui.model.topo.UiClusterMember; |
25 | +import org.onosproject.ui.model.topo.UiDevice; | ||
26 | +import org.onosproject.ui.model.topo.UiHost; | ||
27 | +import org.onosproject.ui.model.topo.UiLink; | ||
25 | import org.onosproject.ui.model.topo.UiRegion; | 28 | import org.onosproject.ui.model.topo.UiRegion; |
26 | import org.onosproject.ui.model.topo.UiTopoLayout; | 29 | import org.onosproject.ui.model.topo.UiTopoLayout; |
27 | import org.slf4j.Logger; | 30 | import org.slf4j.Logger; |
28 | import org.slf4j.LoggerFactory; | 31 | import org.slf4j.LoggerFactory; |
29 | 32 | ||
33 | +import java.util.Collections; | ||
30 | import java.util.List; | 34 | import java.util.List; |
35 | +import java.util.Set; | ||
31 | 36 | ||
32 | /** | 37 | /** |
33 | * Coordinates with the {@link UiTopoLayoutService} to access | 38 | * Coordinates with the {@link UiTopoLayoutService} to access |
... | @@ -44,6 +49,7 @@ import java.util.List; | ... | @@ -44,6 +49,7 @@ import java.util.List; |
44 | * interact with it when topo-related events come in from the client. | 49 | * interact with it when topo-related events come in from the client. |
45 | */ | 50 | */ |
46 | public class UiTopoSession implements UiModelListener { | 51 | public class UiTopoSession implements UiModelListener { |
52 | + | ||
47 | private final Logger log = LoggerFactory.getLogger(getClass()); | 53 | private final Logger log = LoggerFactory.getLogger(getClass()); |
48 | 54 | ||
49 | private final UiWebSocket webSocket; | 55 | private final UiWebSocket webSocket; |
... | @@ -73,6 +79,13 @@ public class UiTopoSession implements UiModelListener { | ... | @@ -73,6 +79,13 @@ public class UiTopoSession implements UiModelListener { |
73 | this.layoutService = layoutService; | 79 | this.layoutService = layoutService; |
74 | } | 80 | } |
75 | 81 | ||
82 | + // constructs a neutered instance, for unit testing | ||
83 | + UiTopoSession() { | ||
84 | + webSocket = null; | ||
85 | + username = null; | ||
86 | + sharedModel = null; | ||
87 | + } | ||
88 | + | ||
76 | /** | 89 | /** |
77 | * Initializes the session; registering with the shared model. | 90 | * Initializes the session; registering with the shared model. |
78 | */ | 91 | */ |
... | @@ -154,6 +167,68 @@ public class UiTopoSession implements UiModelListener { | ... | @@ -154,6 +167,68 @@ public class UiTopoSession implements UiModelListener { |
154 | * @return region that the layout is based upon | 167 | * @return region that the layout is based upon |
155 | */ | 168 | */ |
156 | public UiRegion getRegion(UiTopoLayout layout) { | 169 | public UiRegion getRegion(UiTopoLayout layout) { |
157 | - return sharedModel.getRegion(layout); | 170 | + return sharedModel.getRegion(layout.regionId()); |
171 | + } | ||
172 | + | ||
173 | + /** | ||
174 | + * Returns the regions that are "peers" to this region. That is, based on | ||
175 | + * the layout the user is viewing, all the regions that are associated with | ||
176 | + * layouts that are children of the parent layout to this layout. | ||
177 | + * | ||
178 | + * @param layout the layout being viewed | ||
179 | + * @return all regions that are "siblings" to this layout's region | ||
180 | + */ | ||
181 | + public Set<UiRegion> getPeerRegions(UiTopoLayout layout) { | ||
182 | + UiRegion currentRegion = getRegion(layout); | ||
183 | + | ||
184 | + // TODO: consult topo layout service to get hierarchy info... | ||
185 | + // TODO: then consult shared model to get regions | ||
186 | + return Collections.emptySet(); | ||
187 | + } | ||
188 | + | ||
189 | + /** | ||
190 | + * Returns the subregions of the region in the specified layout. | ||
191 | + * | ||
192 | + * @param layout the layout being viewed | ||
193 | + * @return all regions that are "contained within" this layout's region | ||
194 | + */ | ||
195 | + public Set<UiRegion> getSubRegions(UiTopoLayout layout) { | ||
196 | + UiRegion currentRegion = getRegion(layout); | ||
197 | + | ||
198 | + // TODO: consult topo layout service to get child layouts... | ||
199 | + // TODO: then consult shared model to get regions | ||
200 | + return Collections.emptySet(); | ||
201 | + } | ||
202 | + | ||
203 | + | ||
204 | + /** | ||
205 | + * Returns all devices that are not in a region. | ||
206 | + * | ||
207 | + * @return all devices not in a region | ||
208 | + */ | ||
209 | + public Set<UiDevice> getOrphanDevices() { | ||
210 | + // TODO: get devices with no region | ||
211 | + return Collections.emptySet(); | ||
212 | + } | ||
213 | + | ||
214 | + /** | ||
215 | + * Returns all hosts that are not in a region. | ||
216 | + * | ||
217 | + * @return all hosts not in a region | ||
218 | + */ | ||
219 | + public Set<UiHost> getOrphanHosts() { | ||
220 | + // TODO: get hosts with no region | ||
221 | + return Collections.emptySet(); | ||
222 | + } | ||
223 | + | ||
224 | + /** | ||
225 | + * Returns all links that are not in a region. | ||
226 | + * | ||
227 | + * @return all links not in a region | ||
228 | + */ | ||
229 | + public Set<UiLink> getOrphanLinks() { | ||
230 | + // TODO: get links with no region | ||
231 | + return Collections.emptySet(); | ||
158 | } | 232 | } |
233 | + | ||
159 | } | 234 | } | ... | ... |
... | @@ -55,6 +55,7 @@ import org.onosproject.net.link.LinkListener; | ... | @@ -55,6 +55,7 @@ import org.onosproject.net.link.LinkListener; |
55 | import org.onosproject.net.link.LinkService; | 55 | import org.onosproject.net.link.LinkService; |
56 | import org.onosproject.net.region.Region; | 56 | import org.onosproject.net.region.Region; |
57 | import org.onosproject.net.region.RegionEvent; | 57 | import org.onosproject.net.region.RegionEvent; |
58 | +import org.onosproject.net.region.RegionId; | ||
58 | import org.onosproject.net.region.RegionListener; | 59 | import org.onosproject.net.region.RegionListener; |
59 | import org.onosproject.net.region.RegionService; | 60 | import org.onosproject.net.region.RegionService; |
60 | import org.onosproject.net.statistic.StatisticService; | 61 | import org.onosproject.net.statistic.StatisticService; |
... | @@ -62,15 +63,11 @@ import org.onosproject.net.topology.TopologyService; | ... | @@ -62,15 +63,11 @@ import org.onosproject.net.topology.TopologyService; |
62 | import org.onosproject.ui.impl.topo.UiTopoSession; | 63 | import org.onosproject.ui.impl.topo.UiTopoSession; |
63 | import org.onosproject.ui.model.ServiceBundle; | 64 | import org.onosproject.ui.model.ServiceBundle; |
64 | import org.onosproject.ui.model.topo.UiClusterMember; | 65 | import org.onosproject.ui.model.topo.UiClusterMember; |
65 | -import org.onosproject.ui.model.topo.UiElement; | ||
66 | import org.onosproject.ui.model.topo.UiRegion; | 66 | import org.onosproject.ui.model.topo.UiRegion; |
67 | -import org.onosproject.ui.model.topo.UiTopoLayout; | ||
68 | import org.slf4j.Logger; | 67 | import org.slf4j.Logger; |
69 | import org.slf4j.LoggerFactory; | 68 | import org.slf4j.LoggerFactory; |
70 | 69 | ||
71 | -import java.util.HashSet; | ||
72 | import java.util.List; | 70 | import java.util.List; |
73 | -import java.util.Set; | ||
74 | import java.util.concurrent.ExecutorService; | 71 | import java.util.concurrent.ExecutorService; |
75 | import java.util.concurrent.Executors; | 72 | import java.util.concurrent.Executors; |
76 | 73 | ||
... | @@ -210,23 +207,14 @@ public final class UiSharedTopologyModel | ... | @@ -210,23 +207,14 @@ public final class UiSharedTopologyModel |
210 | return cache.getAllClusterMembers(); | 207 | return cache.getAllClusterMembers(); |
211 | } | 208 | } |
212 | 209 | ||
213 | - public Set<UiElement> getElements(UiTopoLayout layout) { | ||
214 | - Set<UiElement> results = new HashSet<>(); | ||
215 | - | ||
216 | - // TODO: figure out how to extract the appropriate nodes | ||
217 | - // from the cache, for the given layout. | ||
218 | - | ||
219 | - return results; | ||
220 | - } | ||
221 | - | ||
222 | /** | 210 | /** |
223 | - * Returns the region for the given layout. | 211 | + * Returns the region for the given identifier. |
224 | * | 212 | * |
225 | - * @param layout layout filter | 213 | + * @param id region identifier |
226 | - * @return the region the layout is based upon | 214 | + * @return the region |
227 | */ | 215 | */ |
228 | - public UiRegion getRegion(UiTopoLayout layout) { | 216 | + public UiRegion getRegion(RegionId id) { |
229 | - return cache.accessRegion(layout.regionId()); | 217 | + return cache.accessRegion(id); |
230 | } | 218 | } |
231 | 219 | ||
232 | // ===================================================================== | 220 | // ===================================================================== | ... | ... |
1 | +/* | ||
2 | + * Copyright 2016-present Open Networking Laboratory | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | + | ||
17 | +package org.onosproject.ui.impl.topo; | ||
18 | + | ||
19 | +import com.google.common.collect.ImmutableList; | ||
20 | +import com.google.common.collect.ImmutableSet; | ||
21 | +import org.junit.Test; | ||
22 | +import org.onosproject.ui.impl.AbstractUiImplTest; | ||
23 | +import org.onosproject.ui.model.topo.UiNode; | ||
24 | + | ||
25 | +import java.util.List; | ||
26 | +import java.util.Set; | ||
27 | + | ||
28 | +import static org.junit.Assert.assertEquals; | ||
29 | +import static org.onosproject.ui.model.topo.UiNode.LAYER_DEFAULT; | ||
30 | +import static org.onosproject.ui.model.topo.UiNode.LAYER_OPTICAL; | ||
31 | +import static org.onosproject.ui.model.topo.UiNode.LAYER_PACKET; | ||
32 | + | ||
33 | +/** | ||
34 | + * Unit tests for {@link Topo2ViewMessageHandler}. | ||
35 | + */ | ||
36 | +public class Topo2JsonifierTest extends AbstractUiImplTest { | ||
37 | + | ||
38 | + // mock node class for testing | ||
39 | + private static class MockNode extends UiNode { | ||
40 | + private final String id; | ||
41 | + | ||
42 | + MockNode(String id, String layer) { | ||
43 | + this.id = id; | ||
44 | + setLayer(layer); | ||
45 | + } | ||
46 | + | ||
47 | + @Override | ||
48 | + public String idAsString() { | ||
49 | + return id; | ||
50 | + } | ||
51 | + | ||
52 | + @Override | ||
53 | + public String toString() { | ||
54 | + return id; | ||
55 | + } | ||
56 | + } | ||
57 | + | ||
58 | + private static final List<String> ALL_TAGS = ImmutableList.of( | ||
59 | + LAYER_OPTICAL, LAYER_PACKET, LAYER_DEFAULT | ||
60 | + ); | ||
61 | + | ||
62 | + private static final List<String> PKT_DEF_TAGS = ImmutableList.of( | ||
63 | + LAYER_PACKET, LAYER_DEFAULT | ||
64 | + ); | ||
65 | + | ||
66 | + private static final List<String> DEF_TAG_ONLY = ImmutableList.of( | ||
67 | + LAYER_DEFAULT | ||
68 | + ); | ||
69 | + | ||
70 | + private static final MockNode NODE_A = new MockNode("A-O", LAYER_OPTICAL); | ||
71 | + private static final MockNode NODE_B = new MockNode("B-P", LAYER_PACKET); | ||
72 | + private static final MockNode NODE_C = new MockNode("C-O", LAYER_OPTICAL); | ||
73 | + private static final MockNode NODE_D = new MockNode("D-D", LAYER_DEFAULT); | ||
74 | + private static final MockNode NODE_E = new MockNode("E-P", LAYER_PACKET); | ||
75 | + private static final MockNode NODE_F = new MockNode("F-r", "random"); | ||
76 | + | ||
77 | + private static final Set<MockNode> NODES = ImmutableSet.of( | ||
78 | + NODE_A, NODE_B, NODE_C, NODE_D, NODE_E, NODE_F | ||
79 | + ); | ||
80 | + | ||
81 | + private Topo2Jsonifier t2 = new Topo2Jsonifier(); | ||
82 | + | ||
83 | + @Test | ||
84 | + public void threeLayers() { | ||
85 | + print("threeLayers()"); | ||
86 | + | ||
87 | + List<Set<UiNode>> result = t2.splitByLayer(ALL_TAGS, NODES); | ||
88 | + print(result); | ||
89 | + | ||
90 | + assertEquals("wrong split size", 3, result.size()); | ||
91 | + Set<UiNode> opt = result.get(0); | ||
92 | + Set<UiNode> pkt = result.get(1); | ||
93 | + Set<UiNode> def = result.get(2); | ||
94 | + | ||
95 | + assertEquals("opt bad size", 2, opt.size()); | ||
96 | + assertEquals("missing node A", true, opt.contains(NODE_A)); | ||
97 | + assertEquals("missing node C", true, opt.contains(NODE_C)); | ||
98 | + | ||
99 | + assertEquals("pkt bad size", 2, pkt.size()); | ||
100 | + assertEquals("missing node B", true, pkt.contains(NODE_B)); | ||
101 | + assertEquals("missing node E", true, pkt.contains(NODE_E)); | ||
102 | + | ||
103 | + assertEquals("def bad size", 2, def.size()); | ||
104 | + assertEquals("missing node D", true, def.contains(NODE_D)); | ||
105 | + assertEquals("missing node F", true, def.contains(NODE_F)); | ||
106 | + } | ||
107 | + | ||
108 | + @Test | ||
109 | + public void twoLayers() { | ||
110 | + print("twoLayers()"); | ||
111 | + | ||
112 | + List<Set<UiNode>> result = t2.splitByLayer(PKT_DEF_TAGS, NODES); | ||
113 | + print(result); | ||
114 | + | ||
115 | + assertEquals("wrong split size", 2, result.size()); | ||
116 | + Set<UiNode> pkt = result.get(0); | ||
117 | + Set<UiNode> def = result.get(1); | ||
118 | + | ||
119 | + assertEquals("pkt bad size", 2, pkt.size()); | ||
120 | + assertEquals("missing node B", true, pkt.contains(NODE_B)); | ||
121 | + assertEquals("missing node E", true, pkt.contains(NODE_E)); | ||
122 | + | ||
123 | + assertEquals("def bad size", 4, def.size()); | ||
124 | + assertEquals("missing node D", true, def.contains(NODE_D)); | ||
125 | + assertEquals("missing node F", true, def.contains(NODE_F)); | ||
126 | + assertEquals("missing node A", true, def.contains(NODE_A)); | ||
127 | + assertEquals("missing node C", true, def.contains(NODE_C)); | ||
128 | + } | ||
129 | + | ||
130 | + @Test | ||
131 | + public void oneLayer() { | ||
132 | + print("oneLayer()"); | ||
133 | + | ||
134 | + List<Set<UiNode>> result = t2.splitByLayer(DEF_TAG_ONLY, NODES); | ||
135 | + print(result); | ||
136 | + | ||
137 | + assertEquals("wrong split size", 1, result.size()); | ||
138 | + Set<UiNode> def = result.get(0); | ||
139 | + | ||
140 | + assertEquals("def bad size", 6, def.size()); | ||
141 | + assertEquals("missing node D", true, def.contains(NODE_D)); | ||
142 | + assertEquals("missing node F", true, def.contains(NODE_F)); | ||
143 | + assertEquals("missing node A", true, def.contains(NODE_A)); | ||
144 | + assertEquals("missing node C", true, def.contains(NODE_C)); | ||
145 | + assertEquals("missing node B", true, def.contains(NODE_B)); | ||
146 | + assertEquals("missing node E", true, def.contains(NODE_E)); | ||
147 | + } | ||
148 | +} |
-
Please register or login to post a comment