blob: f906546fbfe94ff55ec69524f80309b7e74c44db [file] [log] [blame]
Simon Hunta17fa672015-08-19 18:42:22 -07001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2015-present Open Networking Laboratory
Simon Hunta17fa672015-08-19 18:42:22 -07003 *
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.
Simon Hunta17fa672015-08-19 18:42:22 -070015 */
16
Simon Hunt191c84a2015-08-21 08:24:48 -070017package org.onosproject.ui.topo;
Simon Hunta17fa672015-08-19 18:42:22 -070018
19import com.fasterxml.jackson.databind.JsonNode;
20import com.fasterxml.jackson.databind.node.ArrayNode;
21import com.fasterxml.jackson.databind.node.ObjectNode;
Prince Pereira46c82d42016-09-19 13:30:50 +053022import org.onosproject.net.ConnectPoint;
Simon Hunta17fa672015-08-19 18:42:22 -070023import org.onosproject.net.Device;
Simon Hunt72297212015-08-25 10:15:33 -070024import org.onosproject.net.Element;
Simon Hunta17fa672015-08-19 18:42:22 -070025import org.onosproject.net.Host;
Prince Pereira46c82d42016-09-19 13:30:50 +053026import org.onosproject.net.Link;
Simon Hunta17fa672015-08-19 18:42:22 -070027import org.onosproject.net.device.DeviceService;
28import org.onosproject.net.host.HostService;
Prince Pereira46c82d42016-09-19 13:30:50 +053029import org.onosproject.net.link.LinkService;
Simon Hunta17fa672015-08-19 18:42:22 -070030import org.onosproject.ui.JsonUtils;
31import org.slf4j.Logger;
32import org.slf4j.LoggerFactory;
33
34import java.util.Collections;
35import java.util.HashSet;
36import java.util.Set;
37
38import static com.google.common.base.Strings.isNullOrEmpty;
Prince Pereira46c82d42016-09-19 13:30:50 +053039import static org.onosproject.net.ConnectPoint.deviceConnectPoint;
Simon Hunta17fa672015-08-19 18:42:22 -070040import static org.onosproject.net.DeviceId.deviceId;
41import static org.onosproject.net.HostId.hostId;
42
43/**
Prince Pereira46c82d42016-09-19 13:30:50 +053044 * Encapsulates a selection of devices, hosts and links from the topology view.
Simon Hunta17fa672015-08-19 18:42:22 -070045 */
46public class NodeSelection {
47
Simon Hunt4fc86852015-08-20 17:57:52 -070048 private static final Logger log =
Simon Hunta17fa672015-08-19 18:42:22 -070049 LoggerFactory.getLogger(NodeSelection.class);
50
51 private static final String IDS = "ids";
52 private static final String HOVER = "hover";
Prince Pereira46c82d42016-09-19 13:30:50 +053053 private static final String LINK_ID_DELIM = "-";
Simon Hunta17fa672015-08-19 18:42:22 -070054
55 private final DeviceService deviceService;
56 private final HostService hostService;
Prince Pereira46c82d42016-09-19 13:30:50 +053057 private final LinkService linkService;
Simon Hunta17fa672015-08-19 18:42:22 -070058
59 private final Set<String> ids;
60 private final String hover;
61
62 private final Set<Device> devices = new HashSet<>();
63 private final Set<Host> hosts = new HashSet<>();
Prince Pereira46c82d42016-09-19 13:30:50 +053064 private final Set<Link> links = new HashSet<>();
Simon Hunt72297212015-08-25 10:15:33 -070065 private Element hovered;
Simon Hunta17fa672015-08-19 18:42:22 -070066
67 /**
68 * Creates a node selection entity, from the given payload, using the
Prince Pereira46c82d42016-09-19 13:30:50 +053069 * supplied link, device and host services. Note that if a link, device
70 * or host was hovered over by the mouse, it is available
71 * via {@link #hovered()}.
Simon Hunta17fa672015-08-19 18:42:22 -070072 *
73 * @param payload message payload
74 * @param deviceService device service
75 * @param hostService host service
Prince Pereira46c82d42016-09-19 13:30:50 +053076 * @param linkService link service
Simon Hunta17fa672015-08-19 18:42:22 -070077 */
78 public NodeSelection(ObjectNode payload,
79 DeviceService deviceService,
Prince Pereira46c82d42016-09-19 13:30:50 +053080 HostService hostService,
81 LinkService linkService) {
Simon Hunta17fa672015-08-19 18:42:22 -070082 this.deviceService = deviceService;
83 this.hostService = hostService;
Prince Pereira46c82d42016-09-19 13:30:50 +053084 this.linkService = linkService;
Simon Hunta17fa672015-08-19 18:42:22 -070085
86 ids = extractIds(payload);
87 hover = extractHover(payload);
88
Simon Hunt72297212015-08-25 10:15:33 -070089 // start by extracting the hovered element if any
90 if (isNullOrEmpty(hover)) {
91 hovered = null;
92 } else {
93 setHoveredElement();
94 }
95
Prince Pereira46c82d42016-09-19 13:30:50 +053096 // now go find the links, devices and hosts that are in the selection list
97 Set<String> unmatched = findLinks(ids);
98 unmatched = findDevices(unmatched);
Simon Hunta17fa672015-08-19 18:42:22 -070099 unmatched = findHosts(unmatched);
Jon Hallcbd1b392017-01-18 20:15:44 -0800100 if (!unmatched.isEmpty()) {
Simon Hunta17fa672015-08-19 18:42:22 -0700101 log.debug("Skipping unmatched IDs {}", unmatched);
102 }
103
Simon Hunta17fa672015-08-19 18:42:22 -0700104 }
105
106 /**
Simon Hunt72297212015-08-25 10:15:33 -0700107 * Returns a view of the selected devices (hover not included).
Simon Hunta17fa672015-08-19 18:42:22 -0700108 *
109 * @return selected devices
110 */
111 public Set<Device> devices() {
112 return Collections.unmodifiableSet(devices);
113 }
114
115 /**
Prince Pereira46c82d42016-09-19 13:30:50 +0530116 * Returns a view of the selected links (hover not included).
117 *
118 * @return selected links
119 */
120 public Set<Link> links() {
121 return Collections.unmodifiableSet(links);
122 }
123
124 /**
Simon Hunt72297212015-08-25 10:15:33 -0700125 * Returns a view of the selected devices, including the hovered device
126 * if there was one.
127 *
128 * @return selected (plus hovered) devices
129 */
130 public Set<Device> devicesWithHover() {
131 Set<Device> withHover;
132 if (hovered != null && hovered instanceof Device) {
133 withHover = new HashSet<>(devices);
134 withHover.add((Device) hovered);
135 } else {
136 withHover = devices;
137 }
138 return Collections.unmodifiableSet(withHover);
139 }
140
141 /**
142 * Returns a view of the selected hosts (hover not included).
Simon Hunta17fa672015-08-19 18:42:22 -0700143 *
144 * @return selected hosts
145 */
146 public Set<Host> hosts() {
147 return Collections.unmodifiableSet(hosts);
148 }
149
150 /**
Simon Hunt72297212015-08-25 10:15:33 -0700151 * Returns a view of the selected hosts, including the hovered host
152 * if thee was one.
153 *
154 * @return selected (plus hovered) hosts
155 */
156 public Set<Host> hostsWithHover() {
157 Set<Host> withHover;
158 if (hovered != null && hovered instanceof Host) {
159 withHover = new HashSet<>(hosts);
160 withHover.add((Host) hovered);
161 } else {
162 withHover = hosts;
163 }
164 return Collections.unmodifiableSet(withHover);
165 }
166
167 /**
Prince Pereira46c82d42016-09-19 13:30:50 +0530168 * Returns a view of the selected links, including the hovered link
169 * if thee was one.
170 *
171 * @return selected (plus hovered) links
172 */
173 public Set<Link> linksWithHover() {
174 Set<Link> withHover;
175 if (hovered != null && hovered instanceof Link) {
176 withHover = new HashSet<>(links);
177 withHover.add((Link) hovered);
178 } else {
179 withHover = links;
180 }
181 return Collections.unmodifiableSet(withHover);
182 }
183
184 /**
185 * Returns the element (link, host or device) over which the mouse was hovering,
Simon Hunt72297212015-08-25 10:15:33 -0700186 * or null.
187 *
188 * @return element hovered over
189 */
190 public Element hovered() {
191 return hovered;
192 }
193
194 /**
Simon Hunta17fa672015-08-19 18:42:22 -0700195 * Returns true if nothing is selected.
196 *
197 * @return true if nothing selected
198 */
199 public boolean none() {
Prince Pereira46c82d42016-09-19 13:30:50 +0530200 return devices().isEmpty() && hosts().isEmpty() && links().isEmpty();
Simon Hunta17fa672015-08-19 18:42:22 -0700201 }
202
203 @Override
204 public String toString() {
205 return "NodeSelection{" +
206 "ids=" + ids +
207 ", hover='" + hover + '\'' +
208 ", #devices=" + devices.size() +
209 ", #hosts=" + hosts.size() +
Prince Pereira46c82d42016-09-19 13:30:50 +0530210 ", #links=" + links.size() +
Simon Hunta17fa672015-08-19 18:42:22 -0700211 '}';
212 }
213
214 // == helper methods
215
216 private Set<String> extractIds(ObjectNode payload) {
217 ArrayNode array = (ArrayNode) payload.path(IDS);
218 if (array == null || array.size() == 0) {
219 return Collections.emptySet();
220 }
221
222 Set<String> ids = new HashSet<>();
223 for (JsonNode node : array) {
224 ids.add(node.asText());
225 }
226 return ids;
227 }
228
229 private String extractHover(ObjectNode payload) {
230 return JsonUtils.string(payload, HOVER);
231 }
232
Simon Hunt72297212015-08-25 10:15:33 -0700233 private void setHoveredElement() {
234 Set<String> unmatched;
235 unmatched = new HashSet<>();
236 unmatched.add(hover);
237 unmatched = findDevices(unmatched);
238 if (devices.size() == 1) {
239 hovered = devices.iterator().next();
240 devices.clear();
241 } else {
242 unmatched = findHosts(unmatched);
243 if (hosts.size() == 1) {
244 hovered = hosts.iterator().next();
245 hosts.clear();
246 } else {
247 hovered = null;
248 log.debug("Skipping unmatched HOVER {}", unmatched);
249 }
250 }
251 }
252
Simon Hunta17fa672015-08-19 18:42:22 -0700253 private Set<String> findDevices(Set<String> ids) {
254 Set<String> unmatched = new HashSet<>();
255 Device device;
256
257 for (String id : ids) {
258 try {
259 device = deviceService.getDevice(deviceId(id));
260 if (device != null) {
261 devices.add(device);
262 } else {
Simon Hunt72297212015-08-25 10:15:33 -0700263 unmatched.add(id);
Simon Hunta17fa672015-08-19 18:42:22 -0700264 }
Simon Hunt72297212015-08-25 10:15:33 -0700265 } catch (Exception e) {
Simon Hunta17fa672015-08-19 18:42:22 -0700266 unmatched.add(id);
267 }
268 }
269 return unmatched;
270 }
271
272 private Set<String> findHosts(Set<String> ids) {
273 Set<String> unmatched = new HashSet<>();
274 Host host;
275
276 for (String id : ids) {
277 try {
278 host = hostService.getHost(hostId(id));
279 if (host != null) {
280 hosts.add(host);
281 } else {
Simon Hunt72297212015-08-25 10:15:33 -0700282 unmatched.add(id);
Simon Hunta17fa672015-08-19 18:42:22 -0700283 }
Simon Hunt72297212015-08-25 10:15:33 -0700284 } catch (Exception e) {
Simon Hunta17fa672015-08-19 18:42:22 -0700285 unmatched.add(id);
286 }
287 }
288 return unmatched;
289 }
Prince Pereira46c82d42016-09-19 13:30:50 +0530290
291 private Set<String> findLinks(Set<String> ids) {
292 Set<String> unmatched = new HashSet<>();
293 ConnectPoint cpSrc, cpDst;
294 Link link;
295
296 for (String id : ids) {
297 try {
298 String[] connectPoints = id.split(LINK_ID_DELIM);
299 if (connectPoints.length != 2) {
300 unmatched.add(id);
301 continue;
302 }
303
304 cpSrc = deviceConnectPoint(connectPoints[0]);
305 cpDst = deviceConnectPoint(connectPoints[1]);
306 link = linkService.getLink(cpSrc, cpDst);
307
308 if (link != null) {
309 links.add(link);
310 } else {
311 unmatched.add(id);
312 }
313
314 } catch (Exception e) {
315 unmatched.add(id);
316 }
317 }
318 return unmatched;
319 }
Simon Hunta17fa672015-08-19 18:42:22 -0700320}