ONOS-1479 -- GUI - augmenting topology view for extensibility: WIP.
- Major refactoring of TopologyViewMessageHandler and related classes. Change-Id: I920f7f9f7317f3987a9a8da35ac086e9f8cab8d3
Showing
22 changed files
with
1431 additions
and
42 deletions
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 | + * Partial implementation of the types of highlight to apply to topology | ||
22 | + * elements. | ||
23 | + */ | ||
24 | +public abstract class AbstractHighlight { | ||
25 | + private final TopoElementType type; | ||
26 | + private final String elementId; | ||
27 | + | ||
28 | + public AbstractHighlight(TopoElementType type, String elementId) { | ||
29 | + this.type = type; | ||
30 | + this.elementId = elementId; | ||
31 | + } | ||
32 | + | ||
33 | + public TopoElementType type() { | ||
34 | + return type; | ||
35 | + } | ||
36 | + | ||
37 | + public String elementId() { | ||
38 | + return elementId; | ||
39 | + } | ||
40 | +} |
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 | + * Denotes the types of highlight to apply to a link. | ||
22 | + */ | ||
23 | +public class DeviceHighlight extends AbstractHighlight { | ||
24 | + | ||
25 | + public DeviceHighlight(String deviceId) { | ||
26 | + super(TopoElementType.DEVICE, deviceId); | ||
27 | + } | ||
28 | + | ||
29 | + | ||
30 | +} |
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 | +import java.text.DecimalFormat; | ||
21 | +import java.util.Collections; | ||
22 | +import java.util.HashSet; | ||
23 | +import java.util.Set; | ||
24 | + | ||
25 | +/** | ||
26 | + * Encapsulates highlights to be applied to the topology view, such as | ||
27 | + * highlighting links, displaying link labels, perhaps even decorating | ||
28 | + * nodes with badges, etc. | ||
29 | + */ | ||
30 | +public class Highlights { | ||
31 | + | ||
32 | + private static final DecimalFormat DF0 = new DecimalFormat("#,###"); | ||
33 | + | ||
34 | + private final Set<DeviceHighlight> devices = new HashSet<>(); | ||
35 | + private final Set<HostHighlight> hosts = new HashSet<>(); | ||
36 | + private final Set<LinkHighlight> links = new HashSet<>(); | ||
37 | + | ||
38 | + | ||
39 | + public Highlights add(DeviceHighlight d) { | ||
40 | + devices.add(d); | ||
41 | + return this; | ||
42 | + } | ||
43 | + | ||
44 | + public Highlights add(HostHighlight h) { | ||
45 | + hosts.add(h); | ||
46 | + return this; | ||
47 | + } | ||
48 | + | ||
49 | + public Highlights add(LinkHighlight lh) { | ||
50 | + links.add(lh); | ||
51 | + return this; | ||
52 | + } | ||
53 | + | ||
54 | + | ||
55 | + public Set<DeviceHighlight> devices() { | ||
56 | + return Collections.unmodifiableSet(devices); | ||
57 | + } | ||
58 | + | ||
59 | + public Set<HostHighlight> hosts() { | ||
60 | + return Collections.unmodifiableSet(hosts); | ||
61 | + } | ||
62 | + | ||
63 | + public Set<LinkHighlight> links() { | ||
64 | + return Collections.unmodifiableSet(links); | ||
65 | + } | ||
66 | +} |
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 | + * Denotes the types of highlight to apply to a link. | ||
22 | + */ | ||
23 | +public class HostHighlight extends AbstractHighlight { | ||
24 | + | ||
25 | + public HostHighlight(String hostId) { | ||
26 | + super(TopoElementType.HOST, hostId); | ||
27 | + } | ||
28 | + | ||
29 | + | ||
30 | +} |
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 | +import java.util.Collections; | ||
21 | +import java.util.Set; | ||
22 | +import java.util.TreeSet; | ||
23 | + | ||
24 | +import static com.google.common.base.Preconditions.checkNotNull; | ||
25 | + | ||
26 | +/** | ||
27 | + * Denotes the highlighting to be applied to a link. | ||
28 | + * {@link Flavor} is a closed set of NO-, PRIMARY-, or SECONDARY- highlighting. | ||
29 | + * {@link Mod} is an open ended set of additional modifications (CSS classes) | ||
30 | + * to apply. Note that {@link #MOD_OPTICAL} and {@link #MOD_ANIMATED} are | ||
31 | + * pre-defined mods. | ||
32 | + * Label text may be set, which will also be displayed on the link. | ||
33 | + */ | ||
34 | +public class LinkHighlight extends AbstractHighlight { | ||
35 | + | ||
36 | + private static final String PLAIN = "plain"; | ||
37 | + private static final String PRIMARY = "primary"; | ||
38 | + private static final String SECONDARY = "secondary"; | ||
39 | + private static final String EMPTY = ""; | ||
40 | + private static final String SPACE = " "; | ||
41 | + | ||
42 | + private final Flavor flavor; | ||
43 | + private final Set<Mod> mods = new TreeSet<>(); | ||
44 | + private String label = EMPTY; | ||
45 | + | ||
46 | + /** | ||
47 | + * Constructs a link highlight entity. | ||
48 | + * | ||
49 | + * @param linkId the link identifier | ||
50 | + * @param flavor the highlight flavor | ||
51 | + */ | ||
52 | + public LinkHighlight(String linkId, Flavor flavor) { | ||
53 | + super(TopoElementType.LINK, linkId); | ||
54 | + this.flavor = checkNotNull(flavor); | ||
55 | + } | ||
56 | + | ||
57 | + /** | ||
58 | + * Adds a highlighting modification to this link highlight. | ||
59 | + * | ||
60 | + * @param mod mod to be added | ||
61 | + * @return self, for chaining | ||
62 | + */ | ||
63 | + public LinkHighlight addMod(Mod mod) { | ||
64 | + mods.add(checkNotNull(mod)); | ||
65 | + return this; | ||
66 | + } | ||
67 | + | ||
68 | + /** | ||
69 | + * Adds a label to be displayed on the link. | ||
70 | + * | ||
71 | + * @param label the label text | ||
72 | + * @return self, for chaining | ||
73 | + */ | ||
74 | + public LinkHighlight setLabel(String label) { | ||
75 | + this.label = label == null ? EMPTY : label; | ||
76 | + return this; | ||
77 | + } | ||
78 | + | ||
79 | + /** | ||
80 | + * Returns the highlight flavor. | ||
81 | + * | ||
82 | + * @return highlight flavor | ||
83 | + */ | ||
84 | + public Flavor flavor() { | ||
85 | + return flavor; | ||
86 | + } | ||
87 | + | ||
88 | + /** | ||
89 | + * Returns the highlight modifications. | ||
90 | + * | ||
91 | + * @return highlight modifications | ||
92 | + */ | ||
93 | + public Set<Mod> mods() { | ||
94 | + return Collections.unmodifiableSet(mods); | ||
95 | + } | ||
96 | + | ||
97 | + /** | ||
98 | + * Generates the CSS classes string from the {@link #flavor} and | ||
99 | + * any optional {@link #mods}. | ||
100 | + * | ||
101 | + * @return CSS classes string | ||
102 | + */ | ||
103 | + public String cssClasses() { | ||
104 | + StringBuilder sb = new StringBuilder(flavor.toString()); | ||
105 | + mods.forEach(m -> sb.append(SPACE).append(m)); | ||
106 | + return sb.toString(); | ||
107 | + } | ||
108 | + | ||
109 | + /** | ||
110 | + * Returns the label text. | ||
111 | + * | ||
112 | + * @return label text | ||
113 | + */ | ||
114 | + public String label() { | ||
115 | + return label; | ||
116 | + } | ||
117 | + | ||
118 | + /** | ||
119 | + * Link highlighting flavor. | ||
120 | + */ | ||
121 | + public enum Flavor { | ||
122 | + NO_HIGHLIGHT(PLAIN), | ||
123 | + PRIMARY_HIGHLIGHT(PRIMARY), | ||
124 | + SECONDARY_HIGHLIGHT(SECONDARY); | ||
125 | + | ||
126 | + private String cssName; | ||
127 | + | ||
128 | + Flavor(String s) { | ||
129 | + cssName = s; | ||
130 | + } | ||
131 | + | ||
132 | + @Override | ||
133 | + public String toString() { | ||
134 | + return cssName; | ||
135 | + } | ||
136 | + } | ||
137 | + | ||
138 | + /** | ||
139 | + * Link highlighting modification. | ||
140 | + * <p> | ||
141 | + * Note that this translates to a CSS class name that is applied to | ||
142 | + * the link in the Topology UI. | ||
143 | + */ | ||
144 | + public static final class Mod implements Comparable<Mod> { | ||
145 | + private final String modId; | ||
146 | + | ||
147 | + public Mod(String modId) { | ||
148 | + this.modId = checkNotNull(modId); | ||
149 | + } | ||
150 | + | ||
151 | + @Override | ||
152 | + public String toString() { | ||
153 | + return modId; | ||
154 | + } | ||
155 | + | ||
156 | + @Override | ||
157 | + public boolean equals(Object o) { | ||
158 | + if (this == o) { | ||
159 | + return true; | ||
160 | + } | ||
161 | + if (o == null || getClass() != o.getClass()) { | ||
162 | + return false; | ||
163 | + } | ||
164 | + Mod mod = (Mod) o; | ||
165 | + return modId.equals(mod.modId); | ||
166 | + } | ||
167 | + | ||
168 | + @Override | ||
169 | + public int hashCode() { | ||
170 | + return modId.hashCode(); | ||
171 | + } | ||
172 | + | ||
173 | + | ||
174 | + @Override | ||
175 | + public int compareTo(Mod o) { | ||
176 | + return this.modId.compareTo(o.modId); | ||
177 | + } | ||
178 | + } | ||
179 | + | ||
180 | + /** | ||
181 | + * Denotes a link to be tagged as an optical link. | ||
182 | + */ | ||
183 | + public static final Mod MOD_OPTICAL = new Mod("optical"); | ||
184 | + | ||
185 | + /** | ||
186 | + * Denotes a link to be tagged with animated traffic ("marching ants"). | ||
187 | + */ | ||
188 | + public static final Mod MOD_ANIMATED = new Mod("animated"); | ||
189 | +} |
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 | + * The topology element types to which a highlight can be applied. | ||
22 | + */ | ||
23 | +public enum TopoElementType { | ||
24 | + DEVICE, HOST, LINK | ||
25 | +} |
... | @@ -24,7 +24,8 @@ import org.onosproject.net.LinkKey; | ... | @@ -24,7 +24,8 @@ import org.onosproject.net.LinkKey; |
24 | import org.onosproject.net.link.LinkService; | 24 | import org.onosproject.net.link.LinkService; |
25 | import org.onosproject.ui.RequestHandler; | 25 | import org.onosproject.ui.RequestHandler; |
26 | import org.onosproject.ui.UiMessageHandler; | 26 | import org.onosproject.ui.UiMessageHandler; |
27 | -import org.onosproject.ui.impl.TopologyViewMessageHandlerBase.BiLink; | 27 | +import org.onosproject.ui.impl.topo.BiLink; |
28 | +import org.onosproject.ui.impl.topo.TopoUtils; | ||
28 | import org.onosproject.ui.table.TableModel; | 29 | import org.onosproject.ui.table.TableModel; |
29 | import org.onosproject.ui.table.TableRequestHandler; | 30 | import org.onosproject.ui.table.TableRequestHandler; |
30 | import org.onosproject.ui.table.cell.ConnectPointFormatter; | 31 | import org.onosproject.ui.table.cell.ConnectPointFormatter; |
... | @@ -33,13 +34,14 @@ import org.onosproject.ui.table.cell.EnumFormatter; | ... | @@ -33,13 +34,14 @@ import org.onosproject.ui.table.cell.EnumFormatter; |
33 | import java.util.Collection; | 34 | import java.util.Collection; |
34 | import java.util.Map; | 35 | import java.util.Map; |
35 | 36 | ||
36 | -import static org.onosproject.ui.impl.TopologyViewMessageHandlerBase.addLink; | ||
37 | - | ||
38 | /** | 37 | /** |
39 | * Message handler for link view related messages. | 38 | * Message handler for link view related messages. |
40 | */ | 39 | */ |
41 | public class LinkViewMessageHandler extends UiMessageHandler { | 40 | public class LinkViewMessageHandler extends UiMessageHandler { |
42 | 41 | ||
42 | + private static final String A_BOTH_B = "A ↔ B"; | ||
43 | + private static final String A_SINGLE_B = "A → B"; | ||
44 | + | ||
43 | private static final String LINK_DATA_REQ = "linkDataRequest"; | 45 | private static final String LINK_DATA_REQ = "linkDataRequest"; |
44 | private static final String LINK_DATA_RESP = "linkDataResponse"; | 46 | private static final String LINK_DATA_RESP = "linkDataResponse"; |
45 | private static final String LINKS = "links"; | 47 | private static final String LINKS = "links"; |
... | @@ -94,38 +96,39 @@ public class LinkViewMessageHandler extends UiMessageHandler { | ... | @@ -94,38 +96,39 @@ public class LinkViewMessageHandler extends UiMessageHandler { |
94 | 96 | ||
95 | // First consolidate all uni-directional links into two-directional ones. | 97 | // First consolidate all uni-directional links into two-directional ones. |
96 | Map<LinkKey, BiLink> biLinks = Maps.newHashMap(); | 98 | Map<LinkKey, BiLink> biLinks = Maps.newHashMap(); |
97 | - ls.getLinks().forEach(link -> addLink(biLinks, link)); | 99 | + ls.getLinks().forEach(link -> TopoUtils.addLink(biLinks, link)); |
98 | 100 | ||
99 | // Now scan over all bi-links and produce table rows from them. | 101 | // Now scan over all bi-links and produce table rows from them. |
100 | biLinks.values().forEach(biLink -> populateRow(tm.addRow(), biLink)); | 102 | biLinks.values().forEach(biLink -> populateRow(tm.addRow(), biLink)); |
101 | } | 103 | } |
102 | 104 | ||
103 | private void populateRow(TableModel.Row row, BiLink biLink) { | 105 | private void populateRow(TableModel.Row row, BiLink biLink) { |
104 | - row.cell(ONE, biLink.one.src()) | 106 | + row.cell(ONE, biLink.one().src()) |
105 | - .cell(TWO, biLink.one.dst()) | 107 | + .cell(TWO, biLink.one().dst()) |
106 | .cell(TYPE, linkType(biLink)) | 108 | .cell(TYPE, linkType(biLink)) |
107 | .cell(STATE, linkState(biLink)) | 109 | .cell(STATE, linkState(biLink)) |
108 | .cell(DIRECTION, linkDir(biLink)) | 110 | .cell(DIRECTION, linkDir(biLink)) |
109 | - .cell(DURABLE, biLink.one.isDurable()); | 111 | + .cell(DURABLE, biLink.one().isDurable()); |
110 | } | 112 | } |
111 | 113 | ||
112 | private String linkType(BiLink link) { | 114 | private String linkType(BiLink link) { |
113 | StringBuilder sb = new StringBuilder(); | 115 | StringBuilder sb = new StringBuilder(); |
114 | - sb.append(link.one.type()); | 116 | + sb.append(link.one().type()); |
115 | - if (link.two != null && link.two.type() != link.one.type()) { | 117 | + if (link.two() != null && link.two().type() != link.one().type()) { |
116 | - sb.append(" / ").append(link.two.type()); | 118 | + sb.append(" / ").append(link.two().type()); |
117 | } | 119 | } |
118 | return sb.toString(); | 120 | return sb.toString(); |
119 | } | 121 | } |
120 | 122 | ||
121 | private String linkState(BiLink link) { | 123 | private String linkState(BiLink link) { |
122 | - return (link.one.state() == Link.State.ACTIVE || | 124 | + return (link.one().state() == Link.State.ACTIVE || |
123 | - link.two.state() == Link.State.ACTIVE) ? | 125 | + link.two().state() == Link.State.ACTIVE) ? |
124 | ICON_ID_ONLINE : ICON_ID_OFFLINE; | 126 | ICON_ID_ONLINE : ICON_ID_OFFLINE; |
125 | } | 127 | } |
126 | 128 | ||
127 | private String linkDir(BiLink link) { | 129 | private String linkDir(BiLink link) { |
128 | - return link.two != null ? "A ↔ B" : "A → B"; | 130 | + return link.two() != null ? A_BOTH_B : A_SINGLE_B; |
129 | } | 131 | } |
130 | } | 132 | } |
133 | + | ||
131 | } | 134 | } | ... | ... |
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
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.impl.topo; | ||
19 | + | ||
20 | +import org.onosproject.net.Link; | ||
21 | +import org.onosproject.net.LinkKey; | ||
22 | +import org.onosproject.net.statistic.Load; | ||
23 | +import org.onosproject.ui.topo.LinkHighlight; | ||
24 | + | ||
25 | +import static org.onosproject.ui.topo.LinkHighlight.Flavor.NO_HIGHLIGHT; | ||
26 | +import static org.onosproject.ui.topo.LinkHighlight.Flavor.PRIMARY_HIGHLIGHT; | ||
27 | +import static org.onosproject.ui.topo.LinkHighlight.Flavor.SECONDARY_HIGHLIGHT; | ||
28 | + | ||
29 | +/** | ||
30 | + * Representation of a link and its inverse, and any associated traffic data. | ||
31 | + * This class understands how to generate {@link LinkHighlight}s for sending | ||
32 | + * back to the topology view. | ||
33 | + */ | ||
34 | +public class BiLink { | ||
35 | + | ||
36 | + private static final String EMPTY = ""; | ||
37 | + | ||
38 | + private final LinkKey key; | ||
39 | + private final Link one; | ||
40 | + private Link two; | ||
41 | + | ||
42 | + private boolean hasTraffic = false; | ||
43 | + private long bytes = 0; | ||
44 | + private long rate = 0; | ||
45 | + private long flows = 0; | ||
46 | + private boolean isOptical = false; | ||
47 | + private LinkHighlight.Flavor taggedFlavor = NO_HIGHLIGHT; | ||
48 | + private boolean antMarch = false; | ||
49 | + | ||
50 | + /** | ||
51 | + * Constructs a bilink for the given key and initial link. | ||
52 | + * | ||
53 | + * @param key canonical key for this bilink | ||
54 | + * @param link first link | ||
55 | + */ | ||
56 | + public BiLink(LinkKey key, Link link) { | ||
57 | + this.key = key; | ||
58 | + this.one = link; | ||
59 | + } | ||
60 | + | ||
61 | + /** | ||
62 | + * Sets the second link for this bilink. | ||
63 | + * | ||
64 | + * @param link second link | ||
65 | + */ | ||
66 | + public void setOther(Link link) { | ||
67 | + this.two = link; | ||
68 | + } | ||
69 | + | ||
70 | + /** | ||
71 | + * Sets the optical flag to the given value. | ||
72 | + * | ||
73 | + * @param b true if an optical link | ||
74 | + */ | ||
75 | + public void setOptical(boolean b) { | ||
76 | + isOptical = b; | ||
77 | + } | ||
78 | + | ||
79 | + /** | ||
80 | + * Sets the ant march flag to the given value. | ||
81 | + * | ||
82 | + * @param b true if marching ants required | ||
83 | + */ | ||
84 | + public void setAntMarch(boolean b) { | ||
85 | + antMarch = b; | ||
86 | + } | ||
87 | + | ||
88 | + /** | ||
89 | + * Tags this bilink with a link flavor to be used in visual rendering. | ||
90 | + * | ||
91 | + * @param flavor the flavor to tag | ||
92 | + */ | ||
93 | + public void tagFlavor(LinkHighlight.Flavor flavor) { | ||
94 | + this.taggedFlavor = flavor; | ||
95 | + } | ||
96 | + | ||
97 | + /** | ||
98 | + * Adds load statistics, marks the bilink as having traffic. | ||
99 | + * | ||
100 | + * @param load load to add | ||
101 | + */ | ||
102 | + public void addLoad(Load load) { | ||
103 | + addLoad(load, 0); | ||
104 | + } | ||
105 | + | ||
106 | + /** | ||
107 | + * Adds load statistics, marks the bilink as having traffic, if the | ||
108 | + * load rate is greater than the given threshold. | ||
109 | + * | ||
110 | + * @param load load to add | ||
111 | + * @param threshold threshold to register traffic | ||
112 | + */ | ||
113 | + public void addLoad(Load load, double threshold) { | ||
114 | + if (load != null) { | ||
115 | + this.hasTraffic = hasTraffic || load.rate() > threshold; | ||
116 | + this.bytes += load.latest(); | ||
117 | + this.rate += load.rate(); | ||
118 | + } | ||
119 | + } | ||
120 | + | ||
121 | + /** | ||
122 | + * Adds the given count of flows to this bilink. | ||
123 | + * | ||
124 | + * @param count count of flows | ||
125 | + */ | ||
126 | + public void addFlows(int count) { | ||
127 | + this.flows += count; | ||
128 | + } | ||
129 | + | ||
130 | + /** | ||
131 | + * Generates a link highlight entity, based on state of this bilink. | ||
132 | + * | ||
133 | + * @param type the type of statistics to use to interpret the data | ||
134 | + * @return link highlight data for this bilink | ||
135 | + */ | ||
136 | + public LinkHighlight generateHighlight(LinkStatsType type) { | ||
137 | + switch (type) { | ||
138 | + case FLOW_COUNT: | ||
139 | + return highlightForFlowCount(type); | ||
140 | + | ||
141 | + case FLOW_STATS: | ||
142 | + case PORT_STATS: | ||
143 | + return highlightForStats(type); | ||
144 | + | ||
145 | + case TAGGED: | ||
146 | + return highlightForTagging(type); | ||
147 | + | ||
148 | + default: | ||
149 | + throw new IllegalStateException("unexpected case: " + type); | ||
150 | + } | ||
151 | + } | ||
152 | + | ||
153 | + private LinkHighlight highlightForStats(LinkStatsType type) { | ||
154 | + return new LinkHighlight(linkId(), SECONDARY_HIGHLIGHT) | ||
155 | + .setLabel(generateLabel(type)); | ||
156 | + } | ||
157 | + | ||
158 | + private LinkHighlight highlightForFlowCount(LinkStatsType type) { | ||
159 | + LinkHighlight.Flavor flavor = flows() > 0 ? | ||
160 | + PRIMARY_HIGHLIGHT : SECONDARY_HIGHLIGHT; | ||
161 | + return new LinkHighlight(linkId(), flavor) | ||
162 | + .setLabel(generateLabel(type)); | ||
163 | + } | ||
164 | + | ||
165 | + private LinkHighlight highlightForTagging(LinkStatsType type) { | ||
166 | + LinkHighlight hlite = new LinkHighlight(linkId(), flavor()) | ||
167 | + .setLabel(generateLabel(type)); | ||
168 | + if (isOptical()) { | ||
169 | + hlite.addMod(LinkHighlight.MOD_OPTICAL); | ||
170 | + } | ||
171 | + if (isAntMarch()) { | ||
172 | + hlite.addMod(LinkHighlight.MOD_ANIMATED); | ||
173 | + } | ||
174 | + return hlite; | ||
175 | + } | ||
176 | + | ||
177 | + // Generates a link identifier in the form that the Topology View on the | ||
178 | + private String linkId() { | ||
179 | + return TopoUtils.compactLinkString(one); | ||
180 | + } | ||
181 | + | ||
182 | + // Generates a string representation of the load, to be used as a label | ||
183 | + private String generateLabel(LinkStatsType type) { | ||
184 | + switch (type) { | ||
185 | + case FLOW_COUNT: | ||
186 | + return TopoUtils.formatFlows(flows()); | ||
187 | + | ||
188 | + case FLOW_STATS: | ||
189 | + return TopoUtils.formatBytes(bytes()); | ||
190 | + | ||
191 | + case PORT_STATS: | ||
192 | + return TopoUtils.formatBitRate(rate()); | ||
193 | + | ||
194 | + case TAGGED: | ||
195 | + return hasTraffic() ? TopoUtils.formatBytes(bytes()) : EMPTY; | ||
196 | + | ||
197 | + default: | ||
198 | + return "?"; | ||
199 | + } | ||
200 | + } | ||
201 | + | ||
202 | + // === ---------------------------------------------------------------- | ||
203 | + // accessors | ||
204 | + | ||
205 | + public LinkKey key() { | ||
206 | + return key; | ||
207 | + } | ||
208 | + | ||
209 | + public Link one() { | ||
210 | + return one; | ||
211 | + } | ||
212 | + | ||
213 | + public Link two() { | ||
214 | + return two; | ||
215 | + } | ||
216 | + | ||
217 | + public boolean hasTraffic() { | ||
218 | + return hasTraffic; | ||
219 | + } | ||
220 | + | ||
221 | + public boolean isOptical() { | ||
222 | + return isOptical; | ||
223 | + } | ||
224 | + | ||
225 | + public boolean isAntMarch() { | ||
226 | + return antMarch; | ||
227 | + } | ||
228 | + | ||
229 | + public LinkHighlight.Flavor flavor() { | ||
230 | + return taggedFlavor; | ||
231 | + } | ||
232 | + | ||
233 | + public long bytes() { | ||
234 | + return bytes; | ||
235 | + } | ||
236 | + | ||
237 | + public long rate() { | ||
238 | + return rate; | ||
239 | + } | ||
240 | + | ||
241 | + public long flows() { | ||
242 | + return flows; | ||
243 | + } | ||
244 | +} |
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.impl.topo; | ||
19 | + | ||
20 | +import org.onosproject.net.intent.Intent; | ||
21 | +import org.slf4j.Logger; | ||
22 | +import org.slf4j.LoggerFactory; | ||
23 | + | ||
24 | +import java.util.ArrayList; | ||
25 | +import java.util.Collections; | ||
26 | +import java.util.List; | ||
27 | + | ||
28 | +/** | ||
29 | + * Encapsulates a selection of intents (paths) inferred from a selection | ||
30 | + * of devices and/or hosts from the topology view. | ||
31 | + */ | ||
32 | +public class IntentSelection { | ||
33 | + | ||
34 | + private static final int ALL = -1; | ||
35 | + | ||
36 | + protected static final Logger log = | ||
37 | + LoggerFactory.getLogger(IntentSelection.class); | ||
38 | + | ||
39 | + private final NodeSelection nodes; | ||
40 | + | ||
41 | + private final List<Intent> intents; | ||
42 | + private int index = ALL; | ||
43 | + | ||
44 | + /** | ||
45 | + * Creates an intent selection group, based on selected nodes. | ||
46 | + * | ||
47 | + * @param nodes node selection | ||
48 | + * @param filter intent filter | ||
49 | + */ | ||
50 | + public IntentSelection(NodeSelection nodes, TopologyViewIntentFilter filter) { | ||
51 | + this.nodes = nodes; | ||
52 | + intents = filter.findPathIntents(nodes.hosts(), nodes.devices()); | ||
53 | + } | ||
54 | + | ||
55 | + /** | ||
56 | + * Creates an intent selection group, for a single intent. | ||
57 | + * | ||
58 | + * @param intent the intent | ||
59 | + */ | ||
60 | + public IntentSelection(Intent intent) { | ||
61 | + nodes = null; | ||
62 | + intents = new ArrayList<>(1); | ||
63 | + intents.add(intent); | ||
64 | + index = 0; | ||
65 | + } | ||
66 | + | ||
67 | + /** | ||
68 | + * Returns true if no intents are selected. | ||
69 | + * | ||
70 | + * @return true if nothing selected | ||
71 | + */ | ||
72 | + public boolean none() { | ||
73 | + return intents.isEmpty(); | ||
74 | + } | ||
75 | + | ||
76 | + /** | ||
77 | + * Returns true if all intents in this select group are currently selected. | ||
78 | + * This is the initial state, so that all intents are shown on the | ||
79 | + * topology view with primary highlighting. | ||
80 | + * | ||
81 | + * @return true if all selected | ||
82 | + */ | ||
83 | + public boolean all() { | ||
84 | + return index == ALL; | ||
85 | + } | ||
86 | + | ||
87 | + /** | ||
88 | + * Returns true if there is a single intent in this select group, or if | ||
89 | + * a specific intent has been marked (index != ALL). | ||
90 | + * | ||
91 | + * @return true if single intent marked | ||
92 | + */ | ||
93 | + public boolean single() { | ||
94 | + return !all(); | ||
95 | + } | ||
96 | + | ||
97 | + /** | ||
98 | + * Returns the number of intents in this selection group. | ||
99 | + * | ||
100 | + * @return number of intents | ||
101 | + */ | ||
102 | + public int size() { | ||
103 | + return intents.size(); | ||
104 | + } | ||
105 | + | ||
106 | + /** | ||
107 | + * Returns the index of the currently selected intent. | ||
108 | + * | ||
109 | + * @return the current index | ||
110 | + */ | ||
111 | + public int index() { | ||
112 | + return index; | ||
113 | + } | ||
114 | + | ||
115 | + /** | ||
116 | + * The list of intents in this selection group. | ||
117 | + * | ||
118 | + * @return list of intents | ||
119 | + */ | ||
120 | + public List<Intent> intents() { | ||
121 | + return Collections.unmodifiableList(intents); | ||
122 | + } | ||
123 | + | ||
124 | + /** | ||
125 | + * Marks and returns the next intent in this group. Note that the | ||
126 | + * selection wraps around to the beginning again, if necessary. | ||
127 | + * | ||
128 | + * @return the next intent in the group | ||
129 | + */ | ||
130 | + public Intent next() { | ||
131 | + index += 1; | ||
132 | + if (index >= intents.size()) { | ||
133 | + index = 0; | ||
134 | + } | ||
135 | + return intents.get(index); | ||
136 | + } | ||
137 | + | ||
138 | + /** | ||
139 | + * Marks and returns the previous intent in this group. Note that the | ||
140 | + * selection wraps around to the end again, if necessary. | ||
141 | + * | ||
142 | + * @return the previous intent in the group | ||
143 | + */ | ||
144 | + public Intent prev() { | ||
145 | + index -= 1; | ||
146 | + if (index < 0) { | ||
147 | + index = intents.size() - 1; | ||
148 | + } | ||
149 | + return intents.get(index); | ||
150 | + } | ||
151 | + | ||
152 | + /** | ||
153 | + * Returns the currently marked intent, or null if "all" intents | ||
154 | + * are marked. | ||
155 | + * | ||
156 | + * @return the currently marked intent | ||
157 | + */ | ||
158 | + public Intent current() { | ||
159 | + return all() ? null : intents.get(index); | ||
160 | + } | ||
161 | + | ||
162 | + @Override | ||
163 | + public String toString() { | ||
164 | + return "IntentSelection{" + | ||
165 | + "nodes=" + nodes + | ||
166 | + ", #intents=" + intents.size() + | ||
167 | + ", index=" + index + | ||
168 | + '}'; | ||
169 | + } | ||
170 | + | ||
171 | +} |
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.impl.topo; | ||
19 | + | ||
20 | +/** | ||
21 | + * Designates type of stats to report on a highlighted link. | ||
22 | + */ | ||
23 | +public enum LinkStatsType { | ||
24 | + /** | ||
25 | + * Number of flows. | ||
26 | + */ | ||
27 | + FLOW_COUNT, | ||
28 | + | ||
29 | + /** | ||
30 | + * Number of bytes. | ||
31 | + */ | ||
32 | + FLOW_STATS, | ||
33 | + | ||
34 | + /** | ||
35 | + * Number of bits per second. | ||
36 | + */ | ||
37 | + PORT_STATS, | ||
38 | + | ||
39 | + /** | ||
40 | + * Custom tagged information. | ||
41 | + */ | ||
42 | + TAGGED | ||
43 | +} |
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.impl.topo; | ||
19 | + | ||
20 | +import com.fasterxml.jackson.databind.JsonNode; | ||
21 | +import com.fasterxml.jackson.databind.node.ArrayNode; | ||
22 | +import com.fasterxml.jackson.databind.node.ObjectNode; | ||
23 | +import org.onosproject.net.Device; | ||
24 | +import org.onosproject.net.Host; | ||
25 | +import org.onosproject.net.device.DeviceService; | ||
26 | +import org.onosproject.net.host.HostService; | ||
27 | +import org.onosproject.ui.JsonUtils; | ||
28 | +import org.slf4j.Logger; | ||
29 | +import org.slf4j.LoggerFactory; | ||
30 | + | ||
31 | +import java.util.Collections; | ||
32 | +import java.util.HashSet; | ||
33 | +import java.util.Set; | ||
34 | + | ||
35 | +import static com.google.common.base.Strings.isNullOrEmpty; | ||
36 | +import static org.onosproject.net.DeviceId.deviceId; | ||
37 | +import static org.onosproject.net.HostId.hostId; | ||
38 | + | ||
39 | +/** | ||
40 | + * Encapsulates a selection of devices and/or hosts from the topology view. | ||
41 | + */ | ||
42 | +public class NodeSelection { | ||
43 | + | ||
44 | + protected static final Logger log = | ||
45 | + LoggerFactory.getLogger(NodeSelection.class); | ||
46 | + | ||
47 | + private static final String IDS = "ids"; | ||
48 | + private static final String HOVER = "hover"; | ||
49 | + | ||
50 | + private final DeviceService deviceService; | ||
51 | + private final HostService hostService; | ||
52 | + | ||
53 | + private final Set<String> ids; | ||
54 | + private final String hover; | ||
55 | + | ||
56 | + private final Set<Device> devices = new HashSet<>(); | ||
57 | + private final Set<Host> hosts = new HashSet<>(); | ||
58 | + | ||
59 | + /** | ||
60 | + * Creates a node selection entity, from the given payload, using the | ||
61 | + * supplied device and host services. | ||
62 | + * | ||
63 | + * @param payload message payload | ||
64 | + * @param deviceService device service | ||
65 | + * @param hostService host service | ||
66 | + */ | ||
67 | + public NodeSelection(ObjectNode payload, | ||
68 | + DeviceService deviceService, | ||
69 | + HostService hostService) { | ||
70 | + this.deviceService = deviceService; | ||
71 | + this.hostService = hostService; | ||
72 | + | ||
73 | + ids = extractIds(payload); | ||
74 | + hover = extractHover(payload); | ||
75 | + | ||
76 | + Set<String> unmatched = findDevices(ids); | ||
77 | + unmatched = findHosts(unmatched); | ||
78 | + if (unmatched.size() > 0) { | ||
79 | + log.debug("Skipping unmatched IDs {}", unmatched); | ||
80 | + } | ||
81 | + | ||
82 | + if (!isNullOrEmpty(hover)) { | ||
83 | + unmatched = new HashSet<>(); | ||
84 | + unmatched.add(hover); | ||
85 | + unmatched = findDevices(unmatched); | ||
86 | + unmatched = findHosts(unmatched); | ||
87 | + if (unmatched.size() > 0) { | ||
88 | + log.debug("Skipping unmatched HOVER {}", unmatched); | ||
89 | + } | ||
90 | + } | ||
91 | + } | ||
92 | + | ||
93 | + /** | ||
94 | + * Returns a view of the selected devices. | ||
95 | + * | ||
96 | + * @return selected devices | ||
97 | + */ | ||
98 | + public Set<Device> devices() { | ||
99 | + return Collections.unmodifiableSet(devices); | ||
100 | + } | ||
101 | + | ||
102 | + /** | ||
103 | + * Returns a view of the selected hosts. | ||
104 | + * | ||
105 | + * @return selected hosts | ||
106 | + */ | ||
107 | + public Set<Host> hosts() { | ||
108 | + return Collections.unmodifiableSet(hosts); | ||
109 | + } | ||
110 | + | ||
111 | + /** | ||
112 | + * Returns true if nothing is selected. | ||
113 | + * | ||
114 | + * @return true if nothing selected | ||
115 | + */ | ||
116 | + public boolean none() { | ||
117 | + return devices().size() == 0 && hosts().size() == 0; | ||
118 | + } | ||
119 | + | ||
120 | + @Override | ||
121 | + public String toString() { | ||
122 | + return "NodeSelection{" + | ||
123 | + "ids=" + ids + | ||
124 | + ", hover='" + hover + '\'' + | ||
125 | + ", #devices=" + devices.size() + | ||
126 | + ", #hosts=" + hosts.size() + | ||
127 | + '}'; | ||
128 | + } | ||
129 | + | ||
130 | + // == helper methods | ||
131 | + | ||
132 | + private Set<String> extractIds(ObjectNode payload) { | ||
133 | + ArrayNode array = (ArrayNode) payload.path(IDS); | ||
134 | + if (array == null || array.size() == 0) { | ||
135 | + return Collections.emptySet(); | ||
136 | + } | ||
137 | + | ||
138 | + Set<String> ids = new HashSet<>(); | ||
139 | + for (JsonNode node : array) { | ||
140 | + ids.add(node.asText()); | ||
141 | + } | ||
142 | + return ids; | ||
143 | + } | ||
144 | + | ||
145 | + private String extractHover(ObjectNode payload) { | ||
146 | + return JsonUtils.string(payload, HOVER); | ||
147 | + } | ||
148 | + | ||
149 | + private Set<String> findDevices(Set<String> ids) { | ||
150 | + Set<String> unmatched = new HashSet<>(); | ||
151 | + Device device; | ||
152 | + | ||
153 | + for (String id : ids) { | ||
154 | + try { | ||
155 | + device = deviceService.getDevice(deviceId(id)); | ||
156 | + if (device != null) { | ||
157 | + devices.add(device); | ||
158 | + } else { | ||
159 | + log.debug("Device with ID {} not found", id); | ||
160 | + } | ||
161 | + } catch (IllegalArgumentException e) { | ||
162 | + unmatched.add(id); | ||
163 | + } | ||
164 | + } | ||
165 | + return unmatched; | ||
166 | + } | ||
167 | + | ||
168 | + private Set<String> findHosts(Set<String> ids) { | ||
169 | + Set<String> unmatched = new HashSet<>(); | ||
170 | + Host host; | ||
171 | + | ||
172 | + for (String id : ids) { | ||
173 | + try { | ||
174 | + host = hostService.getHost(hostId(id)); | ||
175 | + if (host != null) { | ||
176 | + hosts.add(host); | ||
177 | + } else { | ||
178 | + log.debug("Host with ID {} not found", id); | ||
179 | + } | ||
180 | + } catch (IllegalArgumentException e) { | ||
181 | + unmatched.add(id); | ||
182 | + } | ||
183 | + } | ||
184 | + return unmatched; | ||
185 | + } | ||
186 | + | ||
187 | +} |
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.impl.topo; | ||
19 | + | ||
20 | +import org.onosproject.incubator.net.PortStatisticsService; | ||
21 | +import org.onosproject.net.device.DeviceService; | ||
22 | +import org.onosproject.net.flow.FlowRuleService; | ||
23 | +import org.onosproject.net.host.HostService; | ||
24 | +import org.onosproject.net.intent.IntentService; | ||
25 | +import org.onosproject.net.link.LinkService; | ||
26 | +import org.onosproject.net.statistic.StatisticService; | ||
27 | + | ||
28 | +import static com.google.common.base.Preconditions.checkNotNull; | ||
29 | + | ||
30 | +/** | ||
31 | + * A bundle of services that the topology view requires to get its job done. | ||
32 | + */ | ||
33 | +public class ServicesBundle { | ||
34 | + | ||
35 | + private final IntentService intentService; | ||
36 | + private final DeviceService deviceService; | ||
37 | + private final HostService hostService; | ||
38 | + private final LinkService linkService; | ||
39 | + private final FlowRuleService flowService; | ||
40 | + private final StatisticService flowStatsService; | ||
41 | + private final PortStatisticsService portStatsService; | ||
42 | + | ||
43 | + /** | ||
44 | + * Creates the services bundle. | ||
45 | + * @param intentService intent service reference | ||
46 | + * @param deviceService device service reference | ||
47 | + * @param hostService host service reference | ||
48 | + * @param linkService link service reference | ||
49 | + * @param flowService flow service reference | ||
50 | + * @param flowStatsService flow statistics service reference | ||
51 | + * @param portStatsService port statistics service reference | ||
52 | + */ | ||
53 | + public ServicesBundle(IntentService intentService, | ||
54 | + DeviceService deviceService, | ||
55 | + HostService hostService, | ||
56 | + LinkService linkService, | ||
57 | + FlowRuleService flowService, | ||
58 | + StatisticService flowStatsService, | ||
59 | + PortStatisticsService portStatsService) { | ||
60 | + this.intentService = checkNotNull(intentService); | ||
61 | + this.deviceService = checkNotNull(deviceService); | ||
62 | + this.hostService = checkNotNull(hostService); | ||
63 | + this.linkService = checkNotNull(linkService); | ||
64 | + this.flowService = checkNotNull(flowService); | ||
65 | + this.flowStatsService = checkNotNull(flowStatsService); | ||
66 | + this.portStatsService = checkNotNull(portStatsService); | ||
67 | + } | ||
68 | + | ||
69 | + public IntentService intentService() { | ||
70 | + return intentService; | ||
71 | + } | ||
72 | + | ||
73 | + public DeviceService deviceService() { | ||
74 | + return deviceService; | ||
75 | + } | ||
76 | + | ||
77 | + public HostService hostService() { | ||
78 | + return hostService; | ||
79 | + } | ||
80 | + | ||
81 | + public LinkService linkService() { | ||
82 | + return linkService; | ||
83 | + } | ||
84 | + | ||
85 | + public FlowRuleService flowService() { | ||
86 | + return flowService; | ||
87 | + } | ||
88 | + | ||
89 | + public StatisticService flowStatsService() { | ||
90 | + return flowStatsService; | ||
91 | + } | ||
92 | + | ||
93 | + public PortStatisticsService portStatsService() { | ||
94 | + return portStatsService; | ||
95 | + } | ||
96 | +} |
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.impl.topo; | ||
19 | + | ||
20 | +import org.onosproject.net.Link; | ||
21 | +import org.onosproject.net.LinkKey; | ||
22 | + | ||
23 | +import java.text.DecimalFormat; | ||
24 | +import java.util.Map; | ||
25 | + | ||
26 | +import static org.onosproject.net.LinkKey.linkKey; | ||
27 | + | ||
28 | +/** | ||
29 | + * Utility methods for helping out with the topology view. | ||
30 | + */ | ||
31 | +public final class TopoUtils { | ||
32 | + | ||
33 | + public static final double KILO = 1024; | ||
34 | + public static final double MEGA = 1024 * KILO; | ||
35 | + public static final double GIGA = 1024 * MEGA; | ||
36 | + | ||
37 | + public static final String GBITS_UNIT = "Gb"; | ||
38 | + public static final String MBITS_UNIT = "Mb"; | ||
39 | + public static final String KBITS_UNIT = "Kb"; | ||
40 | + public static final String BITS_UNIT = "b"; | ||
41 | + public static final String GBYTES_UNIT = "GB"; | ||
42 | + public static final String MBYTES_UNIT = "MB"; | ||
43 | + public static final String KBYTES_UNIT = "KB"; | ||
44 | + public static final String BYTES_UNIT = "B"; | ||
45 | + | ||
46 | + | ||
47 | + private static final DecimalFormat DF2 = new DecimalFormat("#,###.##"); | ||
48 | + | ||
49 | + private static final String COMPACT = "%s/%s-%s/%s"; | ||
50 | + private static final String EMPTY = ""; | ||
51 | + private static final String SPACE = " "; | ||
52 | + private static final String PER_SEC = "ps"; | ||
53 | + private static final String FLOW = "flow"; | ||
54 | + private static final String FLOWS = "flows"; | ||
55 | + | ||
56 | + // non-instantiable | ||
57 | + private TopoUtils() { } | ||
58 | + | ||
59 | + /** | ||
60 | + * Returns a compact identity for the given link, in the form | ||
61 | + * used to identify links in the Topology View on the client. | ||
62 | + * | ||
63 | + * @param link link | ||
64 | + * @return compact link identity | ||
65 | + */ | ||
66 | + public static String compactLinkString(Link link) { | ||
67 | + return String.format(COMPACT, link.src().elementId(), link.src().port(), | ||
68 | + link.dst().elementId(), link.dst().port()); | ||
69 | + } | ||
70 | + | ||
71 | + /** | ||
72 | + * Produces a canonical link key, that is, one that will match both a link | ||
73 | + * and its inverse. | ||
74 | + * | ||
75 | + * @param link the link | ||
76 | + * @return canonical key | ||
77 | + */ | ||
78 | + public static LinkKey canonicalLinkKey(Link link) { | ||
79 | + String sn = link.src().elementId().toString(); | ||
80 | + String dn = link.dst().elementId().toString(); | ||
81 | + return sn.compareTo(dn) < 0 ? | ||
82 | + linkKey(link.src(), link.dst()) : linkKey(link.dst(), link.src()); | ||
83 | + } | ||
84 | + | ||
85 | + /** | ||
86 | + * Returns human readable count of bytes, to be displayed as a label. | ||
87 | + * | ||
88 | + * @param bytes number of bytes | ||
89 | + * @return formatted byte count | ||
90 | + */ | ||
91 | + public static String formatBytes(long bytes) { | ||
92 | + String unit; | ||
93 | + double value; | ||
94 | + if (bytes > GIGA) { | ||
95 | + value = bytes / GIGA; | ||
96 | + unit = GBYTES_UNIT; | ||
97 | + } else if (bytes > MEGA) { | ||
98 | + value = bytes / MEGA; | ||
99 | + unit = MBYTES_UNIT; | ||
100 | + } else if (bytes > KILO) { | ||
101 | + value = bytes / KILO; | ||
102 | + unit = KBYTES_UNIT; | ||
103 | + } else { | ||
104 | + value = bytes; | ||
105 | + unit = BYTES_UNIT; | ||
106 | + } | ||
107 | + return DF2.format(value) + SPACE + unit; | ||
108 | + } | ||
109 | + | ||
110 | + /** | ||
111 | + * Returns human readable bit rate, to be displayed as a label. | ||
112 | + * | ||
113 | + * @param bytes bytes per second | ||
114 | + * @return formatted bits per second | ||
115 | + */ | ||
116 | + public static String formatBitRate(long bytes) { | ||
117 | + String unit; | ||
118 | + double value; | ||
119 | + | ||
120 | + //Convert to bits | ||
121 | + long bits = bytes * 8; | ||
122 | + if (bits > GIGA) { | ||
123 | + value = bits / GIGA; | ||
124 | + unit = GBITS_UNIT; | ||
125 | + | ||
126 | + // NOTE: temporary hack to clip rate at 10.0 Gbps | ||
127 | + // Added for the CORD Fabric demo at ONS 2015 | ||
128 | + // TODO: provide a more elegant solution to this issue | ||
129 | + if (value > 10.0) { | ||
130 | + value = 10.0; | ||
131 | + } | ||
132 | + | ||
133 | + } else if (bits > MEGA) { | ||
134 | + value = bits / MEGA; | ||
135 | + unit = MBITS_UNIT; | ||
136 | + } else if (bits > KILO) { | ||
137 | + value = bits / KILO; | ||
138 | + unit = KBITS_UNIT; | ||
139 | + } else { | ||
140 | + value = bits; | ||
141 | + unit = BITS_UNIT; | ||
142 | + } | ||
143 | + return DF2.format(value) + SPACE + unit + PER_SEC; | ||
144 | + } | ||
145 | + | ||
146 | + /** | ||
147 | + * Returns human readable flow count, to be displayed as a label. | ||
148 | + * | ||
149 | + * @param flows number of flows | ||
150 | + * @return formatted flow count | ||
151 | + */ | ||
152 | + public static String formatFlows(long flows) { | ||
153 | + if (flows < 1) { | ||
154 | + return EMPTY; | ||
155 | + } | ||
156 | + return String.valueOf(flows) + SPACE + (flows > 1 ? FLOWS : FLOW); | ||
157 | + } | ||
158 | + | ||
159 | + | ||
160 | + /** | ||
161 | + * Creates a new biLink with the supplied link (and adds it to the map), | ||
162 | + * or attaches the link to an existing biLink (which already has the | ||
163 | + * peer link). | ||
164 | + * | ||
165 | + * @param linkMap map of biLinks | ||
166 | + * @param link the link to add | ||
167 | + * @return the biLink to which the link was added | ||
168 | + */ | ||
169 | + // creates a new biLink with supplied link, or attaches link to the | ||
170 | + // existing biLink (which already has its peer link) | ||
171 | + public static BiLink addLink(Map<LinkKey, BiLink> linkMap, Link link) { | ||
172 | + LinkKey key = TopoUtils.canonicalLinkKey(link); | ||
173 | + BiLink biLink = linkMap.get(key); | ||
174 | + if (biLink != null) { | ||
175 | + biLink.setOther(link); | ||
176 | + } else { | ||
177 | + biLink = new BiLink(key, link); | ||
178 | + linkMap.put(key, biLink); | ||
179 | + } | ||
180 | + return biLink; | ||
181 | + } | ||
182 | + | ||
183 | + | ||
184 | +} |
... | @@ -13,7 +13,7 @@ | ... | @@ -13,7 +13,7 @@ |
13 | * See the License for the specific language governing permissions and | 13 | * See the License for the specific language governing permissions and |
14 | * limitations under the License. | 14 | * limitations under the License. |
15 | */ | 15 | */ |
16 | -package org.onosproject.ui.impl; | 16 | +package org.onosproject.ui.impl.topo; |
17 | 17 | ||
18 | import org.onosproject.net.ConnectPoint; | 18 | import org.onosproject.net.ConnectPoint; |
19 | import org.onosproject.net.Device; | 19 | import org.onosproject.net.Device; |
... | @@ -56,32 +56,35 @@ public class TopologyViewIntentFilter { | ... | @@ -56,32 +56,35 @@ public class TopologyViewIntentFilter { |
56 | private final LinkService linkService; | 56 | private final LinkService linkService; |
57 | 57 | ||
58 | /** | 58 | /** |
59 | - * Crreates an intent filter. | 59 | + * Creates an intent filter. |
60 | * | 60 | * |
61 | - * @param intentService intent service reference | 61 | + * @param services service references bundle |
62 | - * @param deviceService device service reference | ||
63 | - * @param hostService host service reference | ||
64 | - * @param linkService link service reference | ||
65 | */ | 62 | */ |
66 | - TopologyViewIntentFilter(IntentService intentService, DeviceService deviceService, | 63 | + public TopologyViewIntentFilter(ServicesBundle services) { |
67 | - HostService hostService, LinkService linkService) { | 64 | + this.intentService = services.intentService(); |
68 | - this.intentService = intentService; | 65 | + this.deviceService = services.deviceService(); |
69 | - this.deviceService = deviceService; | 66 | + this.hostService = services.hostService(); |
70 | - this.hostService = hostService; | 67 | + this.linkService = services.linkService(); |
71 | - this.linkService = linkService; | ||
72 | } | 68 | } |
73 | 69 | ||
70 | + | ||
71 | + // TODO: Review - do we need this signature, with sourceIntents?? | ||
72 | +// public List<Intent> findPathIntents(Set<Host> hosts, Set<Device> devices, | ||
73 | +// Iterable<Intent> sourceIntents) { | ||
74 | +// } | ||
75 | + | ||
74 | /** | 76 | /** |
75 | - * Finds all path (host-to-host or point-to-point) intents that pertains | 77 | + * Finds all path (host-to-host or point-to-point) intents that pertain |
76 | - * to the given hosts. | 78 | + * to the given hosts and devices. |
77 | * | 79 | * |
78 | * @param hosts set of hosts to query by | 80 | * @param hosts set of hosts to query by |
79 | * @param devices set of devices to query by | 81 | * @param devices set of devices to query by |
80 | - * @param sourceIntents collection of intents to search | ||
81 | * @return set of intents that 'match' all hosts and devices given | 82 | * @return set of intents that 'match' all hosts and devices given |
82 | */ | 83 | */ |
83 | - List<Intent> findPathIntents(Set<Host> hosts, Set<Device> devices, | 84 | + public List<Intent> findPathIntents(Set<Host> hosts, Set<Device> devices) { |
84 | - Iterable<Intent> sourceIntents) { | 85 | + // start with all intents |
86 | + Iterable<Intent> sourceIntents = intentService.getIntents(); | ||
87 | + | ||
85 | // Derive from this the set of edge connect points. | 88 | // Derive from this the set of edge connect points. |
86 | Set<ConnectPoint> edgePoints = getEdgePoints(hosts); | 89 | Set<ConnectPoint> edgePoints = getEdgePoints(hosts); |
87 | 90 | ... | ... |
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.impl.topo; | ||
19 | + | ||
20 | +import org.onosproject.net.intent.Intent; | ||
21 | +import org.onosproject.ui.topo.LinkHighlight; | ||
22 | + | ||
23 | +/** | ||
24 | + * Auxiliary data carrier for assigning a highlight class to a set of | ||
25 | + * intents, for visualization in the topology view. | ||
26 | + */ | ||
27 | +public class TrafficClass { | ||
28 | + | ||
29 | + private final LinkHighlight.Flavor flavor; | ||
30 | + private final Iterable<Intent> intents; | ||
31 | + private final boolean showTraffic; | ||
32 | + | ||
33 | + public TrafficClass(LinkHighlight.Flavor flavor, Iterable<Intent> intents) { | ||
34 | + this(flavor, intents, false); | ||
35 | + } | ||
36 | + | ||
37 | + public TrafficClass(LinkHighlight.Flavor flavor, Iterable<Intent> intents, | ||
38 | + boolean showTraffic) { | ||
39 | + this.flavor = flavor; | ||
40 | + this.intents = intents; | ||
41 | + this.showTraffic = showTraffic; | ||
42 | + } | ||
43 | + | ||
44 | + public LinkHighlight.Flavor flavor() { | ||
45 | + return flavor; | ||
46 | + } | ||
47 | + | ||
48 | + public Iterable<Intent> intents() { | ||
49 | + return intents; | ||
50 | + } | ||
51 | + | ||
52 | + public boolean showTraffic() { | ||
53 | + return showTraffic; | ||
54 | + } | ||
55 | +} |
... | @@ -58,6 +58,7 @@ | ... | @@ -58,6 +58,7 @@ |
58 | showHosts = false, // whether hosts are displayed | 58 | showHosts = false, // whether hosts are displayed |
59 | showOffline = true, // whether offline devices are displayed | 59 | showOffline = true, // whether offline devices are displayed |
60 | nodeLock = false, // whether nodes can be dragged or not (locked) | 60 | nodeLock = false, // whether nodes can be dragged or not (locked) |
61 | + fTimer, // timer for delayed force layout | ||
61 | fNodesTimer, // timer for delayed nodes update | 62 | fNodesTimer, // timer for delayed nodes update |
62 | fLinksTimer, // timer for delayed links update | 63 | fLinksTimer, // timer for delayed links update |
63 | dim, // the dimensions of the force layout [w,h] | 64 | dim, // the dimensions of the force layout [w,h] |
... | @@ -117,6 +118,7 @@ | ... | @@ -117,6 +118,7 @@ |
117 | network.nodes.push(d); | 118 | network.nodes.push(d); |
118 | lu[id] = d; | 119 | lu[id] = d; |
119 | updateNodes(); | 120 | updateNodes(); |
121 | + fStart(); | ||
120 | } | 122 | } |
121 | 123 | ||
122 | function updateDevice(data) { | 124 | function updateDevice(data) { |
... | @@ -170,6 +172,7 @@ | ... | @@ -170,6 +172,7 @@ |
170 | lu[d.egress] = lnk; | 172 | lu[d.egress] = lnk; |
171 | updateLinks(); | 173 | updateLinks(); |
172 | } | 174 | } |
175 | + fStart(); | ||
173 | } | 176 | } |
174 | 177 | ||
175 | function updateHost(data) { | 178 | function updateHost(data) { |
... | @@ -215,6 +218,7 @@ | ... | @@ -215,6 +218,7 @@ |
215 | aggregateLink(d, data); | 218 | aggregateLink(d, data); |
216 | lu[d.key] = d; | 219 | lu[d.key] = d; |
217 | updateLinks(); | 220 | updateLinks(); |
221 | + fStart(); | ||
218 | } | 222 | } |
219 | } | 223 | } |
220 | 224 | ||
... | @@ -322,6 +326,7 @@ | ... | @@ -322,6 +326,7 @@ |
322 | // remove from lookup cache | 326 | // remove from lookup cache |
323 | delete lu[removed[0].key]; | 327 | delete lu[removed[0].key]; |
324 | updateLinks(); | 328 | updateLinks(); |
329 | + fResume(); | ||
325 | } | 330 | } |
326 | } | 331 | } |
327 | 332 | ||
... | @@ -343,6 +348,7 @@ | ... | @@ -343,6 +348,7 @@ |
343 | // NOTE: upd is false if we were called from removeDeviceElement() | 348 | // NOTE: upd is false if we were called from removeDeviceElement() |
344 | if (upd) { | 349 | if (upd) { |
345 | updateNodes(); | 350 | updateNodes(); |
351 | + fResume(); | ||
346 | } | 352 | } |
347 | } | 353 | } |
348 | 354 | ||
... | @@ -367,6 +373,7 @@ | ... | @@ -367,6 +373,7 @@ |
367 | 373 | ||
368 | // remove from SVG | 374 | // remove from SVG |
369 | updateNodes(); | 375 | updateNodes(); |
376 | + fResume(); | ||
370 | } | 377 | } |
371 | 378 | ||
372 | function updateHostVisibility() { | 379 | function updateHostVisibility() { |
... | @@ -520,8 +527,9 @@ | ... | @@ -520,8 +527,9 @@ |
520 | fNodesTimer = $timeout(_updateNodes, 150); | 527 | fNodesTimer = $timeout(_updateNodes, 150); |
521 | } | 528 | } |
522 | 529 | ||
530 | + // IMPLEMENTATION NOTE: _updateNodes() should NOT stop, start, or resume | ||
531 | + // the force layout; that needs to be determined and implemented elsewhere | ||
523 | function _updateNodes() { | 532 | function _updateNodes() { |
524 | - force.stop(); | ||
525 | // select all the nodes in the layout: | 533 | // select all the nodes in the layout: |
526 | node = nodeG.selectAll('.node') | 534 | node = nodeG.selectAll('.node') |
527 | .data(network.nodes, function (d) { return d.id; }); | 535 | .data(network.nodes, function (d) { return d.id; }); |
... | @@ -536,7 +544,10 @@ | ... | @@ -536,7 +544,10 @@ |
536 | .attr({ | 544 | .attr({ |
537 | id: function (d) { return sus.safeId(d.id); }, | 545 | id: function (d) { return sus.safeId(d.id); }, |
538 | class: mkSvgClass, | 546 | class: mkSvgClass, |
539 | - transform: function (d) { return sus.translate(d.x, d.y); }, | 547 | + transform: function (d) { |
548 | + // Need to guard against NaN here ?? | ||
549 | + return sus.translate(d.x, d.y); | ||
550 | + }, | ||
540 | opacity: 0 | 551 | opacity: 0 |
541 | }) | 552 | }) |
542 | .call(drag) | 553 | .call(drag) |
... | @@ -564,7 +575,6 @@ | ... | @@ -564,7 +575,6 @@ |
564 | // exiting node specifics: | 575 | // exiting node specifics: |
565 | exiting.filter('.host').each(td3.hostExit); | 576 | exiting.filter('.host').each(td3.hostExit); |
566 | exiting.filter('.device').each(td3.deviceExit); | 577 | exiting.filter('.device').each(td3.deviceExit); |
567 | - fStart(); | ||
568 | } | 578 | } |
569 | 579 | ||
570 | // ========================== | 580 | // ========================== |
... | @@ -659,9 +669,10 @@ | ... | @@ -659,9 +669,10 @@ |
659 | fLinksTimer = $timeout(_updateLinks, 150); | 669 | fLinksTimer = $timeout(_updateLinks, 150); |
660 | } | 670 | } |
661 | 671 | ||
672 | + // IMPLEMENTATION NOTE: _updateLinks() should NOT stop, start, or resume | ||
673 | + // the force layout; that needs to be determined and implemented elsewhere | ||
662 | function _updateLinks() { | 674 | function _updateLinks() { |
663 | var th = ts.theme(); | 675 | var th = ts.theme(); |
664 | - force.stop(); | ||
665 | 676 | ||
666 | link = linkG.selectAll('.link') | 677 | link = linkG.selectAll('.link') |
667 | .data(network.links, function (d) { return d.key; }); | 678 | .data(network.links, function (d) { return d.key; }); |
... | @@ -714,7 +725,6 @@ | ... | @@ -714,7 +725,6 @@ |
714 | }) | 725 | }) |
715 | .style('opacity', 0.0) | 726 | .style('opacity', 0.0) |
716 | .remove(); | 727 | .remove(); |
717 | - fStart(); | ||
718 | } | 728 | } |
719 | 729 | ||
720 | 730 | ||
... | @@ -729,14 +739,23 @@ | ... | @@ -729,14 +739,23 @@ |
729 | 739 | ||
730 | function fStart() { | 740 | function fStart() { |
731 | if (!tos.isOblique()) { | 741 | if (!tos.isOblique()) { |
742 | + if (fTimer) { | ||
743 | + $timeout.cancel(fTimer); | ||
744 | + } | ||
745 | + fTimer = $timeout(function () { | ||
732 | $log.debug("Starting force-layout"); | 746 | $log.debug("Starting force-layout"); |
733 | force.start(); | 747 | force.start(); |
748 | + }, 200); | ||
734 | } | 749 | } |
735 | } | 750 | } |
736 | 751 | ||
737 | var tickStuff = { | 752 | var tickStuff = { |
738 | nodeAttr: { | 753 | nodeAttr: { |
739 | - transform: function (d) { return sus.translate(d.x, d.y); } | 754 | + transform: function (d) { |
755 | + var dx = isNaN(d.x) ? 0 : d.x, | ||
756 | + dy = isNaN(d.y) ? 0 : d.y; | ||
757 | + return sus.translate(dx, dy); | ||
758 | + } | ||
740 | }, | 759 | }, |
741 | linkAttr: { | 760 | linkAttr: { |
742 | x1: function (d) { return d.position.x1; }, | 761 | x1: function (d) { return d.position.x1; }, |
... | @@ -1046,6 +1065,9 @@ | ... | @@ -1046,6 +1065,9 @@ |
1046 | force = drag = null; | 1065 | force = drag = null; |
1047 | 1066 | ||
1048 | // clean up $timeout promises | 1067 | // clean up $timeout promises |
1068 | + if (fTimer) { | ||
1069 | + $timeout.cancel(fTimer); | ||
1070 | + } | ||
1049 | if (fNodesTimer) { | 1071 | if (fNodesTimer) { |
1050 | $timeout.cancel(fNodesTimer); | 1072 | $timeout.cancel(fNodesTimer); |
1051 | } | 1073 | } | ... | ... |
... | @@ -293,7 +293,7 @@ | ... | @@ -293,7 +293,7 @@ |
293 | findLinkById( id ) | 293 | findLinkById( id ) |
294 | */ | 294 | */ |
295 | 295 | ||
296 | - var paths = data.paths; | 296 | + var paths = data.links; |
297 | 297 | ||
298 | api.clearLinkTrafficStyle(); | 298 | api.clearLinkTrafficStyle(); |
299 | api.removeLinkLabels(); | 299 | api.removeLinkLabels(); | ... | ... |
... | @@ -114,7 +114,7 @@ | ... | @@ -114,7 +114,7 @@ |
114 | } | 114 | } |
115 | 115 | ||
116 | if (!ev.shiftKey) { | 116 | if (!ev.shiftKey) { |
117 | - deselectAll(); | 117 | + deselectAll(true); |
118 | } | 118 | } |
119 | 119 | ||
120 | selections[obj.id] = { obj: obj, el: el }; | 120 | selections[obj.id] = { obj: obj, el: el }; |
... | @@ -135,7 +135,7 @@ | ... | @@ -135,7 +135,7 @@ |
135 | } | 135 | } |
136 | } | 136 | } |
137 | 137 | ||
138 | - function deselectAll() { | 138 | + function deselectAll(skipUpdate) { |
139 | var something = (selectOrder.length > 0); | 139 | var something = (selectOrder.length > 0); |
140 | 140 | ||
141 | // deselect all nodes in the network... | 141 | // deselect all nodes in the network... |
... | @@ -143,7 +143,9 @@ | ... | @@ -143,7 +143,9 @@ |
143 | selections = {}; | 143 | selections = {}; |
144 | selectOrder = []; | 144 | selectOrder = []; |
145 | api.updateDeviceColors(); | 145 | api.updateDeviceColors(); |
146 | + if (!skipUpdate) { | ||
146 | updateDetail(); | 147 | updateDetail(); |
148 | + } | ||
147 | 149 | ||
148 | // return true if something was selected | 150 | // return true if something was selected |
149 | return something; | 151 | return something; | ... | ... |
... | @@ -42,9 +42,9 @@ | ... | @@ -42,9 +42,9 @@ |
42 | 42 | ||
43 | // invoked in response to change in selection and/or mouseover/out: | 43 | // invoked in response to change in selection and/or mouseover/out: |
44 | function requestTrafficForMode() { | 44 | function requestTrafficForMode() { |
45 | - if (hoverMode === 'flows') { | 45 | + if (trafficMode === 'flows') { |
46 | requestDeviceLinkFlows(); | 46 | requestDeviceLinkFlows(); |
47 | - } else if (hoverMode === 'intents') { | 47 | + } else if (trafficMode === 'intents') { |
48 | requestRelatedIntents(); | 48 | requestRelatedIntents(); |
49 | } else { | 49 | } else { |
50 | cancelTraffic(); | 50 | cancelTraffic(); |
... | @@ -175,7 +175,6 @@ | ... | @@ -175,7 +175,6 @@ |
175 | } | 175 | } |
176 | 176 | ||
177 | 177 | ||
178 | - | ||
179 | // === ----------------------------------------------------- | 178 | // === ----------------------------------------------------- |
180 | // === MODULE DEFINITION === | 179 | // === MODULE DEFINITION === |
181 | 180 | ... | ... |
-
Please register or login to post a comment