blob: a644ba3a159e694359aed3295d5d8c5f1ea25d28 [file] [log] [blame]
Simon Huntc0f20c12016-05-09 09:30:20 -07001/*
2 * Copyright 2016-present 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.model.topo;
18
Simon Hunt0e161092017-05-08 17:41:38 -070019import org.onlab.util.Identifier;
Simon Huntc0f20c12016-05-09 09:30:20 -070020import org.onosproject.net.ConnectPoint;
Simon Huntc13082f2016-08-03 21:20:23 -070021import org.onosproject.net.DeviceId;
Simon Huntc0f20c12016-05-09 09:30:20 -070022import org.onosproject.net.ElementId;
Simon Huntb7fd0802016-10-27 12:21:40 -070023import org.onosproject.net.HostId;
Simon Huntc0f20c12016-05-09 09:30:20 -070024import org.onosproject.net.Link;
Simon Hunt0e161092017-05-08 17:41:38 -070025import org.onosproject.net.LinkKey;
Simon Hunt58a0dd02016-05-17 11:54:23 -070026import org.onosproject.net.PortNumber;
Simon Huntc13082f2016-08-03 21:20:23 -070027import org.onosproject.net.region.RegionId;
28
29import java.util.Comparator;
30
31import static com.google.common.base.Preconditions.checkArgument;
32import static com.google.common.base.Preconditions.checkNotNull;
Simon Huntc0f20c12016-05-09 09:30:20 -070033
34/**
35 * A canonical representation of an identifier for {@link UiLink}s.
36 */
37public final class UiLinkId {
38
Simon Huntc13082f2016-08-03 21:20:23 -070039 private static final String E_PORT_NULL = "Port number cannot be null";
40 private static final String E_DEVICE_ID_NULL = "Device ID cannot be null";
Simon Huntbf59db22017-05-12 13:26:35 -070041 private static final String E_HOST_ID_NULL = "Host ID cannot be null";
Simon Huntc13082f2016-08-03 21:20:23 -070042 private static final String E_REGION_ID_NULL = "Region ID cannot be null";
43 private static final String E_IDENTICAL = "Region IDs cannot be same";
44
45 private static final Comparator<RegionId> REGION_ID_COMPARATOR =
Simon Hunt0e161092017-05-08 17:41:38 -070046 Comparator.comparing(Identifier::toString);
Simon Huntbf59db22017-05-12 13:26:35 -070047 private static final Comparator<DeviceId> DEVICE_ID_COMPARATOR =
48 Comparator.comparing(DeviceId::toString);
49
Simon Huntc13082f2016-08-03 21:20:23 -070050
Simon Huntc0f20c12016-05-09 09:30:20 -070051 /**
52 * Designates the directionality of an underlying (uni-directional) link.
53 */
54 public enum Direction {
55 A_TO_B,
56 B_TO_A
57 }
58
Simon Huntbf59db22017-05-12 13:26:35 -070059 /**
60 * Designates the type of link the identifier represents.
61 */
62 public enum Type {
63 REGION_REGION,
64 REGION_DEVICE,
65 DEVICE_DEVICE,
66 HOST_DEVICE
67 }
68
Simon Huntb7fd0802016-10-27 12:21:40 -070069 static final String CP_DELIMITER = "~";
Simon Huntc13082f2016-08-03 21:20:23 -070070 static final String ID_PORT_DELIMITER = "/";
Simon Huntc0f20c12016-05-09 09:30:20 -070071
Simon Huntc13082f2016-08-03 21:20:23 -070072 private final RegionId regionA;
73 private final ElementId elementA;
Simon Hunt58a0dd02016-05-17 11:54:23 -070074 private final PortNumber portA;
Simon Huntc13082f2016-08-03 21:20:23 -070075
76 private final RegionId regionB;
77 private final ElementId elementB;
Simon Hunt58a0dd02016-05-17 11:54:23 -070078 private final PortNumber portB;
79
Simon Huntc0f20c12016-05-09 09:30:20 -070080 private final String idStr;
Simon Huntb7fd0802016-10-27 12:21:40 -070081 private final String idA;
82 private final String idB;
Simon Huntc0f20c12016-05-09 09:30:20 -070083
Simon Huntbf59db22017-05-12 13:26:35 -070084 private final Type type;
85
Simon Huntc0f20c12016-05-09 09:30:20 -070086 /**
87 * Creates a UI link identifier. It is expected that A comes before B when
88 * the two identifiers are naturally sorted, thus providing a representation
89 * which is invariant to whether A or B is source or destination of the
90 * underlying link.
91 *
Simon Huntc13082f2016-08-03 21:20:23 -070092 * @param a first element ID
Simon Hunt58a0dd02016-05-17 11:54:23 -070093 * @param pa first element port
Simon Huntc13082f2016-08-03 21:20:23 -070094 * @param b second element ID
Simon Hunt58a0dd02016-05-17 11:54:23 -070095 * @param pb second element port
Simon Huntc0f20c12016-05-09 09:30:20 -070096 */
Simon Hunt58a0dd02016-05-17 11:54:23 -070097 private UiLinkId(ElementId a, PortNumber pa, ElementId b, PortNumber pb) {
Simon Huntc13082f2016-08-03 21:20:23 -070098 elementA = a;
Simon Hunt58a0dd02016-05-17 11:54:23 -070099 portA = pa;
Simon Huntc13082f2016-08-03 21:20:23 -0700100 elementB = b;
Simon Hunt58a0dd02016-05-17 11:54:23 -0700101 portB = pb;
Simon Huntc0f20c12016-05-09 09:30:20 -0700102
Simon Huntc13082f2016-08-03 21:20:23 -0700103 regionA = null;
104 regionB = null;
105
Simon Huntbf59db22017-05-12 13:26:35 -0700106 boolean isEdgeLink = (a instanceof HostId);
107
Simon Huntb7fd0802016-10-27 12:21:40 -0700108 // NOTE: for edgelinks, hosts are always element A
Simon Huntbf59db22017-05-12 13:26:35 -0700109 idA = isEdgeLink ? a.toString() : a + ID_PORT_DELIMITER + pa;
Simon Huntb7fd0802016-10-27 12:21:40 -0700110 idB = b + ID_PORT_DELIMITER + pb;
111 idStr = idA + CP_DELIMITER + idB;
Simon Huntbf59db22017-05-12 13:26:35 -0700112
113 type = isEdgeLink ? Type.HOST_DEVICE : Type.DEVICE_DEVICE;
Simon Huntc0f20c12016-05-09 09:30:20 -0700114 }
115
Simon Huntc13082f2016-08-03 21:20:23 -0700116 /**
117 * Creates a UI link identifier. It is expected that A comes before B when
118 * the two identifiers are naturally sorted.
119 *
120 * @param a first region ID
121 * @param b second region ID
122 */
123 private UiLinkId(RegionId a, RegionId b) {
124 regionA = a;
125 regionB = b;
126
127 elementA = null;
128 elementB = null;
129 portA = null;
130 portB = null;
131
Simon Huntb7fd0802016-10-27 12:21:40 -0700132 idA = a.toString();
133 idB = b.toString();
134 idStr = idA + CP_DELIMITER + idB;
Simon Huntbf59db22017-05-12 13:26:35 -0700135
136 type = Type.REGION_REGION;
Simon Huntc13082f2016-08-03 21:20:23 -0700137 }
138
139 /**
140 * Creates a UI link identifier, with region at one end and a device/port
141 * at the other.
142 *
143 * @param r region ID
144 * @param d device ID
145 * @param p port number
146 */
147 private UiLinkId(RegionId r, DeviceId d, PortNumber p) {
148 regionA = r;
149 elementB = d;
150 portB = p;
151
152 regionB = null;
153 elementA = null;
154 portA = null;
155
Simon Huntb7fd0802016-10-27 12:21:40 -0700156 idA = r.toString();
157 idB = elementB + ID_PORT_DELIMITER + portB;
158 idStr = idA + CP_DELIMITER + idB;
Simon Huntbf59db22017-05-12 13:26:35 -0700159
160 type = Type.REGION_DEVICE;
Simon Huntc13082f2016-08-03 21:20:23 -0700161 }
162
Simon Huntc0f20c12016-05-09 09:30:20 -0700163 @Override
164 public String toString() {
165 return idStr;
166 }
167
168 /**
Simon Huntb7fd0802016-10-27 12:21:40 -0700169 * String representation of endpoint A.
170 *
171 * @return string rep of endpoint A
172 */
173 public String idA() {
174 return idA;
175 }
176
177 /**
178 * String representation of endpoint B.
179 *
180 * @return string rep of endpoint B
181 */
182 public String idB() {
183 return idB;
184 }
185
186 /**
Simon Huntc13082f2016-08-03 21:20:23 -0700187 * Returns the identifier of the first element. Note that the returned
188 * value will be null if this identifier is for a region-region link.
Simon Huntc0f20c12016-05-09 09:30:20 -0700189 *
190 * @return first element identity
191 */
192 public ElementId elementA() {
Simon Huntc13082f2016-08-03 21:20:23 -0700193 return elementA;
Simon Huntc0f20c12016-05-09 09:30:20 -0700194 }
195
196 /**
Simon Huntc13082f2016-08-03 21:20:23 -0700197 * Returns the port of the first element. Note that the returned
198 * value will be null if this identifier is for a region-region link.
Simon Hunt58a0dd02016-05-17 11:54:23 -0700199 *
200 * @return first element port
201 */
202 public PortNumber portA() {
203 return portA;
204 }
205
206 /**
Simon Huntc13082f2016-08-03 21:20:23 -0700207 * Returns the identifier of the second element. Note that the returned
208 * value will be null if this identifier is for a region-region link.
Simon Huntc0f20c12016-05-09 09:30:20 -0700209 *
210 * @return second element identity
211 */
212 public ElementId elementB() {
Simon Huntc13082f2016-08-03 21:20:23 -0700213 return elementB;
Simon Huntc0f20c12016-05-09 09:30:20 -0700214 }
215
Simon Hunt58a0dd02016-05-17 11:54:23 -0700216 /**
Simon Huntc13082f2016-08-03 21:20:23 -0700217 * Returns the port of the second element. Note that the returned
218 * value will be null if this identifier is for a region-region link.
Simon Hunt58a0dd02016-05-17 11:54:23 -0700219 *
220 * @return second element port
221 */
222 public PortNumber portB() {
223 return portB;
224 }
225
Simon Huntc13082f2016-08-03 21:20:23 -0700226 /**
227 * Returns the identity of the first region. Note that the returned value
228 * will be null if this identifier is for a device-device or device-host
229 * link.
230 *
231 * @return first region ID
232 */
233 public RegionId regionA() {
234 return regionA;
235 }
236
237 /**
238 * Returns the identity of the second region. Note that the returned value
239 * will be null if this identifier is for a device-device or device-host
240 * link.
241 *
242 * @return second region ID
243 */
244 public RegionId regionB() {
245 return regionB;
246 }
247
Simon Huntbf59db22017-05-12 13:26:35 -0700248 /**
249 * Returns the type of link this identifier represents.
250 *
251 * @return the link identifier type
252 */
253 public Type type() {
254 return type;
255 }
256
257 /**
258 * Returns true if this identifier represents a region-region link.
259 *
260 * @return true if region-region link identifier; false otherwise
261 */
262 public boolean isRegionRegion() {
263 return type == Type.REGION_REGION;
264 }
265
266 /**
267 * Returns true if this identifier represents a region-device link.
268 *
269 * @return true if region-device link identifier; false otherwise
270 */
271 public boolean isRegionDevice() {
272 return type == Type.REGION_DEVICE;
273 }
274
275 /**
276 * Returns true if this identifier represents a device-device
277 * (infrastructure) link.
278 *
279 * @return true if device-device link identifier; false otherwise
280 */
281 public boolean isDeviceDevice() {
282 return type == Type.DEVICE_DEVICE;
283 }
284
285 /**
286 * Returns true if this identifier represents a host-device (edge) link.
287 *
288 * @return true if host-device link identifier; false otherwise
289 */
290 public boolean isHostDevice() {
291 return type == Type.HOST_DEVICE;
292 }
293
Simon Huntc0f20c12016-05-09 09:30:20 -0700294 @Override
295 public boolean equals(Object o) {
296 if (this == o) {
297 return true;
298 }
299 if (o == null || getClass() != o.getClass()) {
300 return false;
301 }
302
303 UiLinkId uiLinkId = (UiLinkId) o;
304 return idStr.equals(uiLinkId.idStr);
305 }
306
307 @Override
308 public int hashCode() {
309 return idStr.hashCode();
310 }
311
312 /**
313 * Returns the direction of the given link, or null if this link ID does
314 * not correspond to the given link.
315 *
316 * @param link the link to examine
317 * @return corresponding direction
318 */
319 Direction directionOf(Link link) {
320 ConnectPoint src = link.src();
321 ElementId srcId = src.elementId();
Simon Huntc13082f2016-08-03 21:20:23 -0700322 return elementA.equals(srcId) ? Direction.A_TO_B
323 : elementB.equals(srcId) ? Direction.B_TO_A
Simon Huntc0f20c12016-05-09 09:30:20 -0700324 : null;
325 }
326
327 /**
328 * Generates the canonical link identifier for the given link.
329 *
330 * @param link link for which the identifier is required
331 * @return link identifier
Simon Hunt0e161092017-05-08 17:41:38 -0700332 * @throws NullPointerException if src or dst connect point is null
Simon Huntc0f20c12016-05-09 09:30:20 -0700333 */
334 public static UiLinkId uiLinkId(Link link) {
Simon Hunt0e161092017-05-08 17:41:38 -0700335 return canonicalizeIdentifier(link.src(), link.dst());
336 }
337
338 /**
339 * Creates the canonical link identifier from the given link key.
340 *
341 * @param lk link key
342 * @return equivalent link identifier
343 * @throws NullPointerException if src or dst connect point is null
344 */
345 public static UiLinkId uiLinkId(LinkKey lk) {
346 return canonicalizeIdentifier(lk.src(), lk.dst());
347 }
348
349 private static UiLinkId canonicalizeIdentifier(ConnectPoint src, ConnectPoint dst) {
Simon Huntc0f20c12016-05-09 09:30:20 -0700350 if (src == null || dst == null) {
Simon Huntb0582492016-09-20 18:26:38 -0700351 throw new NullPointerException(
Simon Hunt0e161092017-05-08 17:41:38 -0700352 "null src or dst connect point (illegal for UiLinkId)");
Simon Huntc0f20c12016-05-09 09:30:20 -0700353 }
Simon Huntc0f20c12016-05-09 09:30:20 -0700354 ElementId srcId = src.elementId();
355 ElementId dstId = dst.elementId();
Simon Huntc0f20c12016-05-09 09:30:20 -0700356
357 // canonicalize
358 int comp = srcId.toString().compareTo(dstId.toString());
Simon Hunt58a0dd02016-05-17 11:54:23 -0700359 return comp <= 0 ? new UiLinkId(srcId, src.port(), dstId, dst.port())
360 : new UiLinkId(dstId, dst.port(), srcId, src.port());
Simon Huntc0f20c12016-05-09 09:30:20 -0700361 }
Simon Huntc13082f2016-08-03 21:20:23 -0700362
363 /**
364 * Generates the canonical link identifier for a link between the
365 * specified region nodes.
366 *
367 * @param one the first region ID
368 * @param two the second region ID
369 * @return link identifier
370 * @throws NullPointerException if any of the required fields are null
371 * @throws IllegalArgumentException if the identifiers are identical
372 */
373 public static UiLinkId uiLinkId(RegionId one, RegionId two) {
374 checkNotNull(one, E_REGION_ID_NULL);
375 checkNotNull(two, E_REGION_ID_NULL);
376 checkArgument(!one.equals(two), E_IDENTICAL);
377
378 boolean flip = REGION_ID_COMPARATOR.compare(one, two) > 0;
379 return flip ? new UiLinkId(two, one) : new UiLinkId(one, two);
380 }
381
382 /**
383 * Generates the canonical link identifier for a link between the specified
384 * region and device/port.
385 *
386 * @param regionId region ID
387 * @param deviceId device ID
388 * @param portNumber port number
389 * @return link identifier
390 * @throws NullPointerException if any of the required fields are null
391 */
392 public static UiLinkId uiLinkId(RegionId regionId, DeviceId deviceId,
393 PortNumber portNumber) {
394 checkNotNull(regionId, E_REGION_ID_NULL);
395 checkNotNull(deviceId, E_DEVICE_ID_NULL);
396 checkNotNull(portNumber, E_PORT_NULL);
397
398 return new UiLinkId(regionId, deviceId, portNumber);
399 }
Simon Huntbf59db22017-05-12 13:26:35 -0700400
401 /**
402 * Generates an identifier for a link between two devices.
403 *
404 * @param a device A
405 * @param pa port A
406 * @param b device B
407 * @param pb port B
408 * @return link identifier
409 * @throws NullPointerException if any of the required fields are null
410 */
411 public static UiLinkId uiLinkId(DeviceId a, PortNumber pa,
412 DeviceId b, PortNumber pb) {
413 checkNotNull(a, E_DEVICE_ID_NULL + " (A)");
414 checkNotNull(b, E_DEVICE_ID_NULL + " (B)");
415 checkNotNull(pa, E_PORT_NULL + " (A)");
416 checkNotNull(pb, E_PORT_NULL + " (B)");
417
418 boolean flip = DEVICE_ID_COMPARATOR.compare(a, b) > 0;
419 return flip ? new UiLinkId(b, pb, a, pa) : new UiLinkId(a, pa, b, pb);
420 }
421
422 /**
423 * Generates an identifier for an edge link. Note that host is always
424 * element A.
425 *
426 * @param h host
427 * @param d device
428 * @param p port
429 * @return link identifier
430 * @throws NullPointerException if any of the required fields are null
431 */
432 public static UiLinkId uiLinkId(HostId h, DeviceId d, PortNumber p) {
433 checkNotNull(h, E_HOST_ID_NULL);
434 checkNotNull(d, E_DEVICE_ID_NULL);
435 checkNotNull(p, E_PORT_NULL);
436 return new UiLinkId(h, PortNumber.P0, d, p);
437 }
438
Simon Huntc0f20c12016-05-09 09:30:20 -0700439}