blob: ada4d155f076b0ed0418e59126dc2c774db9f5b9 [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 Hunt58a0dd02016-05-17 11:54:23 -070019import com.google.common.collect.ImmutableSet;
Simon Huntc0f20c12016-05-09 09:30:20 -070020import org.onosproject.net.DeviceId;
21import org.onosproject.net.HostId;
Simon Hunt23fb1352016-04-11 12:15:19 -070022import org.onosproject.net.region.Region;
Simon Hunt642bc452016-05-04 19:34:45 -070023import org.onosproject.net.region.RegionId;
Simon Hunt23fb1352016-04-11 12:15:19 -070024
Simon Huntd5b96732016-07-08 13:22:27 -070025import java.util.ArrayList;
26import java.util.Collections;
Simon Huntc0f20c12016-05-09 09:30:20 -070027import java.util.HashSet;
Simon Huntd5b96732016-07-08 13:22:27 -070028import java.util.List;
Simon Hunt23fb1352016-04-11 12:15:19 -070029import java.util.Set;
Simon Huntc0f20c12016-05-09 09:30:20 -070030
31import static com.google.common.base.MoreObjects.toStringHelper;
Simon Huntf836a872016-08-10 17:37:36 -070032import static com.google.common.base.Strings.isNullOrEmpty;
Thomas Vachuska8c0b18a2017-04-14 16:27:33 -070033import static org.onosproject.net.DeviceId.deviceId;
Simon Huntb1ce2602016-07-23 14:04:31 -070034import static org.onosproject.net.region.RegionId.regionId;
Simon Hunt23fb1352016-04-11 12:15:19 -070035
Simon Hunt5f6dbf82016-03-30 08:53:33 -070036/**
37 * Represents a region.
38 */
39public class UiRegion extends UiNode {
Simon Hunt23fb1352016-04-11 12:15:19 -070040
Simon Huntf836a872016-08-10 17:37:36 -070041 private static final String NULL_NAME = "(root)";
42 private static final String NO_NAME = "???";
Simon Huntb1ce2602016-07-23 14:04:31 -070043
44 /**
45 * The identifier for the null-region. That is, a container for devices,
46 * hosts, and links for those that belong to no region.
47 */
48 public static final RegionId NULL_ID = regionId(NULL_NAME);
49
50 private static final String[] DEFAULT_LAYER_TAGS = {
51 UiNode.LAYER_OPTICAL,
52 UiNode.LAYER_PACKET,
53 UiNode.LAYER_DEFAULT
54 };
55
Simon Huntc0f20c12016-05-09 09:30:20 -070056 // loose bindings to things in this region
57 private final Set<DeviceId> deviceIds = new HashSet<>();
58 private final Set<HostId> hostIds = new HashSet<>();
Simon Hunt23fb1352016-04-11 12:15:19 -070059
Simon Huntd5b96732016-07-08 13:22:27 -070060 private final List<String> layerOrder = new ArrayList<>();
61
Simon Huntc0f20c12016-05-09 09:30:20 -070062 private final UiTopology topology;
Simon Hunt23fb1352016-04-11 12:15:19 -070063
Thomas Vachuskab877a6f2017-04-14 11:43:30 -070064 private final RegionId regionId;
Simon Huntc0f20c12016-05-09 09:30:20 -070065
Simon Hunt4f4ffc32016-08-03 18:30:47 -070066 // keep track of hierarchy (inferred from UiTopoLayoutService)
67 private RegionId parent;
68 private final Set<RegionId> kids = new HashSet<>();
69
Simon Huntc0f20c12016-05-09 09:30:20 -070070 /**
71 * Constructs a UI region, with a reference to the specified backing region.
72 *
73 * @param topology parent topology
74 * @param region backing region
75 */
76 public UiRegion(UiTopology topology, Region region) {
Simon Huntb1ce2602016-07-23 14:04:31 -070077 // Implementation Note: if region is null, this UiRegion is being used
78 // as a container for devices, hosts, links that belong to no region.
Simon Huntc0f20c12016-05-09 09:30:20 -070079 this.topology = topology;
Thomas Vachuskab877a6f2017-04-14 11:43:30 -070080 this.regionId = region == null ? NULL_ID : region.id();
Simon Huntb1ce2602016-07-23 14:04:31 -070081
82 setLayerOrder(DEFAULT_LAYER_TAGS);
Simon Huntc0f20c12016-05-09 09:30:20 -070083 }
Simon Hunt23fb1352016-04-11 12:15:19 -070084
85 @Override
86 protected void destroy() {
Simon Huntc0f20c12016-05-09 09:30:20 -070087 deviceIds.clear();
88 hostIds.clear();
Simon Hunt23fb1352016-04-11 12:15:19 -070089 }
90
Simon Hunt642bc452016-05-04 19:34:45 -070091 /**
Simon Huntd5b96732016-07-08 13:22:27 -070092 * Sets the layer order for this region.
93 * Typically, the {@code UiNode.LAYER_*} constants will be used here.
94 *
95 * @param layers the layers
96 */
97 public void setLayerOrder(String... layers) {
98 layerOrder.clear();
99 Collections.addAll(layerOrder, layers);
100 }
101
102 /**
Simon Hunt642bc452016-05-04 19:34:45 -0700103 * Returns the identity of the region.
104 *
105 * @return region ID
106 */
107 public RegionId id() {
Thomas Vachuskab877a6f2017-04-14 11:43:30 -0700108 return regionId;
Simon Hunt642bc452016-05-04 19:34:45 -0700109 }
110
Simon Hunt4f4ffc32016-08-03 18:30:47 -0700111 /**
112 * Returns the identity of the parent region.
113 *
114 * @return parent region ID
115 */
116 public RegionId parent() {
117 return parent;
118 }
119
120 /**
121 * Returns true if this is the root (default) region.
122 *
123 * @return true if root region
124 */
125 public boolean isRoot() {
126 return id().equals(parent);
127 }
128
129 /**
130 * Returns the identities of the child regions.
131 *
132 * @return child region IDs
133 */
134 public Set<RegionId> children() {
135 return ImmutableSet.copyOf(kids);
136 }
137
138 /**
Simon Huntc13082f2016-08-03 21:20:23 -0700139 * Returns the UI region that is the parent of this region.
140 *
141 * @return the parent region
142 */
143 public UiRegion parentRegion() {
144 return topology.findRegion(parent);
145 }
146
147 /**
Simon Hunt4f4ffc32016-08-03 18:30:47 -0700148 * Sets the parent ID for this region.
149 *
150 * @param parentId parent ID
151 */
152 public void setParent(RegionId parentId) {
153 parent = parentId;
154 }
155
156 /**
157 * Sets the children IDs for this region.
158 *
159 * @param children children IDs
160 */
161 public void setChildren(Set<RegionId> children) {
162 kids.clear();
163 kids.addAll(children);
164 }
165
Simon Hunt642bc452016-05-04 19:34:45 -0700166 @Override
167 public String idAsString() {
168 return id().toString();
169 }
Simon Huntc0f20c12016-05-09 09:30:20 -0700170
171 @Override
172 public String name() {
Thomas Vachuskab877a6f2017-04-14 11:43:30 -0700173 Region region = backingRegion();
Simon Huntb1ce2602016-07-23 14:04:31 -0700174 return region == null ? NULL_NAME : region.name();
Simon Huntc0f20c12016-05-09 09:30:20 -0700175 }
176
177 /**
Simon Huntb1ce2602016-07-23 14:04:31 -0700178 * Returns the region instance backing this UI region. If this instance
179 * represents the "null-region", the value returned will be null.
Simon Huntc0f20c12016-05-09 09:30:20 -0700180 *
181 * @return the backing region instance
182 */
183 public Region backingRegion() {
Thomas Vachuskab877a6f2017-04-14 11:43:30 -0700184 return topology.services.region().getRegion(regionId);
Simon Huntc0f20c12016-05-09 09:30:20 -0700185 }
186
187 /**
188 * Make sure we have only these devices in the region.
189 *
190 * @param devices devices in the region
191 */
192 public void reconcileDevices(Set<DeviceId> devices) {
193 deviceIds.clear();
194 deviceIds.addAll(devices);
195 }
196
197 @Override
198 public String toString() {
199 return toStringHelper(this)
200 .add("id", id())
201 .add("name", name())
Simon Hunt4f4ffc32016-08-03 18:30:47 -0700202 .add("parent", parent)
203 .add("kids", kids)
Simon Huntc0f20c12016-05-09 09:30:20 -0700204 .add("devices", deviceIds)
205 .add("#hosts", hostIds.size())
Simon Huntc0f20c12016-05-09 09:30:20 -0700206 .toString();
207 }
208
209 /**
210 * Returns the region's type.
211 *
212 * @return region type
213 */
214 public Region.Type type() {
Thomas Vachuskab877a6f2017-04-14 11:43:30 -0700215 Region region = backingRegion();
Simon Huntb1ce2602016-07-23 14:04:31 -0700216 return region == null ? null : region.type();
217 }
218
219
220 /**
221 * Returns the count of devices in this region.
222 *
223 * @return the device count
224 */
225 public int deviceCount() {
226 return deviceIds.size();
Simon Huntc0f20c12016-05-09 09:30:20 -0700227 }
228
229 /**
Simon Hunt58a0dd02016-05-17 11:54:23 -0700230 * Returns the set of device identifiers for this region.
231 *
232 * @return device identifiers for this region
233 */
234 public Set<DeviceId> deviceIds() {
235 return ImmutableSet.copyOf(deviceIds);
236 }
237
238 /**
Simon Huntc0f20c12016-05-09 09:30:20 -0700239 * Returns the devices in this region.
240 *
241 * @return the devices in this region
242 */
243 public Set<UiDevice> devices() {
244 return topology.deviceSet(deviceIds);
245 }
246
Steven Burrows19e6e4f2016-10-05 13:27:07 -0500247
248 /**
249 * Make sure we have only these hosts in the region.
250 *
251 * @param hosts hosts in the region
252 */
253 public void reconcileHosts(Set<HostId> hosts) {
254 hostIds.clear();
255 hostIds.addAll(hosts);
256 }
257
Simon Huntc0f20c12016-05-09 09:30:20 -0700258 /**
Simon Hunt58a0dd02016-05-17 11:54:23 -0700259 * Returns the set of host identifiers for this region.
260 *
261 * @return host identifiers for this region
262 */
263 public Set<HostId> hostIds() {
264 return ImmutableSet.copyOf(hostIds);
265 }
266
267 /**
Simon Huntc0f20c12016-05-09 09:30:20 -0700268 * Returns the hosts in this region.
269 *
270 * @return the hosts in this region
271 */
272 public Set<UiHost> hosts() {
273 return topology.hostSet(hostIds);
274 }
275
276 /**
Steven Burrows19e6e4f2016-10-05 13:27:07 -0500277 * Returns the count of devices in this region.
278 *
279 * @return the device count
280 */
281 public int hostCount() {
282 return hostIds.size();
283 }
284
285 /**
Simon Huntd5b96732016-07-08 13:22:27 -0700286 * Returns the order in which layers should be rendered. Lower layers
287 * come earlier in the list. For example, to indicate that nodes in the
288 * optical layer should be rendered "below" nodes in the packet layer,
289 * this method should return:
290 * <pre>
Simon Huntb1ce2602016-07-23 14:04:31 -0700291 * [UiNode.LAYER_OPTICAL, UiNode.LAYER_PACKET, UiNode.LAYER_DEFAULT]
Simon Huntd5b96732016-07-08 13:22:27 -0700292 * </pre>
293 *
294 * @return layer ordering
295 */
296 public List<String> layerOrder() {
297 return Collections.unmodifiableList(layerOrder);
298 }
Simon Huntf836a872016-08-10 17:37:36 -0700299
300 /**
301 * Guarantees to return a string for the name of the specified region.
302 * If region is null, we return the null region name, else we return
303 * the name as configured on the region.
304 *
305 * @param region the region whose name we require
306 * @return the region's name
307 */
308 public static String safeName(Region region) {
309 if (region == null) {
310 return NULL_NAME;
311 }
312 String name = region.name();
313 return isNullOrEmpty(name) ? NO_NAME : name;
314 }
Thomas Vachuska8c0b18a2017-04-14 16:27:33 -0700315
316 /**
317 * Determins whether the specified event is relevant to the view
318 * constrained to this region.
319 *
320 * @param event UI model event
321 * @return true if relevant
322 */
323 public boolean isRelevant(UiModelEvent event) {
324 switch (event.type()) {
325 case CLUSTER_MEMBER_ADDED_OR_UPDATED:
326 case CLUSTER_MEMBER_REMOVED:
327 return true;
328
329 case REGION_ADDED_OR_UPDATED:
330 case REGION_REMOVED:
331 return isRegionRelevant(((UiRegion) event.subject()).id());
332
333 case DEVICE_ADDED_OR_UPDATED:
334 case DEVICE_REMOVED:
335 return isDeviceRelevant(((UiDevice) event.subject()).id());
336
337 case LINK_ADDED_OR_UPDATED:
338 case LINK_REMOVED:
339 return isLinkRelevant((UiLink) event.subject());
340
341 case HOST_ADDED_OR_UPDATED:
342 case HOST_MOVED:
343 case HOST_REMOVED:
344 return isDeviceRelevant(((UiHost) event.subject()).locationDevice());
345
346 default:
347 return true;
348 }
349 }
350
351 private boolean isDeviceRelevant(DeviceId deviceId) {
352 return deviceIds.contains(deviceId);
353 }
354
355 private boolean isLinkRelevant(UiLink uiLink) {
356 if (uiLink instanceof UiDeviceLink) {
357 UiDeviceLink uiDeviceLink = (UiDeviceLink) uiLink;
358 return isDeviceRelevant(uiDeviceLink.deviceA()) ||
359 isDeviceRelevant(uiDeviceLink.deviceB());
360
361 } else if (uiLink instanceof UiRegionLink) {
362 UiRegionLink uiRegionLink = (UiRegionLink) uiLink;
363 return isRegionRelevant(uiRegionLink.regionA()) ||
364 isRegionRelevant(uiRegionLink.regionB());
365
366 } else if (uiLink instanceof UiRegionDeviceLink) {
367 UiRegionDeviceLink uiRegionDeviceLink = (UiRegionDeviceLink) uiLink;
368 return isRegionRelevant(uiRegionDeviceLink.region()) ||
369 isDeviceRelevant(uiRegionDeviceLink.device());
370
371 } else if (uiLink instanceof UiEdgeLink) {
372 UiEdgeLink uiEdgeLink = (UiEdgeLink) uiLink;
373 return isDeviceRelevant(uiEdgeLink.deviceId());
374 }
375 return false;
376 }
377
378 private boolean isRegionRelevant(RegionId regionId) {
379 return kids.contains(regionId);
380 }
Simon Hunt5f6dbf82016-03-30 08:53:33 -0700381}