blob: f4ffb02188c84b722c43009582c997c5027842ec [file] [log] [blame]
Simon Hunt5f6dbf82016-03-30 08:53:33 -07001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2016-present Open Networking Laboratory
Simon Hunt5f6dbf82016-03-30 08:53:33 -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.
15 */
16
17package org.onosproject.ui.model.topo;
18
Simon Hunt338a3b42016-04-14 09:43:52 -070019import org.onosproject.cluster.NodeId;
Simon Huntc0f20c12016-05-09 09:30:20 -070020import org.onosproject.net.DeviceId;
21import org.onosproject.net.HostId;
Simon Huntc13082f2016-08-03 21:20:23 -070022import org.onosproject.net.PortNumber;
Simon Huntc0f20c12016-05-09 09:30:20 -070023import org.onosproject.net.region.RegionId;
Simon Hunt23fb1352016-04-11 12:15:19 -070024import org.slf4j.Logger;
25import org.slf4j.LoggerFactory;
26
Simon Huntd5b96732016-07-08 13:22:27 -070027import java.util.ArrayList;
28import java.util.Collections;
29import java.util.Comparator;
Simon Huntc0f20c12016-05-09 09:30:20 -070030import java.util.HashMap;
31import java.util.HashSet;
Simon Huntd5b96732016-07-08 13:22:27 -070032import java.util.List;
Simon Huntc0f20c12016-05-09 09:30:20 -070033import java.util.Map;
Simon Huntc13082f2016-08-03 21:20:23 -070034import java.util.Objects;
Simon Hunt23fb1352016-04-11 12:15:19 -070035import java.util.Set;
Simon Huntc13082f2016-08-03 21:20:23 -070036import java.util.stream.Collectors;
Simon Huntc0f20c12016-05-09 09:30:20 -070037
38import static com.google.common.base.MoreObjects.toStringHelper;
Simon Huntc13082f2016-08-03 21:20:23 -070039import static org.onosproject.ui.model.topo.UiLinkId.uiLinkId;
Simon Hunt23fb1352016-04-11 12:15:19 -070040
Simon Hunt5f6dbf82016-03-30 08:53:33 -070041/**
42 * Represents the overall network topology.
43 */
Simon Huntcda9c032016-04-11 10:32:54 -070044public class UiTopology extends UiElement {
Simon Hunt23fb1352016-04-11 12:15:19 -070045
Simon Hunt58a0dd02016-05-17 11:54:23 -070046 private static final String INDENT_1 = " ";
47 private static final String INDENT_2 = " ";
48 private static final String EOL = String.format("%n");
49
Simon Huntc0f20c12016-05-09 09:30:20 -070050 private static final String E_UNMAPPED =
51 "Attempting to retrieve unmapped {}: {}";
52
Simon Hunt642bc452016-05-04 19:34:45 -070053 private static final String DEFAULT_TOPOLOGY_ID = "TOPOLOGY-0";
54
Simon Hunt23fb1352016-04-11 12:15:19 -070055 private static final Logger log = LoggerFactory.getLogger(UiTopology.class);
56
Simon Huntd5b96732016-07-08 13:22:27 -070057 private static final Comparator<UiClusterMember> CLUSTER_MEMBER_COMPARATOR =
58 (o1, o2) -> o1.idAsString().compareTo(o2.idAsString());
59
Simon Huntc0f20c12016-05-09 09:30:20 -070060
61 // top level mappings of topology elements by ID
62 private final Map<NodeId, UiClusterMember> cnodeLookup = new HashMap<>();
63 private final Map<RegionId, UiRegion> regionLookup = new HashMap<>();
64 private final Map<DeviceId, UiDevice> deviceLookup = new HashMap<>();
65 private final Map<HostId, UiHost> hostLookup = new HashMap<>();
Simon Huntc13082f2016-08-03 21:20:23 -070066 private final Map<UiLinkId, UiDeviceLink> devLinkLookup = new HashMap<>();
67 private final Map<UiLinkId, UiEdgeLink> edgeLinkLookup = new HashMap<>();
68
69 // a cache of the computed synthetic links
70 private final List<UiSynthLink> synthLinks = new ArrayList<>();
Simon Huntc0f20c12016-05-09 09:30:20 -070071
Simon Huntb1ce2602016-07-23 14:04:31 -070072 // a container for devices, hosts, etc. belonging to no region
73 private final UiRegion nullRegion = new UiRegion(this, null);
74
Simon Hunt23fb1352016-04-11 12:15:19 -070075
Simon Hunt338a3b42016-04-14 09:43:52 -070076 @Override
77 public String toString() {
Simon Huntc0f20c12016-05-09 09:30:20 -070078 return toStringHelper(this)
79 .add("#cnodes", clusterMemberCount())
80 .add("#regions", regionCount())
81 .add("#devices", deviceLookup.size())
82 .add("#hosts", hostLookup.size())
Simon Huntc13082f2016-08-03 21:20:23 -070083 .add("#dev-links", devLinkLookup.size())
84 .add("#edge-links", edgeLinkLookup.size())
85 .add("#synth-links", synthLinks.size())
Simon Huntc0f20c12016-05-09 09:30:20 -070086 .toString();
87 }
88
89 @Override
90 public String idAsString() {
91 return DEFAULT_TOPOLOGY_ID;
Simon Hunt338a3b42016-04-14 09:43:52 -070092 }
93
Simon Hunt23fb1352016-04-11 12:15:19 -070094 /**
95 * Clears the topology state; that is, drops all regions, devices, hosts,
96 * links, and cluster members.
97 */
98 public void clear() {
99 log.debug("clearing topology model");
Simon Huntc0f20c12016-05-09 09:30:20 -0700100 cnodeLookup.clear();
101 regionLookup.clear();
102 deviceLookup.clear();
103 hostLookup.clear();
Simon Huntc13082f2016-08-03 21:20:23 -0700104 devLinkLookup.clear();
105 edgeLinkLookup.clear();
106
107 synthLinks.clear();
Simon Huntb1ce2602016-07-23 14:04:31 -0700108
109 nullRegion.destroy();
Simon Hunt23fb1352016-04-11 12:15:19 -0700110 }
Simon Hunt338a3b42016-04-14 09:43:52 -0700111
Simon Huntd5b96732016-07-08 13:22:27 -0700112
113 /**
114 * Returns all the cluster members, sorted by their ID.
115 *
116 * @return all cluster members
117 */
118 public List<UiClusterMember> allClusterMembers() {
119 List<UiClusterMember> members = new ArrayList<>(cnodeLookup.values());
120 Collections.sort(members, CLUSTER_MEMBER_COMPARATOR);
121 return members;
122 }
123
Simon Hunt338a3b42016-04-14 09:43:52 -0700124 /**
125 * Returns the cluster member with the given identifier, or null if no
Simon Huntc0f20c12016-05-09 09:30:20 -0700126 * such member exists.
Simon Hunt338a3b42016-04-14 09:43:52 -0700127 *
128 * @param id cluster node identifier
Simon Huntc0f20c12016-05-09 09:30:20 -0700129 * @return corresponding UI cluster member
Simon Hunt338a3b42016-04-14 09:43:52 -0700130 */
131 public UiClusterMember findClusterMember(NodeId id) {
Simon Huntc0f20c12016-05-09 09:30:20 -0700132 return cnodeLookup.get(id);
Simon Hunt338a3b42016-04-14 09:43:52 -0700133 }
134
135 /**
136 * Adds the given cluster member to the topology model.
137 *
138 * @param member cluster member to add
139 */
140 public void add(UiClusterMember member) {
Simon Huntc0f20c12016-05-09 09:30:20 -0700141 cnodeLookup.put(member.id(), member);
Simon Hunt338a3b42016-04-14 09:43:52 -0700142 }
143
144 /**
Simon Hunt642bc452016-05-04 19:34:45 -0700145 * Removes the given cluster member from the topology model.
146 *
147 * @param member cluster member to remove
148 */
149 public void remove(UiClusterMember member) {
Simon Huntc0f20c12016-05-09 09:30:20 -0700150 UiClusterMember m = cnodeLookup.remove(member.id());
151 if (m != null) {
152 m.destroy();
153 }
Simon Hunt642bc452016-05-04 19:34:45 -0700154 }
155
156 /**
Simon Hunt338a3b42016-04-14 09:43:52 -0700157 * Returns the number of members in the cluster.
158 *
159 * @return number of cluster members
160 */
161 public int clusterMemberCount() {
Simon Huntc0f20c12016-05-09 09:30:20 -0700162 return cnodeLookup.size();
163 }
164
Simon Hunt10973dd2016-08-01 15:50:35 -0700165
166 /**
Simon Hunt4f4ffc32016-08-03 18:30:47 -0700167 * Returns all regions in the model (except the
168 * {@link #nullRegion() null region}).
Simon Hunt10973dd2016-08-01 15:50:35 -0700169 *
170 * @return all regions
171 */
172 public Set<UiRegion> allRegions() {
173 return new HashSet<>(regionLookup.values());
174 }
175
Simon Huntc0f20c12016-05-09 09:30:20 -0700176 /**
Simon Huntb1ce2602016-07-23 14:04:31 -0700177 * Returns a reference to the null-region. That is, the container for
178 * devices, hosts, and links that belong to no region.
179 *
180 * @return the null-region
181 */
182 public UiRegion nullRegion() {
183 return nullRegion;
184 }
185
186 /**
Simon Huntc0f20c12016-05-09 09:30:20 -0700187 * Returns the region with the specified identifier, or null if
188 * no such region exists.
189 *
190 * @param id region identifier
191 * @return corresponding UI region
192 */
193 public UiRegion findRegion(RegionId id) {
Simon Hunt4f4ffc32016-08-03 18:30:47 -0700194 return UiRegion.NULL_ID.equals(id) ? nullRegion() : regionLookup.get(id);
Simon Hunt338a3b42016-04-14 09:43:52 -0700195 }
196
197 /**
Simon Huntc0f20c12016-05-09 09:30:20 -0700198 * Adds the given region to the topology model.
199 *
200 * @param uiRegion region to add
201 */
202 public void add(UiRegion uiRegion) {
203 regionLookup.put(uiRegion.id(), uiRegion);
Simon Hunt642bc452016-05-04 19:34:45 -0700204 }
Simon Huntc0f20c12016-05-09 09:30:20 -0700205
206 /**
207 * Removes the given region from the topology model.
208 *
209 * @param uiRegion region to remove
210 */
211 public void remove(UiRegion uiRegion) {
Simon Hunt58a0dd02016-05-17 11:54:23 -0700212 UiRegion r = regionLookup.remove(uiRegion.id());
213 if (r != null) {
214 r.destroy();
215 }
216 }
217
218 /**
219 * Returns the number of regions configured in the topology.
220 *
221 * @return number of regions
222 */
223 public int regionCount() {
224 return regionLookup.size();
Simon Huntc0f20c12016-05-09 09:30:20 -0700225 }
226
227 /**
Simon Huntb1ce2602016-07-23 14:04:31 -0700228 * Returns all devices in the model.
229 *
230 * @return all devices
231 */
232 public Set<UiDevice> allDevices() {
233 return new HashSet<>(deviceLookup.values());
234 }
235
236 /**
Simon Huntc0f20c12016-05-09 09:30:20 -0700237 * Returns the device with the specified identifier, or null if
238 * no such device exists.
239 *
240 * @param id device identifier
241 * @return corresponding UI device
242 */
243 public UiDevice findDevice(DeviceId id) {
244 return deviceLookup.get(id);
245 }
246
247 /**
248 * Adds the given device to the topology model.
249 *
250 * @param uiDevice device to add
251 */
252 public void add(UiDevice uiDevice) {
253 deviceLookup.put(uiDevice.id(), uiDevice);
254 }
255
256 /**
257 * Removes the given device from the topology model.
258 *
259 * @param uiDevice device to remove
260 */
261 public void remove(UiDevice uiDevice) {
262 UiDevice d = deviceLookup.remove(uiDevice.id());
263 if (d != null) {
264 d.destroy();
265 }
266 }
267
268 /**
Simon Hunt58a0dd02016-05-17 11:54:23 -0700269 * Returns the number of devices configured in the topology.
270 *
271 * @return number of devices
272 */
273 public int deviceCount() {
274 return deviceLookup.size();
275 }
276
Simon Huntc13082f2016-08-03 21:20:23 -0700277
Simon Hunt58a0dd02016-05-17 11:54:23 -0700278 /**
Simon Huntc13082f2016-08-03 21:20:23 -0700279 * Returns all device links in the model.
Simon Hunt4854f3d2016-08-02 18:13:15 -0700280 *
Simon Huntc13082f2016-08-03 21:20:23 -0700281 * @return all device links
Simon Hunt4854f3d2016-08-02 18:13:15 -0700282 */
Simon Huntc13082f2016-08-03 21:20:23 -0700283 public Set<UiDeviceLink> allDeviceLinks() {
284 return new HashSet<>(devLinkLookup.values());
Simon Hunt4854f3d2016-08-02 18:13:15 -0700285 }
286
287 /**
Simon Huntc13082f2016-08-03 21:20:23 -0700288 * Returns the device link with the specified identifier, or null if no
289 * such link exists.
Simon Huntc0f20c12016-05-09 09:30:20 -0700290 *
291 * @param id the canonicalized link identifier
Simon Huntc13082f2016-08-03 21:20:23 -0700292 * @return corresponding UI device link
Simon Huntc0f20c12016-05-09 09:30:20 -0700293 */
Simon Huntc13082f2016-08-03 21:20:23 -0700294 public UiDeviceLink findDeviceLink(UiLinkId id) {
295 return devLinkLookup.get(id);
Simon Huntc0f20c12016-05-09 09:30:20 -0700296 }
297
298 /**
Simon Huntc13082f2016-08-03 21:20:23 -0700299 * Returns the edge link with the specified identifier, or null if no
300 * such link exists.
Simon Huntc0f20c12016-05-09 09:30:20 -0700301 *
Simon Huntc13082f2016-08-03 21:20:23 -0700302 * @param id the canonicalized link identifier
303 * @return corresponding UI edge link
Simon Huntc0f20c12016-05-09 09:30:20 -0700304 */
Simon Huntc13082f2016-08-03 21:20:23 -0700305 public UiEdgeLink findEdgeLink(UiLinkId id) {
306 return edgeLinkLookup.get(id);
Simon Huntc0f20c12016-05-09 09:30:20 -0700307 }
308
309 /**
Simon Huntc13082f2016-08-03 21:20:23 -0700310 * Adds the given UI device link to the topology model.
Simon Huntc0f20c12016-05-09 09:30:20 -0700311 *
Simon Huntc13082f2016-08-03 21:20:23 -0700312 * @param uiDeviceLink link to add
Simon Huntc0f20c12016-05-09 09:30:20 -0700313 */
Simon Huntc13082f2016-08-03 21:20:23 -0700314 public void add(UiDeviceLink uiDeviceLink) {
315 devLinkLookup.put(uiDeviceLink.id(), uiDeviceLink);
316 }
317
318 /**
319 * Adds the given UI edge link to the topology model.
320 *
321 * @param uiEdgeLink link to add
322 */
323 public void add(UiEdgeLink uiEdgeLink) {
324 edgeLinkLookup.put(uiEdgeLink.id(), uiEdgeLink);
325 }
326
327 /**
328 * Removes the given UI device link from the model.
329 *
330 * @param uiDeviceLink link to remove
331 */
332 public void remove(UiDeviceLink uiDeviceLink) {
333 UiDeviceLink link = devLinkLookup.remove(uiDeviceLink.id());
Simon Huntc0f20c12016-05-09 09:30:20 -0700334 if (link != null) {
335 link.destroy();
336 }
337 }
338
339 /**
Simon Huntc13082f2016-08-03 21:20:23 -0700340 * Removes the given UI edge link from the model.
Simon Hunt58a0dd02016-05-17 11:54:23 -0700341 *
Simon Huntc13082f2016-08-03 21:20:23 -0700342 * @param uiEdgeLink link to remove
Simon Hunt58a0dd02016-05-17 11:54:23 -0700343 */
Simon Huntc13082f2016-08-03 21:20:23 -0700344 public void remove(UiEdgeLink uiEdgeLink) {
345 UiEdgeLink link = edgeLinkLookup.remove(uiEdgeLink.id());
346 if (link != null) {
347 link.destroy();
348 }
349 }
350
351 /**
352 * Returns the number of device links configured in the topology.
353 *
354 * @return number of device links
355 */
356 public int deviceLinkCount() {
357 return devLinkLookup.size();
358 }
359
360 /**
361 * Returns the number of edge links configured in the topology.
362 *
363 * @return number of edge links
364 */
365 public int edgeLinkCount() {
366 return edgeLinkLookup.size();
Simon Hunt58a0dd02016-05-17 11:54:23 -0700367 }
368
369 /**
Simon Hunt4854f3d2016-08-02 18:13:15 -0700370 * Returns all hosts in the model.
371 *
372 * @return all hosts
373 */
374 public Set<UiHost> allHosts() {
375 return new HashSet<>(hostLookup.values());
376 }
377
378 /**
Simon Huntc0f20c12016-05-09 09:30:20 -0700379 * Returns the host with the specified identifier, or null if no such
380 * host exists.
381 *
382 * @param id host identifier
383 * @return corresponding UI host
384 */
385 public UiHost findHost(HostId id) {
386 return hostLookup.get(id);
387 }
388
389 /**
390 * Adds the given host to the topology model.
391 *
392 * @param uiHost host to add
393 */
394 public void add(UiHost uiHost) {
395 hostLookup.put(uiHost.id(), uiHost);
396 }
397
398 /**
399 * Removes the given host from the topology model.
400 *
401 * @param uiHost host to remove
402 */
403 public void remove(UiHost uiHost) {
404 UiHost h = hostLookup.remove(uiHost.id());
405 if (h != null) {
406 h.destroy();
407 }
408 }
409
Simon Hunt58a0dd02016-05-17 11:54:23 -0700410 /**
411 * Returns the number of hosts configured in the topology.
412 *
413 * @return number of hosts
414 */
415 public int hostCount() {
416 return hostLookup.size();
417 }
418
419
Simon Huntc0f20c12016-05-09 09:30:20 -0700420 // ==
421 // package private methods for supporting linkage amongst topology entities
422 // ==
423
424 /**
425 * Returns the set of UI devices with the given identifiers.
426 *
427 * @param deviceIds device identifiers
428 * @return set of matching UI device instances
429 */
430 Set<UiDevice> deviceSet(Set<DeviceId> deviceIds) {
431 Set<UiDevice> uiDevices = new HashSet<>();
432 for (DeviceId id : deviceIds) {
433 UiDevice d = deviceLookup.get(id);
434 if (d != null) {
435 uiDevices.add(d);
436 } else {
437 log.warn(E_UNMAPPED, "device", id);
438 }
439 }
440 return uiDevices;
441 }
442
443 /**
444 * Returns the set of UI hosts with the given identifiers.
445 *
446 * @param hostIds host identifiers
447 * @return set of matching UI host instances
448 */
449 Set<UiHost> hostSet(Set<HostId> hostIds) {
450 Set<UiHost> uiHosts = new HashSet<>();
451 for (HostId id : hostIds) {
452 UiHost h = hostLookup.get(id);
453 if (h != null) {
454 uiHosts.add(h);
455 } else {
456 log.warn(E_UNMAPPED, "host", id);
457 }
458 }
459 return uiHosts;
460 }
461
462 /**
Simon Huntc13082f2016-08-03 21:20:23 -0700463 * Returns the set of UI device links with the given identifiers.
Simon Huntc0f20c12016-05-09 09:30:20 -0700464 *
465 * @param uiLinkIds link identifiers
Simon Huntc13082f2016-08-03 21:20:23 -0700466 * @return set of matching UI device link instances
Simon Huntc0f20c12016-05-09 09:30:20 -0700467 */
Simon Huntc13082f2016-08-03 21:20:23 -0700468 Set<UiDeviceLink> linkSet(Set<UiLinkId> uiLinkIds) {
469 Set<UiDeviceLink> result = new HashSet<>();
Simon Huntc0f20c12016-05-09 09:30:20 -0700470 for (UiLinkId id : uiLinkIds) {
Simon Huntc13082f2016-08-03 21:20:23 -0700471 UiDeviceLink link = devLinkLookup.get(id);
Simon Huntc0f20c12016-05-09 09:30:20 -0700472 if (link != null) {
Simon Huntc13082f2016-08-03 21:20:23 -0700473 result.add(link);
Simon Huntc0f20c12016-05-09 09:30:20 -0700474 } else {
Simon Huntc13082f2016-08-03 21:20:23 -0700475 log.warn(E_UNMAPPED, "device link", id);
Simon Huntc0f20c12016-05-09 09:30:20 -0700476 }
477 }
Simon Huntc13082f2016-08-03 21:20:23 -0700478 return result;
479 }
480
481 /**
482 * Uses the device-device links and data about the regions to compute the
483 * set of synthetic links that are required per region.
484 */
485 public void computeSynthLinks() {
486 List<UiSynthLink> slinks = new ArrayList<>();
487 allDeviceLinks().forEach((link) -> {
488 UiSynthLink synthetic = inferSyntheticLink(link);
489 slinks.add(synthetic);
490 log.debug("Synthetic link: {}", synthetic);
491 });
492
Simon Huntf59d36b2016-10-04 19:05:53 -0700493
Simon Huntc13082f2016-08-03 21:20:23 -0700494 synthLinks.clear();
495 synthLinks.addAll(slinks);
Simon Huntf59d36b2016-10-04 19:05:53 -0700496
497 // TODO : compute and add host-device links to synthLinks...
498
Simon Huntc13082f2016-08-03 21:20:23 -0700499 }
500
501 private UiSynthLink inferSyntheticLink(UiDeviceLink link) {
502 /*
503 Look at the containment hierarchy of each end of the link. Find the
504 common ancestor region R. A synthetic link will be added to R, based
505 on the "next" node back down the branch...
506
507 S1 --- S2 * in the same region ...
508 : :
509 R R return S1 --- S2 (same link instance)
510
511
512 S1 --- S2 * in different regions (R1, R2) at same level
513 : :
514 R1 R2 return R1 --- R2
515 : :
516 R R
517
518 S1 --- S2 * in different regions at different levels
519 : :
520 R1 R2 return R1 --- R3
521 : :
522 R R3
523 :
524 R
525
526 S1 --- S2 * in different regions at different levels
527 : :
528 R R2 return S1 --- R2
529 :
530 R
531
532 */
533 DeviceId a = link.deviceA();
534 DeviceId b = link.deviceB();
535 List<RegionId> aBranch = ancestors(a);
536 List<RegionId> bBranch = ancestors(b);
537 if (aBranch == null || bBranch == null) {
538 return null;
539 }
540
541 return makeSynthLink(link, aBranch, bBranch);
542 }
543
544 // package private for unit testing
545 UiSynthLink makeSynthLink(UiDeviceLink orig,
546 List<RegionId> aBranch,
547 List<RegionId> bBranch) {
548
549 final int aSize = aBranch.size();
550 final int bSize = bBranch.size();
551 final int min = Math.min(aSize, bSize);
552
553 int index = 0;
554 RegionId commonRegion = aBranch.get(index);
555
556 while (true) {
557 int next = index + 1;
558 if (next == min) {
559 // no more pairs of regions left to test
560 break;
561 }
562 RegionId rA = aBranch.get(next);
563 RegionId rB = bBranch.get(next);
564 if (rA.equals(rB)) {
565 commonRegion = rA;
566 index++;
567 } else {
568 break;
569 }
570 }
571
572
573 int endPointIndex = index + 1;
574 UiLinkId linkId;
575 UiLink link;
576
577 if (endPointIndex < aSize) {
578 // the A endpoint is a subregion
579 RegionId aRegion = aBranch.get(endPointIndex);
580
581 if (endPointIndex < bSize) {
582 // the B endpoint is a subregion
583 RegionId bRegion = bBranch.get(endPointIndex);
584
585 linkId = uiLinkId(aRegion, bRegion);
586 link = new UiRegionLink(this, linkId);
587
588 } else {
589 // the B endpoint is the device
590 DeviceId dB = orig.deviceB();
591 PortNumber pB = orig.portB();
592
593 linkId = uiLinkId(aRegion, dB, pB);
594 link = new UiRegionDeviceLink(this, linkId);
595 }
596
597 } else {
598 // the A endpoint is the device
599 DeviceId dA = orig.deviceA();
600 PortNumber pA = orig.portA();
601
602 if (endPointIndex < bSize) {
603 // the B endpoint is a subregion
604 RegionId bRegion = bBranch.get(endPointIndex);
605
606 linkId = uiLinkId(bRegion, dA, pA);
607 link = new UiRegionDeviceLink(this, linkId);
608
609 } else {
610 // the B endpoint is the device
611 // (so, we can just use the original device-device link...)
612
613 link = orig;
614 }
615 }
616 return new UiSynthLink(commonRegion, link);
617 }
618
619 private List<RegionId> ancestors(DeviceId id) {
620 // return the ancestor chain from this device to root region
621 UiDevice dev = findDevice(id);
622 if (dev == null) {
623 log.warn("Unable to find cached device with ID %s", id);
624 return null;
625 }
626
627 UiRegion r = dev.uiRegion();
628 List<RegionId> result = new ArrayList<>();
629 while (r != null && !r.isRoot()) {
630 result.add(0, r.id());
631 r = r.parentRegion();
632 }
633 // finally add root region, since this is the grand-daddy of them all
634 result.add(0, UiRegion.NULL_ID);
635 return result;
636 }
637
638
639 /**
640 * Returns the synthetic links associated with the specified region.
641 *
642 * @param regionId the region ID
643 * @return synthetic links for this region
644 */
645 public List<UiSynthLink> findSynthLinks(RegionId regionId) {
646 return synthLinks.stream()
647 .filter(s -> Objects.equals(regionId, s.regionId()))
648 .collect(Collectors.toList());
649 }
650
651
652 /**
653 * Returns the number of synthetic links in the topology.
654 *
655 * @return the synthetic link count
656 */
657 public int synthLinkCount() {
658 return synthLinks.size();
Simon Huntc0f20c12016-05-09 09:30:20 -0700659 }
660
Simon Hunt58a0dd02016-05-17 11:54:23 -0700661 /**
662 * Returns a detailed (multi-line) string showing the contents of the
663 * topology.
664 *
665 * @return detailed string
666 */
667 public String dumpString() {
668 StringBuilder sb = new StringBuilder("Topology:").append(EOL);
669
670 sb.append(INDENT_1).append("Cluster Members").append(EOL);
671 for (UiClusterMember m : cnodeLookup.values()) {
672 sb.append(INDENT_2).append(m).append(EOL);
673 }
674
675 sb.append(INDENT_1).append("Regions").append(EOL);
676 for (UiRegion r : regionLookup.values()) {
677 sb.append(INDENT_2).append(r).append(EOL);
678 }
679
680 sb.append(INDENT_1).append("Devices").append(EOL);
681 for (UiDevice d : deviceLookup.values()) {
682 sb.append(INDENT_2).append(d).append(EOL);
683 }
684
685 sb.append(INDENT_1).append("Hosts").append(EOL);
686 for (UiHost h : hostLookup.values()) {
687 sb.append(INDENT_2).append(h).append(EOL);
688 }
689
Simon Huntc13082f2016-08-03 21:20:23 -0700690 sb.append(INDENT_1).append("Device Links").append(EOL);
691 for (UiLink link : devLinkLookup.values()) {
692 sb.append(INDENT_2).append(link).append(EOL);
693 }
694
695 sb.append(INDENT_1).append("Edge Links").append(EOL);
696 for (UiLink link : edgeLinkLookup.values()) {
697 sb.append(INDENT_2).append(link).append(EOL);
698 }
699
700 sb.append(INDENT_1).append("Synth Links").append(EOL);
701 for (UiSynthLink link : synthLinks) {
Simon Hunt58a0dd02016-05-17 11:54:23 -0700702 sb.append(INDENT_2).append(link).append(EOL);
703 }
704 sb.append("------").append(EOL);
705
706 return sb.toString();
707 }
Simon Hunt5f6dbf82016-03-30 08:53:33 -0700708}