blob: 19ab01566f40e78c594a67edcc3ace418d76d8dc [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) {
227 device.setRegionId(services.region().getRegionForDevice(device.id()).id());
228 }
229
230 private void loadDevices() {
231 for (Device d : services.device().getDevices()) {
232 UiDevice device = addNewDevice(d);
233 updateDevice(device);
234 }
235 }
236
237 // invoked from UiSharedTopologyModel device listener
Simon Huntcda9c032016-04-11 10:32:54 -0700238 void addOrUpdateDevice(Device device) {
Simon Huntc0f20c12016-05-09 09:30:20 -0700239 DeviceId id = device.id();
240 UiDevice uiDevice = uiTopology.findDevice(id);
241 if (uiDevice == null) {
242 uiDevice = addNewDevice(device);
243 }
244 updateDevice(uiDevice);
Simon Huntcda9c032016-04-11 10:32:54 -0700245
Simon Huntc0f20c12016-05-09 09:30:20 -0700246 postEvent(DEVICE_ADDED_OR_UPDATED, uiDevice);
Simon Huntcda9c032016-04-11 10:32:54 -0700247 }
248
Simon Hunt58a0dd02016-05-17 11:54:23 -0700249 // package private for unit test access
250 UiDevice accessDevice(DeviceId id) {
251 return uiTopology.findDevice(id);
252 }
253
Simon Huntc0f20c12016-05-09 09:30:20 -0700254 // invoked from UiSharedTopologyModel device listener
Simon Huntcda9c032016-04-11 10:32:54 -0700255 void removeDevice(Device device) {
Simon Huntc0f20c12016-05-09 09:30:20 -0700256 DeviceId id = device.id();
257 UiDevice uiDevice = uiTopology.findDevice(id);
258 if (uiDevice != null) {
259 uiTopology.remove(uiDevice);
260 postEvent(DEVICE_REMOVED, uiDevice);
261 } else {
262 log.warn(E_NO_ELEMENT, "device", id);
263 }
Simon Huntcda9c032016-04-11 10:32:54 -0700264 }
265
Simon Huntc0f20c12016-05-09 09:30:20 -0700266
267 // === LINKS
268
269 private UiLink addNewLink(UiLinkId id) {
270 UiLink uiLink = new UiLink(uiTopology, id);
271 uiTopology.add(uiLink);
272 return uiLink;
273 }
274
275 private void updateLink(UiLink uiLink, Link link) {
276 uiLink.attachBackingLink(link);
277 }
278
279 private void loadLinks() {
280 for (Link link : services.link().getLinks()) {
281 UiLinkId id = uiLinkId(link);
282
283 UiLink uiLink = uiTopology.findLink(id);
284 if (uiLink == null) {
285 uiLink = addNewLink(id);
286 }
287 updateLink(uiLink, link);
288 }
289 }
290
291 // invoked from UiSharedTopologyModel link listener
Simon Hunt23fb1352016-04-11 12:15:19 -0700292 void addOrUpdateLink(Link link) {
Simon Huntc0f20c12016-05-09 09:30:20 -0700293 UiLinkId id = uiLinkId(link);
294 UiLink uiLink = uiTopology.findLink(id);
295 if (uiLink == null) {
296 uiLink = addNewLink(id);
297 }
298 updateLink(uiLink, link);
299
300 postEvent(LINK_ADDED_OR_UPDATED, uiLink);
Simon Hunt23fb1352016-04-11 12:15:19 -0700301 }
302
Simon Hunt58a0dd02016-05-17 11:54:23 -0700303 // package private for unit test access
304 UiLink accessLink(UiLinkId id) {
305 return uiTopology.findLink(id);
306 }
307
Simon Huntc0f20c12016-05-09 09:30:20 -0700308 // invoked from UiSharedTopologyModel link listener
Simon Hunt23fb1352016-04-11 12:15:19 -0700309 void removeLink(Link link) {
Simon Huntc0f20c12016-05-09 09:30:20 -0700310 UiLinkId id = uiLinkId(link);
311 UiLink uiLink = uiTopology.findLink(id);
312 if (uiLink != null) {
313 boolean remaining = uiLink.detachBackingLink(link);
314 if (remaining) {
315 postEvent(LINK_ADDED_OR_UPDATED, uiLink);
316 } else {
317 uiTopology.remove(uiLink);
318 postEvent(LINK_REMOVED, uiLink);
319 }
320 } else {
321 log.warn(E_NO_ELEMENT, "link", id);
322 }
Simon Hunt23fb1352016-04-11 12:15:19 -0700323 }
324
Simon Huntc0f20c12016-05-09 09:30:20 -0700325
326 // === HOSTS
327
Simon Hunt58a0dd02016-05-17 11:54:23 -0700328 private EdgeLink synthesizeLink(Host h) {
329 return createEdgeLink(h, true);
330 }
331
Simon Huntc0f20c12016-05-09 09:30:20 -0700332 private UiHost addNewHost(Host h) {
333 UiHost host = new UiHost(uiTopology, h);
334 uiTopology.add(host);
335
Simon Hunt58a0dd02016-05-17 11:54:23 -0700336 EdgeLink elink = synthesizeLink(h);
337 UiLinkId elinkId = uiLinkId(elink);
338 host.setEdgeLinkId(elinkId);
339
340 // add synthesized edge link to the topology
341 UiLink edgeLink = addNewLink(elinkId);
342 edgeLink.attachEdgeLink(elink);
Simon Huntc0f20c12016-05-09 09:30:20 -0700343
344 return host;
345 }
346
Simon Hunt58a0dd02016-05-17 11:54:23 -0700347 private void insertNewUiLink(UiLinkId id, EdgeLink e) {
348 UiLink newEdgeLink = addNewLink(id);
349 newEdgeLink.attachEdgeLink(e);
Simon Huntc0f20c12016-05-09 09:30:20 -0700350
Simon Huntc0f20c12016-05-09 09:30:20 -0700351 }
352
353 private void updateHost(UiHost uiHost, Host h) {
Simon Hunt58a0dd02016-05-17 11:54:23 -0700354 UiLink existing = uiTopology.findLink(uiHost.edgeLinkId());
355
356 EdgeLink currentElink = synthesizeLink(h);
357 UiLinkId currentElinkId = uiLinkId(currentElink);
358
359 if (existing != null) {
360 if (!currentElinkId.equals(existing.id())) {
361 // edge link has changed
362 insertNewUiLink(currentElinkId, currentElink);
363 uiHost.setEdgeLinkId(currentElinkId);
364
365 uiTopology.remove(existing);
366 }
367
368 } else {
369 // no previously existing edge link
370 insertNewUiLink(currentElinkId, currentElink);
371 uiHost.setEdgeLinkId(currentElinkId);
372
373 }
374
Simon Huntc0f20c12016-05-09 09:30:20 -0700375 HostLocation hloc = h.location();
376 uiHost.setLocation(hloc.deviceId(), hloc.port());
Simon Huntc0f20c12016-05-09 09:30:20 -0700377 }
378
379 private void loadHosts() {
380 for (Host h : services.host().getHosts()) {
381 UiHost host = addNewHost(h);
382 updateHost(host, h);
383 }
384 }
385
386 // invoked from UiSharedTopologyModel host listener
Simon Hunt23fb1352016-04-11 12:15:19 -0700387 void addOrUpdateHost(Host host) {
Simon Huntc0f20c12016-05-09 09:30:20 -0700388 HostId id = host.id();
389 UiHost uiHost = uiTopology.findHost(id);
390 if (uiHost == null) {
391 uiHost = addNewHost(host);
392 }
393 updateHost(uiHost, host);
394
395 postEvent(HOST_ADDED_OR_UPDATED, uiHost);
Simon Hunt23fb1352016-04-11 12:15:19 -0700396 }
397
Simon Huntc0f20c12016-05-09 09:30:20 -0700398 // invoked from UiSharedTopologyModel host listener
Simon Hunt23fb1352016-04-11 12:15:19 -0700399 void moveHost(Host host, Host prevHost) {
Simon Huntc0f20c12016-05-09 09:30:20 -0700400 UiHost uiHost = uiTopology.findHost(prevHost.id());
Simon Hunt58a0dd02016-05-17 11:54:23 -0700401 if (uiHost != null) {
402 updateHost(uiHost, host);
403 postEvent(HOST_MOVED, uiHost);
404 } else {
405 log.warn(E_NO_ELEMENT, "host", prevHost.id());
406 }
407 }
Simon Huntc0f20c12016-05-09 09:30:20 -0700408
Simon Hunt58a0dd02016-05-17 11:54:23 -0700409 // package private for unit test access
410 UiHost accessHost(HostId id) {
411 return uiTopology.findHost(id);
Simon Hunt23fb1352016-04-11 12:15:19 -0700412 }
413
Simon Huntc0f20c12016-05-09 09:30:20 -0700414 // invoked from UiSharedTopologyModel host listener
Simon Hunt23fb1352016-04-11 12:15:19 -0700415 void removeHost(Host host) {
Simon Huntc0f20c12016-05-09 09:30:20 -0700416 HostId id = host.id();
417 UiHost uiHost = uiTopology.findHost(id);
418 if (uiHost != null) {
Simon Hunt58a0dd02016-05-17 11:54:23 -0700419 UiLink edgeLink = uiTopology.findLink(uiHost.edgeLinkId());
420 uiTopology.remove(edgeLink);
Simon Huntc0f20c12016-05-09 09:30:20 -0700421 uiTopology.remove(uiHost);
Simon Huntc0f20c12016-05-09 09:30:20 -0700422 postEvent(HOST_REMOVED, uiHost);
423 } else {
424 log.warn(E_NO_ELEMENT, "host", id);
425 }
Simon Hunt23fb1352016-04-11 12:15:19 -0700426 }
Simon Hunt338a3b42016-04-14 09:43:52 -0700427
Simon Huntc0f20c12016-05-09 09:30:20 -0700428
429 // === CACHE STATISTICS
430
Simon Hunt338a3b42016-04-14 09:43:52 -0700431 /**
Simon Hunt58a0dd02016-05-17 11:54:23 -0700432 * Returns a detailed (multi-line) string showing the contents of the cache.
433 *
434 * @return detailed string
435 */
436 public String dumpString() {
437 return uiTopology.dumpString();
438 }
439
440 /**
Simon Hunt338a3b42016-04-14 09:43:52 -0700441 * Returns the number of members in the cluster.
442 *
443 * @return number of cluster members
444 */
445 public int clusterMemberCount() {
446 return uiTopology.clusterMemberCount();
447 }
448
449 /**
Simon Huntc0f20c12016-05-09 09:30:20 -0700450 * Returns the number of regions in the topology.
Simon Hunt338a3b42016-04-14 09:43:52 -0700451 *
452 * @return number of regions
453 */
454 public int regionCount() {
455 return uiTopology.regionCount();
456 }
Simon Hunt58a0dd02016-05-17 11:54:23 -0700457
458 /**
459 * Returns the number of devices in the topology.
460 *
461 * @return number of devices
462 */
463 public int deviceCount() {
464 return uiTopology.deviceCount();
465 }
466
467 /**
468 * Returns the number of links in the topology.
469 *
470 * @return number of links
471 */
472 public int linkCount() {
473 return uiTopology.linkCount();
474 }
475
476 /**
477 * Returns the number of hosts in the topology.
478 *
479 * @return number of hosts
480 */
481 public int hostCount() {
482 return uiTopology.hostCount();
483 }
Simon Huntcda9c032016-04-11 10:32:54 -0700484}