Simon Hunt
Committed by Gerrit Code Review

ONOS-2186 - GUI Topo Overlay - (WIP)

- Showing traffic on selected intent now subdues other elements.
- Augmented Highlights to allow for retrieval by ID.
- Reparented HostHighlight and DeviceHighlight to NodeHighlight.
- Added a few extra highlight unit tests.

Change-Id: I0de1cefdcfda58a6fec6e90be5fe898d35aa1b37
...@@ -20,7 +20,7 @@ package org.onosproject.ui.topo; ...@@ -20,7 +20,7 @@ package org.onosproject.ui.topo;
20 /** 20 /**
21 * Denotes the highlighting to apply to a device. 21 * Denotes the highlighting to apply to a device.
22 */ 22 */
23 -public class DeviceHighlight extends AbstractHighlight { 23 +public class DeviceHighlight extends NodeHighlight {
24 24
25 public DeviceHighlight(String deviceId) { 25 public DeviceHighlight(String deviceId) {
26 super(TopoElementType.DEVICE, deviceId); 26 super(TopoElementType.DEVICE, deviceId);
......
...@@ -17,9 +17,10 @@ ...@@ -17,9 +17,10 @@
17 17
18 package org.onosproject.ui.topo; 18 package org.onosproject.ui.topo;
19 19
20 +import java.util.Collection;
20 import java.util.Collections; 21 import java.util.Collections;
21 -import java.util.HashSet; 22 +import java.util.HashMap;
22 -import java.util.Set; 23 +import java.util.Map;
23 24
24 import static com.google.common.base.Preconditions.checkNotNull; 25 import static com.google.common.base.Preconditions.checkNotNull;
25 26
...@@ -53,9 +54,9 @@ public class Highlights { ...@@ -53,9 +54,9 @@ public class Highlights {
53 } 54 }
54 } 55 }
55 56
56 - private final Set<DeviceHighlight> devices = new HashSet<>(); 57 + private final Map<String, DeviceHighlight> devices = new HashMap<>();
57 - private final Set<HostHighlight> hosts = new HashSet<>(); 58 + private final Map<String, HostHighlight> hosts = new HashMap<>();
58 - private final Set<LinkHighlight> links = new HashSet<>(); 59 + private final Map<String, LinkHighlight> links = new HashMap<>();
59 60
60 private Amount subdueLevel = Amount.ZERO; 61 private Amount subdueLevel = Amount.ZERO;
61 62
...@@ -67,7 +68,7 @@ public class Highlights { ...@@ -67,7 +68,7 @@ public class Highlights {
67 * @return self, for chaining 68 * @return self, for chaining
68 */ 69 */
69 public Highlights add(DeviceHighlight dh) { 70 public Highlights add(DeviceHighlight dh) {
70 - devices.add(dh); 71 + devices.put(dh.elementId(), dh);
71 return this; 72 return this;
72 } 73 }
73 74
...@@ -78,7 +79,7 @@ public class Highlights { ...@@ -78,7 +79,7 @@ public class Highlights {
78 * @return self, for chaining 79 * @return self, for chaining
79 */ 80 */
80 public Highlights add(HostHighlight hh) { 81 public Highlights add(HostHighlight hh) {
81 - hosts.add(hh); 82 + hosts.put(hh.elementId(), hh);
82 return this; 83 return this;
83 } 84 }
84 85
...@@ -89,7 +90,7 @@ public class Highlights { ...@@ -89,7 +90,7 @@ public class Highlights {
89 * @return self, for chaining 90 * @return self, for chaining
90 */ 91 */
91 public Highlights add(LinkHighlight lh) { 92 public Highlights add(LinkHighlight lh) {
92 - links.add(lh); 93 + links.put(lh.elementId(), lh);
93 return this; 94 return this;
94 } 95 }
95 96
...@@ -106,30 +107,30 @@ public class Highlights { ...@@ -106,30 +107,30 @@ public class Highlights {
106 } 107 }
107 108
108 /** 109 /**
109 - * Returns the set of device highlights. 110 + * Returns the collection of device highlights.
110 * 111 *
111 * @return device highlights 112 * @return device highlights
112 */ 113 */
113 - public Set<DeviceHighlight> devices() { 114 + public Collection<DeviceHighlight> devices() {
114 - return Collections.unmodifiableSet(devices); 115 + return Collections.unmodifiableCollection(devices.values());
115 } 116 }
116 117
117 /** 118 /**
118 - * Returns the set of host highlights. 119 + * Returns the collection of host highlights.
119 * 120 *
120 * @return host highlights 121 * @return host highlights
121 */ 122 */
122 - public Set<HostHighlight> hosts() { 123 + public Collection<HostHighlight> hosts() {
123 - return Collections.unmodifiableSet(hosts); 124 + return Collections.unmodifiableCollection(hosts.values());
124 } 125 }
125 126
126 /** 127 /**
127 - * Returns the set of link highlights. 128 + * Returns the collection of link highlights.
128 * 129 *
129 * @return link highlights 130 * @return link highlights
130 */ 131 */
131 - public Set<LinkHighlight> links() { 132 + public Collection<LinkHighlight> links() {
132 - return Collections.unmodifiableSet(links); 133 + return Collections.unmodifiableCollection(links.values());
133 } 134 }
134 135
135 /** 136 /**
...@@ -141,4 +142,49 @@ public class Highlights { ...@@ -141,4 +142,49 @@ public class Highlights {
141 public Amount subdueLevel() { 142 public Amount subdueLevel() {
142 return subdueLevel; 143 return subdueLevel;
143 } 144 }
145 +
146 + /**
147 + * Returns the node highlight (device or host) for the given element
148 + * identifier, or null if no match.
149 + *
150 + * @param id element identifier
151 + * @return corresponding node highlight
152 + */
153 + public NodeHighlight getNode(String id) {
154 + NodeHighlight nh = devices.get(id);
155 + return nh != null ? nh : hosts.get(id);
156 + }
157 +
158 + /**
159 + * Returns the device highlight for the given device identifier,
160 + * or null if no match.
161 + *
162 + * @param id device identifier
163 + * @return corresponding device highlight
164 + */
165 + public DeviceHighlight getDevice(String id) {
166 + return devices.get(id);
167 + }
168 +
169 + /**
170 + * Returns the host highlight for the given host identifier,
171 + * or null if no match.
172 + *
173 + * @param id host identifier
174 + * @return corresponding host highlight
175 + */
176 + public HostHighlight getHost(String id) {
177 + return hosts.get(id);
178 + }
179 +
180 + /**
181 + * Returns the link highlight for the given link identifier,
182 + * or null if no match.
183 + *
184 + * @param id link identifier
185 + * @return corresponding link highlight
186 + */
187 + public LinkHighlight getLink(String id) {
188 + return links.get(id);
189 + }
144 } 190 }
......
...@@ -20,7 +20,7 @@ package org.onosproject.ui.topo; ...@@ -20,7 +20,7 @@ package org.onosproject.ui.topo;
20 /** 20 /**
21 * Denotes the highlighting to apply to a host. 21 * Denotes the highlighting to apply to a host.
22 */ 22 */
23 -public class HostHighlight extends AbstractHighlight { 23 +public class HostHighlight extends NodeHighlight {
24 24
25 public HostHighlight(String hostId) { 25 public HostHighlight(String hostId) {
26 super(TopoElementType.HOST, hostId); 26 super(TopoElementType.HOST, hostId);
......
1 +/*
2 + * Copyright 2015 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 +
18 +package org.onosproject.ui.topo;
19 +
20 +/**
21 + * Parent class of {@link DeviceHighlight} and {@link HostHighlight}.
22 + */
23 +public abstract class NodeHighlight extends AbstractHighlight {
24 + public NodeHighlight(TopoElementType type, String elementId) {
25 + super(type, elementId);
26 + }
27 +}
...@@ -17,28 +17,75 @@ ...@@ -17,28 +17,75 @@
17 17
18 package org.onosproject.ui.topo; 18 package org.onosproject.ui.topo;
19 19
20 +import org.junit.Before;
20 import org.junit.Test; 21 import org.junit.Test;
22 +import org.onosproject.ui.topo.Highlights.Amount;
21 23
22 import static org.junit.Assert.assertEquals; 24 import static org.junit.Assert.assertEquals;
25 +import static org.junit.Assert.assertNull;
26 +import static org.junit.Assert.assertTrue;
23 27
24 /** 28 /**
25 * Unit tests for {@link Highlights}. 29 * Unit tests for {@link Highlights}.
26 */ 30 */
27 public class HighlightsTest { 31 public class HighlightsTest {
28 32
29 - private Highlights hl; 33 + private static final String DEV_1 = "dev-1";
34 + private static final String DEV_2 = "dev-2";
35 + private static final String HOST_A = "Host...A";
36 +
37 + private Highlights highlights;
38 + private DeviceHighlight dh1;
39 + private DeviceHighlight dh2;
40 + private HostHighlight hha;
41 +
42 + @Before
43 + public void setUp() {
44 + highlights = new Highlights();
45 + }
30 46
31 @Test 47 @Test
32 public void basic() { 48 public void basic() {
33 - hl = new Highlights(); 49 + assertEquals("devices", 0, highlights.devices().size());
50 + assertEquals("hosts", 0, highlights.hosts().size());
51 + assertEquals("links", 0, highlights.links().size());
52 + assertEquals("sudue", Amount.ZERO, highlights.subdueLevel());
53 + }
54 +
55 + @Test
56 + public void coupleOfDevices() {
57 + dh1 = new DeviceHighlight(DEV_1);
58 + dh2 = new DeviceHighlight(DEV_2);
59 +
60 + highlights.add(dh1);
61 + highlights.add(dh2);
62 + assertTrue("missing dh1", highlights.devices().contains(dh1));
63 + assertTrue("missing dh2", highlights.devices().contains(dh2));
64 + }
34 65
35 - assertEquals("devices", 0, hl.devices().size()); 66 + @Test
36 - assertEquals("hosts", 0, hl.hosts().size()); 67 + public void alternateSubdue() {
37 - assertEquals("links", 0, hl.links().size()); 68 + highlights.subdueAllElse(Amount.MINIMALLY);
38 - assertEquals("sudue", Highlights.Amount.ZERO, hl.subdueLevel()); 69 + assertEquals("wrong level", Amount.MINIMALLY, highlights.subdueLevel());
70 + }
71 +
72 + @Test
73 + public void highlightRetrieval() {
74 + dh1 = new DeviceHighlight(DEV_1);
75 + hha = new HostHighlight(HOST_A);
76 + highlights.add(dh1)
77 + .add(hha);
78 +
79 + assertNull("dev as host", highlights.getHost(DEV_1));
80 + assertNull("host as dev", highlights.getDevice(HOST_A));
81 +
82 + assertEquals("missed dev as dev", dh1, highlights.getDevice(DEV_1));
83 + assertEquals("missed dev as node", dh1, highlights.getNode(DEV_1));
84 +
85 + assertEquals("missed host as host", hha, highlights.getHost(HOST_A));
86 + assertEquals("missed host as node", hha, highlights.getNode(HOST_A));
39 } 87 }
40 88
41 // NOTE: further unit tests involving the Highlights class are done 89 // NOTE: further unit tests involving the Highlights class are done
42 // in TopoJsonTest. 90 // in TopoJsonTest.
43 -
44 } 91 }
......
...@@ -20,7 +20,9 @@ package org.onosproject.ui.impl; ...@@ -20,7 +20,9 @@ package org.onosproject.ui.impl;
20 import com.google.common.collect.ImmutableList; 20 import com.google.common.collect.ImmutableList;
21 import org.onosproject.net.Device; 21 import org.onosproject.net.Device;
22 import org.onosproject.net.DeviceId; 22 import org.onosproject.net.DeviceId;
23 +import org.onosproject.net.ElementId;
23 import org.onosproject.net.Host; 24 import org.onosproject.net.Host;
25 +import org.onosproject.net.HostId;
24 import org.onosproject.net.Link; 26 import org.onosproject.net.Link;
25 import org.onosproject.net.PortNumber; 27 import org.onosproject.net.PortNumber;
26 import org.onosproject.net.flow.FlowEntry; 28 import org.onosproject.net.flow.FlowEntry;
...@@ -40,8 +42,12 @@ import org.onosproject.ui.impl.topo.TopoIntentFilter; ...@@ -40,8 +42,12 @@ import org.onosproject.ui.impl.topo.TopoIntentFilter;
40 import org.onosproject.ui.impl.topo.TrafficLink; 42 import org.onosproject.ui.impl.topo.TrafficLink;
41 import org.onosproject.ui.impl.topo.TrafficLink.StatsType; 43 import org.onosproject.ui.impl.topo.TrafficLink.StatsType;
42 import org.onosproject.ui.impl.topo.TrafficLinkMap; 44 import org.onosproject.ui.impl.topo.TrafficLinkMap;
45 +import org.onosproject.ui.topo.DeviceHighlight;
43 import org.onosproject.ui.topo.Highlights; 46 import org.onosproject.ui.topo.Highlights;
47 +import org.onosproject.ui.topo.Highlights.Amount;
48 +import org.onosproject.ui.topo.HostHighlight;
44 import org.onosproject.ui.topo.LinkHighlight.Flavor; 49 import org.onosproject.ui.topo.LinkHighlight.Flavor;
50 +import org.onosproject.ui.topo.NodeHighlight;
45 import org.onosproject.ui.topo.NodeSelection; 51 import org.onosproject.ui.topo.NodeSelection;
46 import org.onosproject.ui.topo.TopoUtils; 52 import org.onosproject.ui.topo.TopoUtils;
47 import org.slf4j.Logger; 53 import org.slf4j.Logger;
...@@ -59,9 +65,7 @@ import java.util.Timer; ...@@ -59,9 +65,7 @@ import java.util.Timer;
59 import java.util.TimerTask; 65 import java.util.TimerTask;
60 66
61 import static org.onosproject.net.DefaultEdgeLink.createEdgeLink; 67 import static org.onosproject.net.DefaultEdgeLink.createEdgeLink;
62 -import static org.onosproject.ui.impl.TrafficMonitor.Mode.IDLE; 68 +import static org.onosproject.ui.impl.TrafficMonitor.Mode.*;
63 -import static org.onosproject.ui.impl.TrafficMonitor.Mode.RELATED_INTENTS;
64 -import static org.onosproject.ui.impl.TrafficMonitor.Mode.SELECTED_INTENT;
65 69
66 /** 70 /**
67 * Encapsulates the behavior of monitoring specific traffic patterns. 71 * Encapsulates the behavior of monitoring specific traffic patterns.
...@@ -442,6 +446,7 @@ public class TrafficMonitor { ...@@ -442,6 +446,7 @@ public class TrafficMonitor {
442 current.id(), selectedIntents.index(), selectedIntents.size()); 446 current.id(), selectedIntents.index(), selectedIntents.size());
443 447
444 highlightIntentLinksWithTraffic(highlights, primary); 448 highlightIntentLinksWithTraffic(highlights, primary);
449 + highlights.subdueAllElse(Amount.MINIMALLY);
445 } 450 }
446 return highlights; 451 return highlights;
447 } 452 }
...@@ -540,19 +545,20 @@ public class TrafficMonitor { ...@@ -540,19 +545,20 @@ public class TrafficMonitor {
540 TrafficLinkMap linkMap = new TrafficLinkMap(); 545 TrafficLinkMap linkMap = new TrafficLinkMap();
541 // NOTE: highlight secondary first, then primary, so that links shared 546 // NOTE: highlight secondary first, then primary, so that links shared
542 // by intents are colored correctly ("last man wins") 547 // by intents are colored correctly ("last man wins")
543 - createTrafficLinks(linkMap, secondary, Flavor.SECONDARY_HIGHLIGHT, false); 548 + createTrafficLinks(highlights, linkMap, secondary, Flavor.SECONDARY_HIGHLIGHT, false);
544 - createTrafficLinks(linkMap, primary, Flavor.PRIMARY_HIGHLIGHT, false); 549 + createTrafficLinks(highlights, linkMap, primary, Flavor.PRIMARY_HIGHLIGHT, false);
545 colorLinks(highlights, linkMap); 550 colorLinks(highlights, linkMap);
546 } 551 }
547 552
548 private void highlightIntentLinksWithTraffic(Highlights highlights, 553 private void highlightIntentLinksWithTraffic(Highlights highlights,
549 Set<Intent> primary) { 554 Set<Intent> primary) {
550 TrafficLinkMap linkMap = new TrafficLinkMap(); 555 TrafficLinkMap linkMap = new TrafficLinkMap();
551 - createTrafficLinks(linkMap, primary, Flavor.PRIMARY_HIGHLIGHT, true); 556 + createTrafficLinks(highlights, linkMap, primary, Flavor.PRIMARY_HIGHLIGHT, true);
552 colorLinks(highlights, linkMap); 557 colorLinks(highlights, linkMap);
553 } 558 }
554 559
555 - private void createTrafficLinks(TrafficLinkMap linkMap, Set<Intent> intents, 560 + private void createTrafficLinks(Highlights highlights,
561 + TrafficLinkMap linkMap, Set<Intent> intents,
556 Flavor flavor, boolean showTraffic) { 562 Flavor flavor, boolean showTraffic) {
557 for (Intent intent : intents) { 563 for (Intent intent : intents) {
558 List<Intent> installables = servicesBundle.intentService() 564 List<Intent> installables = servicesBundle.intentService()
...@@ -573,11 +579,33 @@ public class TrafficMonitor { ...@@ -573,11 +579,33 @@ public class TrafficMonitor {
573 579
574 boolean isOptical = intent instanceof OpticalConnectivityIntent; 580 boolean isOptical = intent instanceof OpticalConnectivityIntent;
575 processLinks(linkMap, links, flavor, isOptical, showTraffic); 581 processLinks(linkMap, links, flavor, isOptical, showTraffic);
582 + updateHighlights(highlights, links);
576 } 583 }
577 } 584 }
578 } 585 }
579 } 586 }
580 587
588 + private void updateHighlights(Highlights highlights, Iterable<Link> links) {
589 + for (Link link : links) {
590 + ensureNodePresent(highlights, link.src().elementId());
591 + ensureNodePresent(highlights, link.dst().elementId());
592 + }
593 + }
594 +
595 + private void ensureNodePresent(Highlights highlights, ElementId eid) {
596 + String id = eid.toString();
597 + NodeHighlight nh = highlights.getNode(id);
598 + if (nh == null) {
599 + if (eid instanceof DeviceId) {
600 + nh = new DeviceHighlight(id);
601 + highlights.add((DeviceHighlight) nh);
602 + } else if (eid instanceof HostId) {
603 + nh = new HostHighlight(id);
604 + highlights.add((HostHighlight) nh);
605 + }
606 + }
607 + }
608 +
581 // Extracts links from the specified flow rule intent resources 609 // Extracts links from the specified flow rule intent resources
582 private Collection<Link> linkResources(Intent installable) { 610 private Collection<Link> linkResources(Intent installable) {
583 ImmutableList.Builder<Link> builder = ImmutableList.builder(); 611 ImmutableList.Builder<Link> builder = ImmutableList.builder();
......
...@@ -90,13 +90,13 @@ public final class TopoJson { ...@@ -90,13 +90,13 @@ public final class TopoJson {
90 } 90 }
91 91
92 private static ObjectNode json(DeviceHighlight dh) { 92 private static ObjectNode json(DeviceHighlight dh) {
93 - // TODO: implement this once we know what a device highlight looks like 93 + return objectNode()
94 - return objectNode(); 94 + .put(ID, dh.elementId());
95 } 95 }
96 96
97 private static ObjectNode json(HostHighlight hh) { 97 private static ObjectNode json(HostHighlight hh) {
98 - // TODO: implement this once we know what a host highlight looks like 98 + return objectNode()
99 - return objectNode(); 99 + .put(ID, hh.elementId());
100 } 100 }
101 101
102 private static ObjectNode json(LinkHighlight lh) { 102 private static ObjectNode json(LinkHighlight lh) {
......
...@@ -242,6 +242,10 @@ ...@@ -242,6 +242,10 @@
242 242
243 // ======================== 243 // ========================
244 244
245 + function nodeById(id) {
246 + return lu[id];
247 + }
248 +
245 function makeNodeKey(node1, node2) { 249 function makeNodeKey(node1, node2) {
246 return node1 + '-' + node2; 250 return node1 + '-' + node2;
247 } 251 }
...@@ -515,10 +519,10 @@ ...@@ -515,10 +519,10 @@
515 }); 519 });
516 } 520 }
517 521
518 - function unsuppressLink(id, less) { 522 + function unsuppressLink(key, less) {
519 var cls = supAmt(less); 523 var cls = supAmt(less);
520 link.each(function (n) { 524 link.each(function (n) {
521 - if (n.id === id) { 525 + if (n.key === key) {
522 n.el.classed(cls, false); 526 n.el.classed(cls, false);
523 } 527 }
524 }); 528 });
...@@ -922,6 +926,7 @@ ...@@ -922,6 +926,7 @@
922 clearLinkTrafficStyle: clearLinkTrafficStyle, 926 clearLinkTrafficStyle: clearLinkTrafficStyle,
923 removeLinkLabels: removeLinkLabels, 927 removeLinkLabels: removeLinkLabels,
924 findLinkById: tms.findLinkById, 928 findLinkById: tms.findLinkById,
929 + findNodeById: nodeById,
925 updateLinks: updateLinks, 930 updateLinks: updateLinks,
926 updateNodes: updateNodes, 931 updateNodes: updateNodes,
927 supLayers: suppressLayers, 932 supLayers: suppressLayers,
......
...@@ -301,11 +301,12 @@ ...@@ -301,11 +301,12 @@
301 clearLinkTrafficStyle() 301 clearLinkTrafficStyle()
302 removeLinkLabels() 302 removeLinkLabels()
303 findLinkById( id ) 303 findLinkById( id )
304 + findNodeById( id )
304 updateLinks() 305 updateLinks()
305 updateNodes() 306 updateNodes()
306 supLayers( bool, [less] ) 307 supLayers( bool, [less] )
307 unsupNode( id, [less] ) 308 unsupNode( id, [less] )
308 - unsupLink( id, [less] ) 309 + unsupLink( key, [less] )
309 */ 310 */
310 311
311 // TODO: clear node highlighting 312 // TODO: clear node highlighting
...@@ -322,16 +323,30 @@ ...@@ -322,16 +323,30 @@
322 api.supLayers(false, true); 323 api.supLayers(false, true);
323 } 324 }
324 325
325 - // TODO: device and host highlights 326 + data.hosts.forEach(function (host) {
327 + var hdata = api.findNodeById(host.id);
328 + if (hdata && !hdata.el.empty()) {
329 + api.unsupNode(hdata.id, less);
330 + // TODO: further highlighting?
331 + }
332 + });
333 +
334 + data.devices.forEach(function (device) {
335 + var ddata = api.findNodeById(device.id);
336 + if (ddata && !ddata.el.empty()) {
337 + api.unsupNode(ddata.id, less);
338 + // TODO: further highlighting?
339 + }
340 + });
326 341
327 - data.links.forEach(function (lnk) { 342 + data.links.forEach(function (link) {
328 - var ldata = api.findLinkById(lnk.id), 343 + var ldata = api.findLinkById(link.id),
329 - lab = lnk.label, 344 + lab = link.label,
330 units, portcls, magnitude; 345 units, portcls, magnitude;
331 346
332 if (ldata && !ldata.el.empty()) { 347 if (ldata && !ldata.el.empty()) {
333 - api.unsupLink(ldata.id, less); 348 + api.unsupLink(ldata.key, less);
334 - ldata.el.classed(lnk.css, true); 349 + ldata.el.classed(link.css, true);
335 ldata.label = lab; 350 ldata.label = lab;
336 351
337 // inject additional styling for port-based traffic 352 // inject additional styling for port-based traffic
......