blob: f98ab7b162b4395b678977e8c758c8c330de2700 [file] [log] [blame]
Simon Huntcda9c032016-04-11 10:32:54 -07001/*
Brian O'Connor0a4e6742016-09-15 23:03:10 -07002 * Copyright 2016-present Open Networking Laboratory
Simon Huntcda9c032016-04-11 10:32:54 -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.impl.topo.model;
18
Simon Hunt23fb1352016-04-11 12:15:19 -070019import org.onosproject.cluster.ControllerNode;
Simon Hunt642bc452016-05-04 19:34:45 -070020import org.onosproject.cluster.NodeId;
Simon Hunt23fb1352016-04-11 12:15:19 -070021import org.onosproject.cluster.RoleInfo;
Simon Huntcda9c032016-04-11 10:32:54 -070022import org.onosproject.event.EventDispatcher;
23import org.onosproject.net.Device;
Simon Hunt23fb1352016-04-11 12:15:19 -070024import org.onosproject.net.DeviceId;
Simon Huntc0f20c12016-05-09 09:30:20 -070025import org.onosproject.net.EdgeLink;
Simon Hunt23fb1352016-04-11 12:15:19 -070026import org.onosproject.net.Host;
Simon Huntc0f20c12016-05-09 09:30:20 -070027import org.onosproject.net.HostId;
28import org.onosproject.net.HostLocation;
Simon Hunt23fb1352016-04-11 12:15:19 -070029import org.onosproject.net.Link;
30import org.onosproject.net.region.Region;
Simon Huntc0f20c12016-05-09 09:30:20 -070031import org.onosproject.net.region.RegionId;
Simon Hunt4f4ffc32016-08-03 18:30:47 -070032import org.onosproject.ui.UiTopoLayoutService;
Simon Hunt642bc452016-05-04 19:34:45 -070033import org.onosproject.ui.model.ServiceBundle;
Simon Hunt338a3b42016-04-14 09:43:52 -070034import org.onosproject.ui.model.topo.UiClusterMember;
Simon Huntcda9c032016-04-11 10:32:54 -070035import org.onosproject.ui.model.topo.UiDevice;
Simon Huntc13082f2016-08-03 21:20:23 -070036import org.onosproject.ui.model.topo.UiDeviceLink;
37import org.onosproject.ui.model.topo.UiEdgeLink;
Simon Huntc0f20c12016-05-09 09:30:20 -070038import org.onosproject.ui.model.topo.UiElement;
39import org.onosproject.ui.model.topo.UiHost;
Simon Huntc0f20c12016-05-09 09:30:20 -070040import org.onosproject.ui.model.topo.UiLinkId;
41import org.onosproject.ui.model.topo.UiRegion;
Simon Huntc13082f2016-08-03 21:20:23 -070042import org.onosproject.ui.model.topo.UiSynthLink;
Simon Hunt4f4ffc32016-08-03 18:30:47 -070043import org.onosproject.ui.model.topo.UiTopoLayout;
44import org.onosproject.ui.model.topo.UiTopoLayoutId;
Simon Hunt23fb1352016-04-11 12:15:19 -070045import org.onosproject.ui.model.topo.UiTopology;
Simon Hunt642bc452016-05-04 19:34:45 -070046import org.slf4j.Logger;
47import org.slf4j.LoggerFactory;
Simon Hunt23fb1352016-04-11 12:15:19 -070048
Simon Huntb1ce2602016-07-23 14:04:31 -070049import java.util.HashSet;
Simon Huntd5b96732016-07-08 13:22:27 -070050import java.util.List;
Simon Huntc0f20c12016-05-09 09:30:20 -070051import java.util.Set;
52
53import static org.onosproject.net.DefaultEdgeLink.createEdgeLink;
Simon Hunt642bc452016-05-04 19:34:45 -070054import static org.onosproject.ui.impl.topo.model.UiModelEvent.Type.CLUSTER_MEMBER_ADDED_OR_UPDATED;
55import static org.onosproject.ui.impl.topo.model.UiModelEvent.Type.CLUSTER_MEMBER_REMOVED;
56import static org.onosproject.ui.impl.topo.model.UiModelEvent.Type.DEVICE_ADDED_OR_UPDATED;
Simon Hunt23fb1352016-04-11 12:15:19 -070057import static org.onosproject.ui.impl.topo.model.UiModelEvent.Type.DEVICE_REMOVED;
Simon Huntc0f20c12016-05-09 09:30:20 -070058import static org.onosproject.ui.impl.topo.model.UiModelEvent.Type.HOST_ADDED_OR_UPDATED;
59import static org.onosproject.ui.impl.topo.model.UiModelEvent.Type.HOST_MOVED;
60import static org.onosproject.ui.impl.topo.model.UiModelEvent.Type.HOST_REMOVED;
61import static org.onosproject.ui.impl.topo.model.UiModelEvent.Type.LINK_ADDED_OR_UPDATED;
62import static org.onosproject.ui.impl.topo.model.UiModelEvent.Type.LINK_REMOVED;
63import static org.onosproject.ui.impl.topo.model.UiModelEvent.Type.REGION_ADDED_OR_UPDATED;
64import static org.onosproject.ui.impl.topo.model.UiModelEvent.Type.REGION_REMOVED;
65import static org.onosproject.ui.model.topo.UiLinkId.uiLinkId;
Simon Huntcda9c032016-04-11 10:32:54 -070066
67/**
68 * UI Topology Model cache.
69 */
70class ModelCache {
71
Simon Huntc0f20c12016-05-09 09:30:20 -070072 private static final String E_NO_ELEMENT = "Tried to remove non-member {}: {}";
73
Simon Hunt642bc452016-05-04 19:34:45 -070074 private static final Logger log = LoggerFactory.getLogger(ModelCache.class);
75
76 private final ServiceBundle services;
Simon Huntcda9c032016-04-11 10:32:54 -070077 private final EventDispatcher dispatcher;
Simon Hunt23fb1352016-04-11 12:15:19 -070078 private final UiTopology uiTopology = new UiTopology();
Simon Huntcda9c032016-04-11 10:32:54 -070079
Simon Hunt642bc452016-05-04 19:34:45 -070080 ModelCache(ServiceBundle services, EventDispatcher eventDispatcher) {
81 this.services = services;
Simon Huntcda9c032016-04-11 10:32:54 -070082 this.dispatcher = eventDispatcher;
83 }
84
Simon Hunt338a3b42016-04-14 09:43:52 -070085 @Override
86 public String toString() {
87 return "ModelCache{" + uiTopology + "}";
88 }
89
Simon Huntc0f20c12016-05-09 09:30:20 -070090 private void postEvent(UiModelEvent.Type type, UiElement subject) {
91 dispatcher.post(new UiModelEvent(type, subject));
92 }
93
Simon Huntcda9c032016-04-11 10:32:54 -070094 void clear() {
Simon Hunt23fb1352016-04-11 12:15:19 -070095 uiTopology.clear();
Simon Huntcda9c032016-04-11 10:32:54 -070096 }
97
98 /**
Simon Huntc0f20c12016-05-09 09:30:20 -070099 * Create our internal model of the global topology. An assumption we are
100 * making is that the topology is empty to start.
Simon Huntcda9c032016-04-11 10:32:54 -0700101 */
102 void load() {
Simon Huntc0f20c12016-05-09 09:30:20 -0700103 loadClusterMembers();
104 loadRegions();
105 loadDevices();
Simon Huntc13082f2016-08-03 21:20:23 -0700106 loadDeviceLinks();
Simon Huntc0f20c12016-05-09 09:30:20 -0700107 loadHosts();
Simon Huntcda9c032016-04-11 10:32:54 -0700108 }
109
110
Simon Huntc0f20c12016-05-09 09:30:20 -0700111 // === CLUSTER MEMBERS
112
113 private UiClusterMember addNewClusterMember(ControllerNode n) {
114 UiClusterMember member = new UiClusterMember(uiTopology, n);
115 uiTopology.add(member);
116 return member;
117 }
118
119 private void updateClusterMember(UiClusterMember member) {
120 ControllerNode.State state = services.cluster().getState(member.id());
121 member.setState(state);
Simon Huntc0f20c12016-05-09 09:30:20 -0700122 }
123
124 private void loadClusterMembers() {
125 for (ControllerNode n : services.cluster().getNodes()) {
126 UiClusterMember member = addNewClusterMember(n);
127 updateClusterMember(member);
128 }
129 }
130
131 // invoked from UiSharedTopologyModel cluster event listener
Simon Hunt338a3b42016-04-14 09:43:52 -0700132 void addOrUpdateClusterMember(ControllerNode cnode) {
Simon Hunt642bc452016-05-04 19:34:45 -0700133 NodeId id = cnode.id();
134 UiClusterMember member = uiTopology.findClusterMember(id);
135 if (member == null) {
Simon Huntc0f20c12016-05-09 09:30:20 -0700136 member = addNewClusterMember(cnode);
Simon Hunt338a3b42016-04-14 09:43:52 -0700137 }
Simon Huntc0f20c12016-05-09 09:30:20 -0700138 updateClusterMember(member);
Simon Hunt338a3b42016-04-14 09:43:52 -0700139
Simon Huntc0f20c12016-05-09 09:30:20 -0700140 postEvent(CLUSTER_MEMBER_ADDED_OR_UPDATED, member);
Simon Hunt338a3b42016-04-14 09:43:52 -0700141 }
142
Simon Huntc0f20c12016-05-09 09:30:20 -0700143 // package private for unit test access
144 UiClusterMember accessClusterMember(NodeId id) {
145 return uiTopology.findClusterMember(id);
146 }
147
148 // invoked from UiSharedTopologyModel cluster event listener
Simon Hunt338a3b42016-04-14 09:43:52 -0700149 void removeClusterMember(ControllerNode cnode) {
Simon Hunt642bc452016-05-04 19:34:45 -0700150 NodeId id = cnode.id();
151 UiClusterMember member = uiTopology.findClusterMember(id);
152 if (member != null) {
153 uiTopology.remove(member);
Simon Huntc0f20c12016-05-09 09:30:20 -0700154 postEvent(CLUSTER_MEMBER_REMOVED, member);
Simon Hunt642bc452016-05-04 19:34:45 -0700155 } else {
Simon Huntc0f20c12016-05-09 09:30:20 -0700156 log.warn(E_NO_ELEMENT, "cluster node", id);
Simon Hunt642bc452016-05-04 19:34:45 -0700157 }
Simon Hunt338a3b42016-04-14 09:43:52 -0700158 }
159
Simon Huntd5b96732016-07-08 13:22:27 -0700160 List<UiClusterMember> getAllClusterMembers() {
161 return uiTopology.allClusterMembers();
162 }
163
Simon Huntc0f20c12016-05-09 09:30:20 -0700164
165 // === MASTERSHIP CHANGES
166
167 // invoked from UiSharedTopologyModel mastership listener
Simon Hunt338a3b42016-04-14 09:43:52 -0700168 void updateMasterships(DeviceId deviceId, RoleInfo roleInfo) {
Simon Huntc0f20c12016-05-09 09:30:20 -0700169 // To think about:: do we need to store mastership info?
170 // or can we rely on looking it up live?
Simon Hunt338a3b42016-04-14 09:43:52 -0700171 // TODO: store the updated mastership information
172 // TODO: post event
173 }
174
Simon Huntb1ce2602016-07-23 14:04:31 -0700175 // === THE NULL REGION
176
177 UiRegion nullRegion() {
178 return uiTopology.nullRegion();
179 }
Simon Huntc0f20c12016-05-09 09:30:20 -0700180
181 // === REGIONS
182
183 private UiRegion addNewRegion(Region r) {
184 UiRegion region = new UiRegion(uiTopology, r);
185 uiTopology.add(region);
Simon Huntb1ce2602016-07-23 14:04:31 -0700186 log.debug("Region {} added to topology", region);
Simon Huntc0f20c12016-05-09 09:30:20 -0700187 return region;
188 }
189
190 private void updateRegion(UiRegion region) {
Simon Huntb1ce2602016-07-23 14:04:31 -0700191 RegionId rid = region.id();
192 Set<DeviceId> deviceIds = services.region().getRegionDevices(rid);
Steven Burrows19e6e4f2016-10-05 13:27:07 -0500193 Set<HostId> hostIds = services.region().getRegionHosts(rid);
Simon Huntb1ce2602016-07-23 14:04:31 -0700194
195 // Make sure device objects refer to their region
196 deviceIds.forEach(d -> {
197 UiDevice dev = uiTopology.findDevice(d);
198 if (dev != null) {
199 dev.setRegionId(rid);
200 } else {
201 // if we don't have the UiDevice in the topology, what can we do?
202 log.warn("Region device {}, but we don't have UiDevice in topology", d);
203 }
204 });
205
Steven Burrows19e6e4f2016-10-05 13:27:07 -0500206 hostIds.forEach(d -> {
207 UiHost host = uiTopology.findHost(d);
208 if (host != null) {
209 host.setRegionId(rid);
210 } else {
211 // if we don't have the UiDevice in the topology, what can we do?
212 log.warn("Region host {}, but we don't have UiHost in topology", d);
213 }
214 });
215
Simon Huntb1ce2602016-07-23 14:04:31 -0700216 // Make sure the region object refers to the devices
217 region.reconcileDevices(deviceIds);
Steven Burrows19e6e4f2016-10-05 13:27:07 -0500218 region.reconcileHosts(hostIds);
Simon Hunt4f4ffc32016-08-03 18:30:47 -0700219
220 fixupContainmentHierarchy(region);
221 }
222
223 private void fixupContainmentHierarchy(UiRegion region) {
224 UiTopoLayoutService ls = services.layout();
225 RegionId regionId = region.id();
226
227 UiTopoLayout layout = ls.getLayout(regionId);
228 if (layout == null) {
229 // no layout backed by this region
230 log.warn("No layout backed by region {}", regionId);
231 return;
232 }
233
234 UiTopoLayoutId layoutId = layout.id();
235
236 if (!layout.isRoot()) {
237 UiTopoLayoutId parentId = layout.parent();
238 UiTopoLayout parentLayout = ls.getLayout(parentId);
239 RegionId parentRegionId = parentLayout.regionId();
240 region.setParent(parentRegionId);
241 }
242
243 Set<UiTopoLayout> kids = ls.getChildren(layoutId);
244 Set<RegionId> kidRegionIds = new HashSet<>(kids.size());
245 kids.forEach(k -> kidRegionIds.add(k.regionId()));
246 region.setChildren(kidRegionIds);
Simon Huntc0f20c12016-05-09 09:30:20 -0700247 }
248
249 private void loadRegions() {
250 for (Region r : services.region().getRegions()) {
251 UiRegion region = addNewRegion(r);
252 updateRegion(region);
253 }
254 }
255
256 // invoked from UiSharedTopologyModel region listener
Simon Hunt338a3b42016-04-14 09:43:52 -0700257 void addOrUpdateRegion(Region region) {
Simon Huntc0f20c12016-05-09 09:30:20 -0700258 RegionId id = region.id();
259 UiRegion uiRegion = uiTopology.findRegion(id);
260 if (uiRegion == null) {
261 uiRegion = addNewRegion(region);
262 }
263 updateRegion(uiRegion);
264
265 postEvent(REGION_ADDED_OR_UPDATED, uiRegion);
Simon Hunt338a3b42016-04-14 09:43:52 -0700266 }
267
Simon Hunt58a0dd02016-05-17 11:54:23 -0700268 // package private for unit test access
269 UiRegion accessRegion(RegionId id) {
Simon Huntd5b96732016-07-08 13:22:27 -0700270 return id == null ? null : uiTopology.findRegion(id);
Simon Hunt58a0dd02016-05-17 11:54:23 -0700271 }
272
Simon Huntc0f20c12016-05-09 09:30:20 -0700273 // invoked from UiSharedTopologyModel region listener
Simon Hunt338a3b42016-04-14 09:43:52 -0700274 void removeRegion(Region region) {
Simon Huntc0f20c12016-05-09 09:30:20 -0700275 RegionId id = region.id();
276 UiRegion uiRegion = uiTopology.findRegion(id);
277 if (uiRegion != null) {
278 uiTopology.remove(uiRegion);
279 postEvent(REGION_REMOVED, uiRegion);
280 } else {
281 log.warn(E_NO_ELEMENT, "region", id);
282 }
Simon Hunt338a3b42016-04-14 09:43:52 -0700283 }
284
Simon Hunt10973dd2016-08-01 15:50:35 -0700285 Set<UiRegion> getAllRegions() {
286 return uiTopology.allRegions();
287 }
288
Simon Huntc0f20c12016-05-09 09:30:20 -0700289
290 // === DEVICES
291
292 private UiDevice addNewDevice(Device d) {
293 UiDevice device = new UiDevice(uiTopology, d);
Simon Huntb1ce2602016-07-23 14:04:31 -0700294 updateDevice(device);
Simon Huntc0f20c12016-05-09 09:30:20 -0700295 uiTopology.add(device);
Simon Huntb1ce2602016-07-23 14:04:31 -0700296 log.debug("Device {} added to topology", device);
Simon Huntc0f20c12016-05-09 09:30:20 -0700297 return device;
298 }
299
Simon Huntb1ce2602016-07-23 14:04:31 -0700300 // make sure the UiDevice is tagged with the region it belongs to
Simon Huntc0f20c12016-05-09 09:30:20 -0700301 private void updateDevice(UiDevice device) {
Simon Huntb1ce2602016-07-23 14:04:31 -0700302 Region r = services.region().getRegionForDevice(device.id());
303 RegionId rid = r == null ? UiRegion.NULL_ID : r.id();
304 device.setRegionId(rid);
Simon Huntc0f20c12016-05-09 09:30:20 -0700305 }
306
307 private void loadDevices() {
308 for (Device d : services.device().getDevices()) {
Simon Huntb1ce2602016-07-23 14:04:31 -0700309 addNewDevice(d);
Simon Huntc0f20c12016-05-09 09:30:20 -0700310 }
311 }
312
313 // invoked from UiSharedTopologyModel device listener
Simon Huntcda9c032016-04-11 10:32:54 -0700314 void addOrUpdateDevice(Device device) {
Simon Huntc0f20c12016-05-09 09:30:20 -0700315 DeviceId id = device.id();
316 UiDevice uiDevice = uiTopology.findDevice(id);
317 if (uiDevice == null) {
318 uiDevice = addNewDevice(device);
Simon Huntb1ce2602016-07-23 14:04:31 -0700319 } else {
320 updateDevice(uiDevice);
Simon Huntc0f20c12016-05-09 09:30:20 -0700321 }
Simon Huntcda9c032016-04-11 10:32:54 -0700322
Simon Huntc0f20c12016-05-09 09:30:20 -0700323 postEvent(DEVICE_ADDED_OR_UPDATED, uiDevice);
Simon Huntcda9c032016-04-11 10:32:54 -0700324 }
325
Simon Hunt58a0dd02016-05-17 11:54:23 -0700326 // package private for unit test access
327 UiDevice accessDevice(DeviceId id) {
328 return uiTopology.findDevice(id);
329 }
330
Simon Huntc0f20c12016-05-09 09:30:20 -0700331 // invoked from UiSharedTopologyModel device listener
Simon Huntcda9c032016-04-11 10:32:54 -0700332 void removeDevice(Device device) {
Simon Huntc0f20c12016-05-09 09:30:20 -0700333 DeviceId id = device.id();
334 UiDevice uiDevice = uiTopology.findDevice(id);
335 if (uiDevice != null) {
336 uiTopology.remove(uiDevice);
337 postEvent(DEVICE_REMOVED, uiDevice);
338 } else {
339 log.warn(E_NO_ELEMENT, "device", id);
340 }
Simon Huntcda9c032016-04-11 10:32:54 -0700341 }
342
Simon Hunt4854f3d2016-08-02 18:13:15 -0700343 Set<UiDevice> getAllDevices() {
344 return uiTopology.allDevices();
345 }
346
Simon Huntc0f20c12016-05-09 09:30:20 -0700347
Simon Huntc13082f2016-08-03 21:20:23 -0700348 // === LINKS ===
Simon Huntc0f20c12016-05-09 09:30:20 -0700349
Simon Huntc13082f2016-08-03 21:20:23 -0700350 private UiDeviceLink addNewDeviceLink(UiLinkId id) {
351 UiDeviceLink uiDeviceLink = new UiDeviceLink(uiTopology, id);
352 uiTopology.add(uiDeviceLink);
353 return uiDeviceLink;
Simon Huntc0f20c12016-05-09 09:30:20 -0700354 }
355
Simon Huntc13082f2016-08-03 21:20:23 -0700356 private UiEdgeLink addNewEdgeLink(UiLinkId id) {
357 UiEdgeLink uiEdgeLink = new UiEdgeLink(uiTopology, id);
358 uiTopology.add(uiEdgeLink);
359 return uiEdgeLink;
Simon Huntc0f20c12016-05-09 09:30:20 -0700360 }
361
Simon Huntc13082f2016-08-03 21:20:23 -0700362 private void updateDeviceLink(UiDeviceLink uiDeviceLink, Link link) {
363 uiDeviceLink.attachBackingLink(link);
364 }
365
366 private void loadDeviceLinks() {
Simon Huntc0f20c12016-05-09 09:30:20 -0700367 for (Link link : services.link().getLinks()) {
368 UiLinkId id = uiLinkId(link);
369
Simon Huntc13082f2016-08-03 21:20:23 -0700370 UiDeviceLink uiDeviceLink = uiTopology.findDeviceLink(id);
371 if (uiDeviceLink == null) {
372 uiDeviceLink = addNewDeviceLink(id);
Simon Huntc0f20c12016-05-09 09:30:20 -0700373 }
Simon Huntc13082f2016-08-03 21:20:23 -0700374 updateDeviceLink(uiDeviceLink, link);
Simon Huntc0f20c12016-05-09 09:30:20 -0700375 }
376 }
377
378 // invoked from UiSharedTopologyModel link listener
Simon Huntc13082f2016-08-03 21:20:23 -0700379 void addOrUpdateDeviceLink(Link link) {
Simon Huntc0f20c12016-05-09 09:30:20 -0700380 UiLinkId id = uiLinkId(link);
Simon Huntc13082f2016-08-03 21:20:23 -0700381 UiDeviceLink uiDeviceLink = uiTopology.findDeviceLink(id);
382 if (uiDeviceLink == null) {
383 uiDeviceLink = addNewDeviceLink(id);
Simon Huntc0f20c12016-05-09 09:30:20 -0700384 }
Simon Huntc13082f2016-08-03 21:20:23 -0700385 updateDeviceLink(uiDeviceLink, link);
Simon Huntc0f20c12016-05-09 09:30:20 -0700386
Simon Huntc13082f2016-08-03 21:20:23 -0700387 postEvent(LINK_ADDED_OR_UPDATED, uiDeviceLink);
Simon Hunt23fb1352016-04-11 12:15:19 -0700388 }
389
Simon Hunt58a0dd02016-05-17 11:54:23 -0700390 // package private for unit test access
Simon Huntc13082f2016-08-03 21:20:23 -0700391 UiDeviceLink accessDeviceLink(UiLinkId id) {
392 return uiTopology.findDeviceLink(id);
Simon Hunt58a0dd02016-05-17 11:54:23 -0700393 }
394
Simon Huntc0f20c12016-05-09 09:30:20 -0700395 // invoked from UiSharedTopologyModel link listener
Simon Huntc13082f2016-08-03 21:20:23 -0700396 void removeDeviceLink(Link link) {
Simon Huntc0f20c12016-05-09 09:30:20 -0700397 UiLinkId id = uiLinkId(link);
Simon Huntc13082f2016-08-03 21:20:23 -0700398 UiDeviceLink uiDeviceLink = uiTopology.findDeviceLink(id);
399 if (uiDeviceLink != null) {
400 boolean remaining = uiDeviceLink.detachBackingLink(link);
Simon Huntc0f20c12016-05-09 09:30:20 -0700401 if (remaining) {
Simon Huntc13082f2016-08-03 21:20:23 -0700402 postEvent(LINK_ADDED_OR_UPDATED, uiDeviceLink);
Simon Huntc0f20c12016-05-09 09:30:20 -0700403 } else {
Simon Huntc13082f2016-08-03 21:20:23 -0700404 uiTopology.remove(uiDeviceLink);
405 postEvent(LINK_REMOVED, uiDeviceLink);
Simon Huntc0f20c12016-05-09 09:30:20 -0700406 }
407 } else {
Simon Huntc13082f2016-08-03 21:20:23 -0700408 log.warn(E_NO_ELEMENT, "Device link", id);
Simon Huntc0f20c12016-05-09 09:30:20 -0700409 }
Simon Hunt23fb1352016-04-11 12:15:19 -0700410 }
411
Simon Huntc13082f2016-08-03 21:20:23 -0700412 Set<UiDeviceLink> getAllDeviceLinks() {
413 return uiTopology.allDeviceLinks();
Simon Hunt4854f3d2016-08-02 18:13:15 -0700414 }
Simon Huntc0f20c12016-05-09 09:30:20 -0700415
416 // === HOSTS
417
Simon Hunt58a0dd02016-05-17 11:54:23 -0700418 private EdgeLink synthesizeLink(Host h) {
419 return createEdgeLink(h, true);
420 }
421
Simon Huntc0f20c12016-05-09 09:30:20 -0700422 private UiHost addNewHost(Host h) {
423 UiHost host = new UiHost(uiTopology, h);
424 uiTopology.add(host);
425
Simon Hunt58a0dd02016-05-17 11:54:23 -0700426 EdgeLink elink = synthesizeLink(h);
427 UiLinkId elinkId = uiLinkId(elink);
428 host.setEdgeLinkId(elinkId);
429
430 // add synthesized edge link to the topology
Simon Huntb7fd0802016-10-27 12:21:40 -0700431 addNewEdgeLink(elinkId);
Simon Huntc0f20c12016-05-09 09:30:20 -0700432
433 return host;
434 }
435
Simon Huntb7fd0802016-10-27 12:21:40 -0700436 private void insertNewUiEdgeLink(UiLinkId id) {
437 addNewEdgeLink(id);
Simon Huntc0f20c12016-05-09 09:30:20 -0700438 }
439
440 private void updateHost(UiHost uiHost, Host h) {
Simon Huntc13082f2016-08-03 21:20:23 -0700441 UiEdgeLink existing = uiTopology.findEdgeLink(uiHost.edgeLinkId());
Simon Hunt58a0dd02016-05-17 11:54:23 -0700442
Simon Huntb7fd0802016-10-27 12:21:40 -0700443 // TODO: review - do we need EdgeLink now that we are creating from id only?
Simon Hunt58a0dd02016-05-17 11:54:23 -0700444 EdgeLink currentElink = synthesizeLink(h);
445 UiLinkId currentElinkId = uiLinkId(currentElink);
446
447 if (existing != null) {
448 if (!currentElinkId.equals(existing.id())) {
449 // edge link has changed
Simon Huntb7fd0802016-10-27 12:21:40 -0700450 insertNewUiEdgeLink(currentElinkId);
Simon Hunt58a0dd02016-05-17 11:54:23 -0700451 uiHost.setEdgeLinkId(currentElinkId);
452
453 uiTopology.remove(existing);
454 }
455
456 } else {
457 // no previously existing edge link
Simon Huntb7fd0802016-10-27 12:21:40 -0700458 insertNewUiEdgeLink(currentElinkId);
Simon Hunt58a0dd02016-05-17 11:54:23 -0700459 uiHost.setEdgeLinkId(currentElinkId);
460
461 }
462
Simon Huntc0f20c12016-05-09 09:30:20 -0700463 HostLocation hloc = h.location();
464 uiHost.setLocation(hloc.deviceId(), hloc.port());
Simon Huntc0f20c12016-05-09 09:30:20 -0700465 }
466
467 private void loadHosts() {
468 for (Host h : services.host().getHosts()) {
469 UiHost host = addNewHost(h);
470 updateHost(host, h);
471 }
472 }
473
474 // invoked from UiSharedTopologyModel host listener
Simon Hunt23fb1352016-04-11 12:15:19 -0700475 void addOrUpdateHost(Host host) {
Simon Huntc0f20c12016-05-09 09:30:20 -0700476 HostId id = host.id();
477 UiHost uiHost = uiTopology.findHost(id);
478 if (uiHost == null) {
479 uiHost = addNewHost(host);
480 }
481 updateHost(uiHost, host);
482
483 postEvent(HOST_ADDED_OR_UPDATED, uiHost);
Simon Hunt23fb1352016-04-11 12:15:19 -0700484 }
485
Simon Huntc0f20c12016-05-09 09:30:20 -0700486 // invoked from UiSharedTopologyModel host listener
Simon Hunt23fb1352016-04-11 12:15:19 -0700487 void moveHost(Host host, Host prevHost) {
Simon Huntc0f20c12016-05-09 09:30:20 -0700488 UiHost uiHost = uiTopology.findHost(prevHost.id());
Simon Hunt58a0dd02016-05-17 11:54:23 -0700489 if (uiHost != null) {
490 updateHost(uiHost, host);
491 postEvent(HOST_MOVED, uiHost);
492 } else {
493 log.warn(E_NO_ELEMENT, "host", prevHost.id());
494 }
495 }
Simon Huntc0f20c12016-05-09 09:30:20 -0700496
Simon Hunt58a0dd02016-05-17 11:54:23 -0700497 // package private for unit test access
498 UiHost accessHost(HostId id) {
499 return uiTopology.findHost(id);
Simon Hunt23fb1352016-04-11 12:15:19 -0700500 }
501
Simon Huntc0f20c12016-05-09 09:30:20 -0700502 // invoked from UiSharedTopologyModel host listener
Simon Hunt23fb1352016-04-11 12:15:19 -0700503 void removeHost(Host host) {
Simon Huntc0f20c12016-05-09 09:30:20 -0700504 HostId id = host.id();
505 UiHost uiHost = uiTopology.findHost(id);
506 if (uiHost != null) {
Simon Huntc13082f2016-08-03 21:20:23 -0700507 UiEdgeLink edgeLink = uiTopology.findEdgeLink(uiHost.edgeLinkId());
Simon Hunt58a0dd02016-05-17 11:54:23 -0700508 uiTopology.remove(edgeLink);
Simon Huntc0f20c12016-05-09 09:30:20 -0700509 uiTopology.remove(uiHost);
Simon Huntc0f20c12016-05-09 09:30:20 -0700510 postEvent(HOST_REMOVED, uiHost);
511 } else {
512 log.warn(E_NO_ELEMENT, "host", id);
513 }
Simon Hunt23fb1352016-04-11 12:15:19 -0700514 }
Simon Hunt338a3b42016-04-14 09:43:52 -0700515
Simon Hunt4854f3d2016-08-02 18:13:15 -0700516 Set<UiHost> getAllHosts() {
517 return uiTopology.allHosts();
518 }
519
Simon Huntc0f20c12016-05-09 09:30:20 -0700520
Simon Huntc13082f2016-08-03 21:20:23 -0700521 // === SYNTHETIC LINKS
522
523 List<UiSynthLink> getSynthLinks(RegionId regionId) {
524 return uiTopology.findSynthLinks(regionId);
525 }
526
Simon Huntb1ce2602016-07-23 14:04:31 -0700527 /**
528 * Refreshes the internal state.
529 */
530 public void refresh() {
Simon Huntc13082f2016-08-03 21:20:23 -0700531 // fix up internal linkages to ensure they are correct
Simon Huntb1ce2602016-07-23 14:04:31 -0700532
Simon Hunt4f4ffc32016-08-03 18:30:47 -0700533 // make sure regions reflect layout containment hierarchy
534 fixupContainmentHierarchy(uiTopology.nullRegion());
535 uiTopology.allRegions().forEach(this::fixupContainmentHierarchy);
536
Steven Burrows19e6e4f2016-10-05 13:27:07 -0500537 // make sure devices and hosts are in the correct region
Simon Huntb1ce2602016-07-23 14:04:31 -0700538 Set<UiDevice> allDevices = uiTopology.allDevices();
Steven Burrows19e6e4f2016-10-05 13:27:07 -0500539 Set<UiHost> allHosts = uiTopology.allHosts();
Simon Huntb1ce2602016-07-23 14:04:31 -0700540
541 services.region().getRegions().forEach(r -> {
542 RegionId rid = r.id();
543 UiRegion region = uiTopology.findRegion(rid);
544 if (region != null) {
Steven Burrows8f45ce22016-10-27 20:04:14 -0500545 reconcileDevicesAndHostsWithRegion(allDevices, allHosts, rid, region);
Simon Huntb1ce2602016-07-23 14:04:31 -0700546 } else {
547 log.warn("No UiRegion in topology for ID {}", rid);
548 }
549 });
550
551 // what is left over, must belong to the null-region
552 Set<DeviceId> leftOver = new HashSet<>(allDevices.size());
553 allDevices.forEach(d -> leftOver.add(d.id()));
554 uiTopology.nullRegion().reconcileDevices(leftOver);
Simon Huntc13082f2016-08-03 21:20:23 -0700555
Steven Burrows19e6e4f2016-10-05 13:27:07 -0500556 Set<HostId> leftOverHosts = new HashSet<>(allHosts.size());
557 allHosts.forEach(h -> leftOverHosts.add(h.id()));
558 uiTopology.nullRegion().reconcileHosts(leftOverHosts);
559
Simon Huntc13082f2016-08-03 21:20:23 -0700560 // now that we have correct region hierarchy, and devices are in their
561 // respective regions, we can compute synthetic links for each region.
562 uiTopology.computeSynthLinks();
Simon Huntb1ce2602016-07-23 14:04:31 -0700563 }
564
Steven Burrows8f45ce22016-10-27 20:04:14 -0500565 private void reconcileDevicesAndHostsWithRegion(Set<UiDevice> allDevices,
566 Set<UiHost> allHosts,
567 RegionId rid,
568 UiRegion region) {
Steven Burrows19e6e4f2016-10-05 13:27:07 -0500569 Set<DeviceId> deviceIds = services.region().getRegionDevices(rid);
Steven Burrows8f45ce22016-10-27 20:04:14 -0500570 Set<HostId> hostIds = new HashSet<>();
Steven Burrows19e6e4f2016-10-05 13:27:07 -0500571 region.reconcileDevices(deviceIds);
572
573 deviceIds.forEach(devId -> {
574 UiDevice dev = uiTopology.findDevice(devId);
575 if (dev != null) {
Steven Burrows8f45ce22016-10-27 20:04:14 -0500576 dev.setRegionId(rid);
Steven Burrows19e6e4f2016-10-05 13:27:07 -0500577 allDevices.remove(dev);
578 } else {
579 log.warn("Region device ID {} but no UiDevice in topology",
580 devId);
581 }
Steven Burrows8f45ce22016-10-27 20:04:14 -0500582
583 Set<Host> hosts = services.host().getConnectedHosts(devId);
584 for (Host h : hosts) {
585 HostId hid = h.id();
586 hostIds.add(hid);
587 UiHost host = uiTopology.findHost(hid);
588
589 if (host != null) {
590 host.setRegionId(rid);
591 allHosts.remove(host);
592 } else {
593 log.warn("Region host ID {} but no UiHost in topology",
594 hid);
595 }
596 }
Steven Burrows19e6e4f2016-10-05 13:27:07 -0500597 });
Steven Burrows8f45ce22016-10-27 20:04:14 -0500598
599 region.reconcileHosts(hostIds);
Steven Burrows19e6e4f2016-10-05 13:27:07 -0500600 }
601
Simon Huntc13082f2016-08-03 21:20:23 -0700602
Simon Huntc0f20c12016-05-09 09:30:20 -0700603 // === CACHE STATISTICS
604
Simon Hunt338a3b42016-04-14 09:43:52 -0700605 /**
Simon Hunt58a0dd02016-05-17 11:54:23 -0700606 * Returns a detailed (multi-line) string showing the contents of the cache.
607 *
608 * @return detailed string
609 */
610 public String dumpString() {
611 return uiTopology.dumpString();
612 }
613
614 /**
Simon Hunt338a3b42016-04-14 09:43:52 -0700615 * Returns the number of members in the cluster.
616 *
617 * @return number of cluster members
618 */
619 public int clusterMemberCount() {
620 return uiTopology.clusterMemberCount();
621 }
622
623 /**
Simon Huntc0f20c12016-05-09 09:30:20 -0700624 * Returns the number of regions in the topology.
Simon Hunt338a3b42016-04-14 09:43:52 -0700625 *
626 * @return number of regions
627 */
628 public int regionCount() {
629 return uiTopology.regionCount();
630 }
Simon Hunt58a0dd02016-05-17 11:54:23 -0700631
632 /**
633 * Returns the number of devices in the topology.
634 *
635 * @return number of devices
636 */
637 public int deviceCount() {
638 return uiTopology.deviceCount();
639 }
640
641 /**
Simon Huntc13082f2016-08-03 21:20:23 -0700642 * Returns the number of device links in the topology.
Simon Hunt58a0dd02016-05-17 11:54:23 -0700643 *
Simon Huntc13082f2016-08-03 21:20:23 -0700644 * @return number of device links
Simon Hunt58a0dd02016-05-17 11:54:23 -0700645 */
Simon Huntc13082f2016-08-03 21:20:23 -0700646 public int deviceLinkCount() {
647 return uiTopology.deviceLinkCount();
648 }
649
650 /**
651 * Returns the number of edge links in the topology.
652 *
653 * @return number of edge links
654 */
655 public int edgeLinkCount() {
656 return uiTopology.edgeLinkCount();
Simon Hunt58a0dd02016-05-17 11:54:23 -0700657 }
658
659 /**
660 * Returns the number of hosts in the topology.
661 *
662 * @return number of hosts
663 */
664 public int hostCount() {
665 return uiTopology.hostCount();
666 }
Simon Huntd5b96732016-07-08 13:22:27 -0700667
Simon Huntc13082f2016-08-03 21:20:23 -0700668 /**
669 * Returns the number of synthetic links in the topology.
670 *
671 * @return the number of synthetic links
672 */
673 public int synthLinkCount() {
674 return uiTopology.synthLinkCount();
675 }
Simon Huntcda9c032016-04-11 10:32:54 -0700676}