blob: 6566511de0d917dda29f20aa7be0a20d43cc567e [file] [log] [blame]
Simon Huntcda9c032016-04-11 10:32:54 -07001/*
2 * Copyright 2016 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
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 Hunt642bc452016-05-04 19:34:45 -070032import org.onosproject.ui.model.ServiceBundle;
Simon Hunt338a3b42016-04-14 09:43:52 -070033import org.onosproject.ui.model.topo.UiClusterMember;
Simon Huntcda9c032016-04-11 10:32:54 -070034import org.onosproject.ui.model.topo.UiDevice;
Simon Huntc0f20c12016-05-09 09:30:20 -070035import org.onosproject.ui.model.topo.UiElement;
36import org.onosproject.ui.model.topo.UiHost;
37import org.onosproject.ui.model.topo.UiLink;
38import org.onosproject.ui.model.topo.UiLinkId;
39import org.onosproject.ui.model.topo.UiRegion;
Simon Hunt23fb1352016-04-11 12:15:19 -070040import org.onosproject.ui.model.topo.UiTopology;
Simon Hunt642bc452016-05-04 19:34:45 -070041import org.slf4j.Logger;
42import org.slf4j.LoggerFactory;
Simon Hunt23fb1352016-04-11 12:15:19 -070043
Simon Huntc0f20c12016-05-09 09:30:20 -070044import java.util.Set;
45
46import static org.onosproject.net.DefaultEdgeLink.createEdgeLink;
Simon Hunt642bc452016-05-04 19:34:45 -070047import static org.onosproject.ui.impl.topo.model.UiModelEvent.Type.CLUSTER_MEMBER_ADDED_OR_UPDATED;
48import static org.onosproject.ui.impl.topo.model.UiModelEvent.Type.CLUSTER_MEMBER_REMOVED;
49import static org.onosproject.ui.impl.topo.model.UiModelEvent.Type.DEVICE_ADDED_OR_UPDATED;
Simon Hunt23fb1352016-04-11 12:15:19 -070050import static org.onosproject.ui.impl.topo.model.UiModelEvent.Type.DEVICE_REMOVED;
Simon Huntc0f20c12016-05-09 09:30:20 -070051import static org.onosproject.ui.impl.topo.model.UiModelEvent.Type.HOST_ADDED_OR_UPDATED;
52import static org.onosproject.ui.impl.topo.model.UiModelEvent.Type.HOST_MOVED;
53import static org.onosproject.ui.impl.topo.model.UiModelEvent.Type.HOST_REMOVED;
54import static org.onosproject.ui.impl.topo.model.UiModelEvent.Type.LINK_ADDED_OR_UPDATED;
55import static org.onosproject.ui.impl.topo.model.UiModelEvent.Type.LINK_REMOVED;
56import static org.onosproject.ui.impl.topo.model.UiModelEvent.Type.REGION_ADDED_OR_UPDATED;
57import static org.onosproject.ui.impl.topo.model.UiModelEvent.Type.REGION_REMOVED;
58import static org.onosproject.ui.model.topo.UiLinkId.uiLinkId;
Simon Huntcda9c032016-04-11 10:32:54 -070059
60/**
61 * UI Topology Model cache.
62 */
63class ModelCache {
64
Simon Huntc0f20c12016-05-09 09:30:20 -070065 private static final String E_NO_ELEMENT = "Tried to remove non-member {}: {}";
66
Simon Hunt642bc452016-05-04 19:34:45 -070067 private static final Logger log = LoggerFactory.getLogger(ModelCache.class);
68
69 private final ServiceBundle services;
Simon Huntcda9c032016-04-11 10:32:54 -070070 private final EventDispatcher dispatcher;
Simon Hunt23fb1352016-04-11 12:15:19 -070071 private final UiTopology uiTopology = new UiTopology();
Simon Huntcda9c032016-04-11 10:32:54 -070072
Simon Hunt642bc452016-05-04 19:34:45 -070073 ModelCache(ServiceBundle services, EventDispatcher eventDispatcher) {
74 this.services = services;
Simon Huntcda9c032016-04-11 10:32:54 -070075 this.dispatcher = eventDispatcher;
76 }
77
Simon Hunt338a3b42016-04-14 09:43:52 -070078 @Override
79 public String toString() {
80 return "ModelCache{" + uiTopology + "}";
81 }
82
Simon Huntc0f20c12016-05-09 09:30:20 -070083 private void postEvent(UiModelEvent.Type type, UiElement subject) {
84 dispatcher.post(new UiModelEvent(type, subject));
85 }
86
Simon Huntcda9c032016-04-11 10:32:54 -070087 void clear() {
Simon Hunt23fb1352016-04-11 12:15:19 -070088 uiTopology.clear();
Simon Huntcda9c032016-04-11 10:32:54 -070089 }
90
91 /**
Simon Huntc0f20c12016-05-09 09:30:20 -070092 * Create our internal model of the global topology. An assumption we are
93 * making is that the topology is empty to start.
Simon Huntcda9c032016-04-11 10:32:54 -070094 */
95 void load() {
Simon Huntc0f20c12016-05-09 09:30:20 -070096 loadClusterMembers();
97 loadRegions();
98 loadDevices();
99 loadLinks();
100 loadHosts();
Simon Huntcda9c032016-04-11 10:32:54 -0700101 }
102
103
Simon Huntc0f20c12016-05-09 09:30:20 -0700104 // === CLUSTER MEMBERS
105
106 private UiClusterMember addNewClusterMember(ControllerNode n) {
107 UiClusterMember member = new UiClusterMember(uiTopology, n);
108 uiTopology.add(member);
109 return member;
110 }
111
112 private void updateClusterMember(UiClusterMember member) {
113 ControllerNode.State state = services.cluster().getState(member.id());
114 member.setState(state);
115 member.setMastership(services.mastership().getDevicesOf(member.id()));
116 // NOTE: 'UI-attached' is session-based data, not global, so will
117 // be set elsewhere
118 }
119
120 private void loadClusterMembers() {
121 for (ControllerNode n : services.cluster().getNodes()) {
122 UiClusterMember member = addNewClusterMember(n);
123 updateClusterMember(member);
124 }
125 }
126
127 // invoked from UiSharedTopologyModel cluster event listener
Simon Hunt338a3b42016-04-14 09:43:52 -0700128 void addOrUpdateClusterMember(ControllerNode cnode) {
Simon Hunt642bc452016-05-04 19:34:45 -0700129 NodeId id = cnode.id();
130 UiClusterMember member = uiTopology.findClusterMember(id);
131 if (member == null) {
Simon Huntc0f20c12016-05-09 09:30:20 -0700132 member = addNewClusterMember(cnode);
Simon Hunt338a3b42016-04-14 09:43:52 -0700133 }
Simon Huntc0f20c12016-05-09 09:30:20 -0700134 updateClusterMember(member);
Simon Hunt338a3b42016-04-14 09:43:52 -0700135
Simon Huntc0f20c12016-05-09 09:30:20 -0700136 postEvent(CLUSTER_MEMBER_ADDED_OR_UPDATED, member);
Simon Hunt338a3b42016-04-14 09:43:52 -0700137 }
138
Simon Huntc0f20c12016-05-09 09:30:20 -0700139 // package private for unit test access
140 UiClusterMember accessClusterMember(NodeId id) {
141 return uiTopology.findClusterMember(id);
142 }
143
144 // invoked from UiSharedTopologyModel cluster event listener
Simon Hunt338a3b42016-04-14 09:43:52 -0700145 void removeClusterMember(ControllerNode cnode) {
Simon Hunt642bc452016-05-04 19:34:45 -0700146 NodeId id = cnode.id();
147 UiClusterMember member = uiTopology.findClusterMember(id);
148 if (member != null) {
149 uiTopology.remove(member);
Simon Huntc0f20c12016-05-09 09:30:20 -0700150 postEvent(CLUSTER_MEMBER_REMOVED, member);
Simon Hunt642bc452016-05-04 19:34:45 -0700151 } else {
Simon Huntc0f20c12016-05-09 09:30:20 -0700152 log.warn(E_NO_ELEMENT, "cluster node", id);
Simon Hunt642bc452016-05-04 19:34:45 -0700153 }
Simon Hunt338a3b42016-04-14 09:43:52 -0700154 }
155
Simon Huntc0f20c12016-05-09 09:30:20 -0700156
157 // === MASTERSHIP CHANGES
158
159 // invoked from UiSharedTopologyModel mastership listener
Simon Hunt338a3b42016-04-14 09:43:52 -0700160 void updateMasterships(DeviceId deviceId, RoleInfo roleInfo) {
Simon Huntc0f20c12016-05-09 09:30:20 -0700161 // To think about:: do we need to store mastership info?
162 // or can we rely on looking it up live?
Simon Hunt338a3b42016-04-14 09:43:52 -0700163 // TODO: store the updated mastership information
164 // TODO: post event
165 }
166
Simon Huntc0f20c12016-05-09 09:30:20 -0700167
168 // === REGIONS
169
170 private UiRegion addNewRegion(Region r) {
171 UiRegion region = new UiRegion(uiTopology, r);
172 uiTopology.add(region);
173 return region;
174 }
175
176 private void updateRegion(UiRegion region) {
177 Set<DeviceId> devs = services.region().getRegionDevices(region.id());
178 region.reconcileDevices(devs);
179 }
180
181 private void loadRegions() {
182 for (Region r : services.region().getRegions()) {
183 UiRegion region = addNewRegion(r);
184 updateRegion(region);
185 }
186 }
187
188 // invoked from UiSharedTopologyModel region listener
Simon Hunt338a3b42016-04-14 09:43:52 -0700189 void addOrUpdateRegion(Region region) {
Simon Huntc0f20c12016-05-09 09:30:20 -0700190 RegionId id = region.id();
191 UiRegion uiRegion = uiTopology.findRegion(id);
192 if (uiRegion == null) {
193 uiRegion = addNewRegion(region);
194 }
195 updateRegion(uiRegion);
196
197 postEvent(REGION_ADDED_OR_UPDATED, uiRegion);
Simon Hunt338a3b42016-04-14 09:43:52 -0700198 }
199
Simon Hunt58a0dd02016-05-17 11:54:23 -0700200 // package private for unit test access
201 UiRegion accessRegion(RegionId id) {
202 return uiTopology.findRegion(id);
203 }
204
Simon Huntc0f20c12016-05-09 09:30:20 -0700205 // invoked from UiSharedTopologyModel region listener
Simon Hunt338a3b42016-04-14 09:43:52 -0700206 void removeRegion(Region region) {
Simon Huntc0f20c12016-05-09 09:30:20 -0700207 RegionId id = region.id();
208 UiRegion uiRegion = uiTopology.findRegion(id);
209 if (uiRegion != null) {
210 uiTopology.remove(uiRegion);
211 postEvent(REGION_REMOVED, uiRegion);
212 } else {
213 log.warn(E_NO_ELEMENT, "region", id);
214 }
Simon Hunt338a3b42016-04-14 09:43:52 -0700215 }
216
Simon Huntc0f20c12016-05-09 09:30:20 -0700217
218 // === DEVICES
219
220 private UiDevice addNewDevice(Device d) {
221 UiDevice device = new UiDevice(uiTopology, d);
222 uiTopology.add(device);
223 return device;
224 }
225
226 private void updateDevice(UiDevice device) {
Thomas Vachuska92b016b2016-05-20 11:37:57 -0700227 Region regionForDevice = services.region().getRegionForDevice(device.id());
228 if (regionForDevice != null) {
229 device.setRegionId(regionForDevice.id());
230 }
Simon Huntc0f20c12016-05-09 09:30:20 -0700231 }
232
233 private void loadDevices() {
234 for (Device d : services.device().getDevices()) {
235 UiDevice device = addNewDevice(d);
236 updateDevice(device);
237 }
238 }
239
240 // invoked from UiSharedTopologyModel device listener
Simon Huntcda9c032016-04-11 10:32:54 -0700241 void addOrUpdateDevice(Device device) {
Simon Huntc0f20c12016-05-09 09:30:20 -0700242 DeviceId id = device.id();
243 UiDevice uiDevice = uiTopology.findDevice(id);
244 if (uiDevice == null) {
245 uiDevice = addNewDevice(device);
246 }
247 updateDevice(uiDevice);
Simon Huntcda9c032016-04-11 10:32:54 -0700248
Simon Huntc0f20c12016-05-09 09:30:20 -0700249 postEvent(DEVICE_ADDED_OR_UPDATED, uiDevice);
Simon Huntcda9c032016-04-11 10:32:54 -0700250 }
251
Simon Hunt58a0dd02016-05-17 11:54:23 -0700252 // package private for unit test access
253 UiDevice accessDevice(DeviceId id) {
254 return uiTopology.findDevice(id);
255 }
256
Simon Huntc0f20c12016-05-09 09:30:20 -0700257 // invoked from UiSharedTopologyModel device listener
Simon Huntcda9c032016-04-11 10:32:54 -0700258 void removeDevice(Device device) {
Simon Huntc0f20c12016-05-09 09:30:20 -0700259 DeviceId id = device.id();
260 UiDevice uiDevice = uiTopology.findDevice(id);
261 if (uiDevice != null) {
262 uiTopology.remove(uiDevice);
263 postEvent(DEVICE_REMOVED, uiDevice);
264 } else {
265 log.warn(E_NO_ELEMENT, "device", id);
266 }
Simon Huntcda9c032016-04-11 10:32:54 -0700267 }
268
Simon Huntc0f20c12016-05-09 09:30:20 -0700269
270 // === LINKS
271
272 private UiLink addNewLink(UiLinkId id) {
273 UiLink uiLink = new UiLink(uiTopology, id);
274 uiTopology.add(uiLink);
275 return uiLink;
276 }
277
278 private void updateLink(UiLink uiLink, Link link) {
279 uiLink.attachBackingLink(link);
280 }
281
282 private void loadLinks() {
283 for (Link link : services.link().getLinks()) {
284 UiLinkId id = uiLinkId(link);
285
286 UiLink uiLink = uiTopology.findLink(id);
287 if (uiLink == null) {
288 uiLink = addNewLink(id);
289 }
290 updateLink(uiLink, link);
291 }
292 }
293
294 // invoked from UiSharedTopologyModel link listener
Simon Hunt23fb1352016-04-11 12:15:19 -0700295 void addOrUpdateLink(Link link) {
Simon Huntc0f20c12016-05-09 09:30:20 -0700296 UiLinkId id = uiLinkId(link);
297 UiLink uiLink = uiTopology.findLink(id);
298 if (uiLink == null) {
299 uiLink = addNewLink(id);
300 }
301 updateLink(uiLink, link);
302
303 postEvent(LINK_ADDED_OR_UPDATED, uiLink);
Simon Hunt23fb1352016-04-11 12:15:19 -0700304 }
305
Simon Hunt58a0dd02016-05-17 11:54:23 -0700306 // package private for unit test access
307 UiLink accessLink(UiLinkId id) {
308 return uiTopology.findLink(id);
309 }
310
Simon Huntc0f20c12016-05-09 09:30:20 -0700311 // invoked from UiSharedTopologyModel link listener
Simon Hunt23fb1352016-04-11 12:15:19 -0700312 void removeLink(Link link) {
Simon Huntc0f20c12016-05-09 09:30:20 -0700313 UiLinkId id = uiLinkId(link);
314 UiLink uiLink = uiTopology.findLink(id);
315 if (uiLink != null) {
316 boolean remaining = uiLink.detachBackingLink(link);
317 if (remaining) {
318 postEvent(LINK_ADDED_OR_UPDATED, uiLink);
319 } else {
320 uiTopology.remove(uiLink);
321 postEvent(LINK_REMOVED, uiLink);
322 }
323 } else {
324 log.warn(E_NO_ELEMENT, "link", id);
325 }
Simon Hunt23fb1352016-04-11 12:15:19 -0700326 }
327
Simon Huntc0f20c12016-05-09 09:30:20 -0700328
329 // === HOSTS
330
Simon Hunt58a0dd02016-05-17 11:54:23 -0700331 private EdgeLink synthesizeLink(Host h) {
332 return createEdgeLink(h, true);
333 }
334
Simon Huntc0f20c12016-05-09 09:30:20 -0700335 private UiHost addNewHost(Host h) {
336 UiHost host = new UiHost(uiTopology, h);
337 uiTopology.add(host);
338
Simon Hunt58a0dd02016-05-17 11:54:23 -0700339 EdgeLink elink = synthesizeLink(h);
340 UiLinkId elinkId = uiLinkId(elink);
341 host.setEdgeLinkId(elinkId);
342
343 // add synthesized edge link to the topology
344 UiLink edgeLink = addNewLink(elinkId);
345 edgeLink.attachEdgeLink(elink);
Simon Huntc0f20c12016-05-09 09:30:20 -0700346
347 return host;
348 }
349
Simon Hunt58a0dd02016-05-17 11:54:23 -0700350 private void insertNewUiLink(UiLinkId id, EdgeLink e) {
351 UiLink newEdgeLink = addNewLink(id);
352 newEdgeLink.attachEdgeLink(e);
Simon Huntc0f20c12016-05-09 09:30:20 -0700353
Simon Huntc0f20c12016-05-09 09:30:20 -0700354 }
355
356 private void updateHost(UiHost uiHost, Host h) {
Simon Hunt58a0dd02016-05-17 11:54:23 -0700357 UiLink existing = uiTopology.findLink(uiHost.edgeLinkId());
358
359 EdgeLink currentElink = synthesizeLink(h);
360 UiLinkId currentElinkId = uiLinkId(currentElink);
361
362 if (existing != null) {
363 if (!currentElinkId.equals(existing.id())) {
364 // edge link has changed
365 insertNewUiLink(currentElinkId, currentElink);
366 uiHost.setEdgeLinkId(currentElinkId);
367
368 uiTopology.remove(existing);
369 }
370
371 } else {
372 // no previously existing edge link
373 insertNewUiLink(currentElinkId, currentElink);
374 uiHost.setEdgeLinkId(currentElinkId);
375
376 }
377
Simon Huntc0f20c12016-05-09 09:30:20 -0700378 HostLocation hloc = h.location();
379 uiHost.setLocation(hloc.deviceId(), hloc.port());
Simon Huntc0f20c12016-05-09 09:30:20 -0700380 }
381
382 private void loadHosts() {
383 for (Host h : services.host().getHosts()) {
384 UiHost host = addNewHost(h);
385 updateHost(host, h);
386 }
387 }
388
389 // invoked from UiSharedTopologyModel host listener
Simon Hunt23fb1352016-04-11 12:15:19 -0700390 void addOrUpdateHost(Host host) {
Simon Huntc0f20c12016-05-09 09:30:20 -0700391 HostId id = host.id();
392 UiHost uiHost = uiTopology.findHost(id);
393 if (uiHost == null) {
394 uiHost = addNewHost(host);
395 }
396 updateHost(uiHost, host);
397
398 postEvent(HOST_ADDED_OR_UPDATED, uiHost);
Simon Hunt23fb1352016-04-11 12:15:19 -0700399 }
400
Simon Huntc0f20c12016-05-09 09:30:20 -0700401 // invoked from UiSharedTopologyModel host listener
Simon Hunt23fb1352016-04-11 12:15:19 -0700402 void moveHost(Host host, Host prevHost) {
Simon Huntc0f20c12016-05-09 09:30:20 -0700403 UiHost uiHost = uiTopology.findHost(prevHost.id());
Simon Hunt58a0dd02016-05-17 11:54:23 -0700404 if (uiHost != null) {
405 updateHost(uiHost, host);
406 postEvent(HOST_MOVED, uiHost);
407 } else {
408 log.warn(E_NO_ELEMENT, "host", prevHost.id());
409 }
410 }
Simon Huntc0f20c12016-05-09 09:30:20 -0700411
Simon Hunt58a0dd02016-05-17 11:54:23 -0700412 // package private for unit test access
413 UiHost accessHost(HostId id) {
414 return uiTopology.findHost(id);
Simon Hunt23fb1352016-04-11 12:15:19 -0700415 }
416
Simon Huntc0f20c12016-05-09 09:30:20 -0700417 // invoked from UiSharedTopologyModel host listener
Simon Hunt23fb1352016-04-11 12:15:19 -0700418 void removeHost(Host host) {
Simon Huntc0f20c12016-05-09 09:30:20 -0700419 HostId id = host.id();
420 UiHost uiHost = uiTopology.findHost(id);
421 if (uiHost != null) {
Simon Hunt58a0dd02016-05-17 11:54:23 -0700422 UiLink edgeLink = uiTopology.findLink(uiHost.edgeLinkId());
423 uiTopology.remove(edgeLink);
Simon Huntc0f20c12016-05-09 09:30:20 -0700424 uiTopology.remove(uiHost);
Simon Huntc0f20c12016-05-09 09:30:20 -0700425 postEvent(HOST_REMOVED, uiHost);
426 } else {
427 log.warn(E_NO_ELEMENT, "host", id);
428 }
Simon Hunt23fb1352016-04-11 12:15:19 -0700429 }
Simon Hunt338a3b42016-04-14 09:43:52 -0700430
Simon Huntc0f20c12016-05-09 09:30:20 -0700431
432 // === CACHE STATISTICS
433
Simon Hunt338a3b42016-04-14 09:43:52 -0700434 /**
Simon Hunt58a0dd02016-05-17 11:54:23 -0700435 * Returns a detailed (multi-line) string showing the contents of the cache.
436 *
437 * @return detailed string
438 */
439 public String dumpString() {
440 return uiTopology.dumpString();
441 }
442
443 /**
Simon Hunt338a3b42016-04-14 09:43:52 -0700444 * Returns the number of members in the cluster.
445 *
446 * @return number of cluster members
447 */
448 public int clusterMemberCount() {
449 return uiTopology.clusterMemberCount();
450 }
451
452 /**
Simon Huntc0f20c12016-05-09 09:30:20 -0700453 * Returns the number of regions in the topology.
Simon Hunt338a3b42016-04-14 09:43:52 -0700454 *
455 * @return number of regions
456 */
457 public int regionCount() {
458 return uiTopology.regionCount();
459 }
Simon Hunt58a0dd02016-05-17 11:54:23 -0700460
461 /**
462 * Returns the number of devices in the topology.
463 *
464 * @return number of devices
465 */
466 public int deviceCount() {
467 return uiTopology.deviceCount();
468 }
469
470 /**
471 * Returns the number of links in the topology.
472 *
473 * @return number of links
474 */
475 public int linkCount() {
476 return uiTopology.linkCount();
477 }
478
479 /**
480 * Returns the number of hosts in the topology.
481 *
482 * @return number of hosts
483 */
484 public int hostCount() {
485 return uiTopology.hostCount();
486 }
Simon Huntcda9c032016-04-11 10:32:54 -0700487}