blob: a9981e76c9c4a757dd3bfc9207cb60cb6f5b8f02 [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 Huntc0f20c12016-05-09 09:30:20 -0700200 // invoked from UiSharedTopologyModel region listener
Simon Hunt338a3b42016-04-14 09:43:52 -0700201 void removeRegion(Region region) {
Simon Huntc0f20c12016-05-09 09:30:20 -0700202 RegionId id = region.id();
203 UiRegion uiRegion = uiTopology.findRegion(id);
204 if (uiRegion != null) {
205 uiTopology.remove(uiRegion);
206 postEvent(REGION_REMOVED, uiRegion);
207 } else {
208 log.warn(E_NO_ELEMENT, "region", id);
209 }
Simon Hunt338a3b42016-04-14 09:43:52 -0700210 }
211
Simon Huntc0f20c12016-05-09 09:30:20 -0700212
213 // === DEVICES
214
215 private UiDevice addNewDevice(Device d) {
216 UiDevice device = new UiDevice(uiTopology, d);
217 uiTopology.add(device);
218 return device;
219 }
220
221 private void updateDevice(UiDevice device) {
222 device.setRegionId(services.region().getRegionForDevice(device.id()).id());
223 }
224
225 private void loadDevices() {
226 for (Device d : services.device().getDevices()) {
227 UiDevice device = addNewDevice(d);
228 updateDevice(device);
229 }
230 }
231
232 // invoked from UiSharedTopologyModel device listener
Simon Huntcda9c032016-04-11 10:32:54 -0700233 void addOrUpdateDevice(Device device) {
Simon Huntc0f20c12016-05-09 09:30:20 -0700234 DeviceId id = device.id();
235 UiDevice uiDevice = uiTopology.findDevice(id);
236 if (uiDevice == null) {
237 uiDevice = addNewDevice(device);
238 }
239 updateDevice(uiDevice);
Simon Huntcda9c032016-04-11 10:32:54 -0700240
Simon Huntc0f20c12016-05-09 09:30:20 -0700241 postEvent(DEVICE_ADDED_OR_UPDATED, uiDevice);
Simon Huntcda9c032016-04-11 10:32:54 -0700242 }
243
Simon Huntc0f20c12016-05-09 09:30:20 -0700244 // invoked from UiSharedTopologyModel device listener
Simon Huntcda9c032016-04-11 10:32:54 -0700245 void removeDevice(Device device) {
Simon Huntc0f20c12016-05-09 09:30:20 -0700246 DeviceId id = device.id();
247 UiDevice uiDevice = uiTopology.findDevice(id);
248 if (uiDevice != null) {
249 uiTopology.remove(uiDevice);
250 postEvent(DEVICE_REMOVED, uiDevice);
251 } else {
252 log.warn(E_NO_ELEMENT, "device", id);
253 }
Simon Huntcda9c032016-04-11 10:32:54 -0700254 }
255
Simon Huntc0f20c12016-05-09 09:30:20 -0700256
257 // === LINKS
258
259 private UiLink addNewLink(UiLinkId id) {
260 UiLink uiLink = new UiLink(uiTopology, id);
261 uiTopology.add(uiLink);
262 return uiLink;
263 }
264
265 private void updateLink(UiLink uiLink, Link link) {
266 uiLink.attachBackingLink(link);
267 }
268
269 private void loadLinks() {
270 for (Link link : services.link().getLinks()) {
271 UiLinkId id = uiLinkId(link);
272
273 UiLink uiLink = uiTopology.findLink(id);
274 if (uiLink == null) {
275 uiLink = addNewLink(id);
276 }
277 updateLink(uiLink, link);
278 }
279 }
280
281 // invoked from UiSharedTopologyModel link listener
Simon Hunt23fb1352016-04-11 12:15:19 -0700282 void addOrUpdateLink(Link link) {
Simon Huntc0f20c12016-05-09 09:30:20 -0700283 UiLinkId id = uiLinkId(link);
284 UiLink uiLink = uiTopology.findLink(id);
285 if (uiLink == null) {
286 uiLink = addNewLink(id);
287 }
288 updateLink(uiLink, link);
289
290 postEvent(LINK_ADDED_OR_UPDATED, uiLink);
Simon Hunt23fb1352016-04-11 12:15:19 -0700291 }
292
Simon Huntc0f20c12016-05-09 09:30:20 -0700293 // invoked from UiSharedTopologyModel link listener
Simon Hunt23fb1352016-04-11 12:15:19 -0700294 void removeLink(Link link) {
Simon Huntc0f20c12016-05-09 09:30:20 -0700295 UiLinkId id = uiLinkId(link);
296 UiLink uiLink = uiTopology.findLink(id);
297 if (uiLink != null) {
298 boolean remaining = uiLink.detachBackingLink(link);
299 if (remaining) {
300 postEvent(LINK_ADDED_OR_UPDATED, uiLink);
301 } else {
302 uiTopology.remove(uiLink);
303 postEvent(LINK_REMOVED, uiLink);
304 }
305 } else {
306 log.warn(E_NO_ELEMENT, "link", id);
307 }
Simon Hunt23fb1352016-04-11 12:15:19 -0700308 }
309
Simon Huntc0f20c12016-05-09 09:30:20 -0700310
311 // === HOSTS
312
313 private UiHost addNewHost(Host h) {
314 UiHost host = new UiHost(uiTopology, h);
315 uiTopology.add(host);
316
317 UiLink edgeLink = addNewEdgeLink(host);
318 host.setEdgeLinkId(edgeLink.id());
319
320 return host;
321 }
322
323 private void removeOldEdgeLink(UiHost uiHost) {
324 UiLink old = uiTopology.findLink(uiHost.edgeLinkId());
325 if (old != null) {
326 uiTopology.remove(old);
327 }
328 }
329
330 private UiLink addNewEdgeLink(UiHost uiHost) {
331 EdgeLink elink = createEdgeLink(uiHost.backingHost(), true);
332 UiLinkId elinkId = UiLinkId.uiLinkId(elink);
333 UiLink uiLink = addNewLink(elinkId);
334 uiLink.attachEdgeLink(elink);
335 return uiLink;
336 }
337
338 private void updateHost(UiHost uiHost, Host h) {
339 removeOldEdgeLink(uiHost);
340 HostLocation hloc = h.location();
341 uiHost.setLocation(hloc.deviceId(), hloc.port());
342 addNewEdgeLink(uiHost);
343 }
344
345 private void loadHosts() {
346 for (Host h : services.host().getHosts()) {
347 UiHost host = addNewHost(h);
348 updateHost(host, h);
349 }
350 }
351
352 // invoked from UiSharedTopologyModel host listener
Simon Hunt23fb1352016-04-11 12:15:19 -0700353 void addOrUpdateHost(Host host) {
Simon Huntc0f20c12016-05-09 09:30:20 -0700354 HostId id = host.id();
355 UiHost uiHost = uiTopology.findHost(id);
356 if (uiHost == null) {
357 uiHost = addNewHost(host);
358 }
359 updateHost(uiHost, host);
360
361 postEvent(HOST_ADDED_OR_UPDATED, uiHost);
Simon Hunt23fb1352016-04-11 12:15:19 -0700362 }
363
Simon Huntc0f20c12016-05-09 09:30:20 -0700364 // invoked from UiSharedTopologyModel host listener
Simon Hunt23fb1352016-04-11 12:15:19 -0700365 void moveHost(Host host, Host prevHost) {
Simon Huntc0f20c12016-05-09 09:30:20 -0700366 UiHost uiHost = uiTopology.findHost(prevHost.id());
367 updateHost(uiHost, host);
368
369 postEvent(HOST_MOVED, uiHost);
Simon Hunt23fb1352016-04-11 12:15:19 -0700370 }
371
Simon Huntc0f20c12016-05-09 09:30:20 -0700372 // invoked from UiSharedTopologyModel host listener
Simon Hunt23fb1352016-04-11 12:15:19 -0700373 void removeHost(Host host) {
Simon Huntc0f20c12016-05-09 09:30:20 -0700374 HostId id = host.id();
375 UiHost uiHost = uiTopology.findHost(id);
376 if (uiHost != null) {
377 uiTopology.remove(uiHost);
378 removeOldEdgeLink(uiHost);
379 postEvent(HOST_REMOVED, uiHost);
380 } else {
381 log.warn(E_NO_ELEMENT, "host", id);
382 }
Simon Hunt23fb1352016-04-11 12:15:19 -0700383 }
Simon Hunt338a3b42016-04-14 09:43:52 -0700384
Simon Huntc0f20c12016-05-09 09:30:20 -0700385
386 // === CACHE STATISTICS
387
Simon Hunt338a3b42016-04-14 09:43:52 -0700388 /**
389 * Returns the number of members in the cluster.
390 *
391 * @return number of cluster members
392 */
393 public int clusterMemberCount() {
394 return uiTopology.clusterMemberCount();
395 }
396
397 /**
Simon Huntc0f20c12016-05-09 09:30:20 -0700398 * Returns the number of regions in the topology.
Simon Hunt338a3b42016-04-14 09:43:52 -0700399 *
400 * @return number of regions
401 */
402 public int regionCount() {
403 return uiTopology.regionCount();
404 }
Simon Huntcda9c032016-04-11 10:32:54 -0700405}