blob: dd1b3b8e1c18f063cb06a569f36a5315b3188b1c [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";
41 private static final String E_REGION_ID_NULL = "Region ID cannot be null";
42 private static final String E_IDENTICAL = "Region IDs cannot be same";
43
44 private static final Comparator<RegionId> REGION_ID_COMPARATOR =
Simon Hunt0e161092017-05-08 17:41:38 -070045 Comparator.comparing(Identifier::toString);
Simon Huntc13082f2016-08-03 21:20:23 -070046
Simon Huntc0f20c12016-05-09 09:30:20 -070047 /**
48 * Designates the directionality of an underlying (uni-directional) link.
49 */
50 public enum Direction {
51 A_TO_B,
52 B_TO_A
53 }
54
Simon Huntb7fd0802016-10-27 12:21:40 -070055 static final String CP_DELIMITER = "~";
Simon Huntc13082f2016-08-03 21:20:23 -070056 static final String ID_PORT_DELIMITER = "/";
Simon Huntc0f20c12016-05-09 09:30:20 -070057
Simon Huntc13082f2016-08-03 21:20:23 -070058 private final RegionId regionA;
59 private final ElementId elementA;
Simon Hunt58a0dd02016-05-17 11:54:23 -070060 private final PortNumber portA;
Simon Huntc13082f2016-08-03 21:20:23 -070061
62 private final RegionId regionB;
63 private final ElementId elementB;
Simon Hunt58a0dd02016-05-17 11:54:23 -070064 private final PortNumber portB;
65
Simon Huntc0f20c12016-05-09 09:30:20 -070066 private final String idStr;
Simon Huntb7fd0802016-10-27 12:21:40 -070067 private final String idA;
68 private final String idB;
Simon Huntc0f20c12016-05-09 09:30:20 -070069
70 /**
71 * Creates a UI link identifier. It is expected that A comes before B when
72 * the two identifiers are naturally sorted, thus providing a representation
73 * which is invariant to whether A or B is source or destination of the
74 * underlying link.
75 *
Simon Huntc13082f2016-08-03 21:20:23 -070076 * @param a first element ID
Simon Hunt58a0dd02016-05-17 11:54:23 -070077 * @param pa first element port
Simon Huntc13082f2016-08-03 21:20:23 -070078 * @param b second element ID
Simon Hunt58a0dd02016-05-17 11:54:23 -070079 * @param pb second element port
Simon Huntc0f20c12016-05-09 09:30:20 -070080 */
Simon Hunt58a0dd02016-05-17 11:54:23 -070081 private UiLinkId(ElementId a, PortNumber pa, ElementId b, PortNumber pb) {
Simon Huntc13082f2016-08-03 21:20:23 -070082 elementA = a;
Simon Hunt58a0dd02016-05-17 11:54:23 -070083 portA = pa;
Simon Huntc13082f2016-08-03 21:20:23 -070084 elementB = b;
Simon Hunt58a0dd02016-05-17 11:54:23 -070085 portB = pb;
Simon Huntc0f20c12016-05-09 09:30:20 -070086
Simon Huntc13082f2016-08-03 21:20:23 -070087 regionA = null;
88 regionB = null;
89
Simon Huntb7fd0802016-10-27 12:21:40 -070090 // NOTE: for edgelinks, hosts are always element A
91 idA = (a instanceof HostId) ? a.toString() : a + ID_PORT_DELIMITER + pa;
92 idB = b + ID_PORT_DELIMITER + pb;
93 idStr = idA + CP_DELIMITER + idB;
Simon Huntc0f20c12016-05-09 09:30:20 -070094 }
95
Simon Huntc13082f2016-08-03 21:20:23 -070096 /**
97 * Creates a UI link identifier. It is expected that A comes before B when
98 * the two identifiers are naturally sorted.
99 *
100 * @param a first region ID
101 * @param b second region ID
102 */
103 private UiLinkId(RegionId a, RegionId b) {
104 regionA = a;
105 regionB = b;
106
107 elementA = null;
108 elementB = null;
109 portA = null;
110 portB = null;
111
Simon Huntb7fd0802016-10-27 12:21:40 -0700112 idA = a.toString();
113 idB = b.toString();
114 idStr = idA + CP_DELIMITER + idB;
Simon Huntc13082f2016-08-03 21:20:23 -0700115 }
116
117 /**
118 * Creates a UI link identifier, with region at one end and a device/port
119 * at the other.
120 *
121 * @param r region ID
122 * @param d device ID
123 * @param p port number
124 */
125 private UiLinkId(RegionId r, DeviceId d, PortNumber p) {
126 regionA = r;
127 elementB = d;
128 portB = p;
129
130 regionB = null;
131 elementA = null;
132 portA = null;
133
Simon Huntb7fd0802016-10-27 12:21:40 -0700134 idA = r.toString();
135 idB = elementB + ID_PORT_DELIMITER + portB;
136 idStr = idA + CP_DELIMITER + idB;
Simon Huntc13082f2016-08-03 21:20:23 -0700137 }
138
Simon Huntc0f20c12016-05-09 09:30:20 -0700139 @Override
140 public String toString() {
141 return idStr;
142 }
143
144 /**
Simon Huntb7fd0802016-10-27 12:21:40 -0700145 * String representation of endpoint A.
146 *
147 * @return string rep of endpoint A
148 */
149 public String idA() {
150 return idA;
151 }
152
153 /**
154 * String representation of endpoint B.
155 *
156 * @return string rep of endpoint B
157 */
158 public String idB() {
159 return idB;
160 }
161
162 /**
Simon Huntc13082f2016-08-03 21:20:23 -0700163 * Returns the identifier of the first element. Note that the returned
164 * value will be null if this identifier is for a region-region link.
Simon Huntc0f20c12016-05-09 09:30:20 -0700165 *
166 * @return first element identity
167 */
168 public ElementId elementA() {
Simon Huntc13082f2016-08-03 21:20:23 -0700169 return elementA;
Simon Huntc0f20c12016-05-09 09:30:20 -0700170 }
171
172 /**
Simon Huntc13082f2016-08-03 21:20:23 -0700173 * Returns the port of the first element. Note that the returned
174 * value will be null if this identifier is for a region-region link.
Simon Hunt58a0dd02016-05-17 11:54:23 -0700175 *
176 * @return first element port
177 */
178 public PortNumber portA() {
179 return portA;
180 }
181
182 /**
Simon Huntc13082f2016-08-03 21:20:23 -0700183 * Returns the identifier of the second element. Note that the returned
184 * value will be null if this identifier is for a region-region link.
Simon Huntc0f20c12016-05-09 09:30:20 -0700185 *
186 * @return second element identity
187 */
188 public ElementId elementB() {
Simon Huntc13082f2016-08-03 21:20:23 -0700189 return elementB;
Simon Huntc0f20c12016-05-09 09:30:20 -0700190 }
191
Simon Hunt58a0dd02016-05-17 11:54:23 -0700192 /**
Simon Huntc13082f2016-08-03 21:20:23 -0700193 * Returns the port of the second element. Note that the returned
194 * value will be null if this identifier is for a region-region link.
Simon Hunt58a0dd02016-05-17 11:54:23 -0700195 *
196 * @return second element port
197 */
198 public PortNumber portB() {
199 return portB;
200 }
201
Simon Huntc13082f2016-08-03 21:20:23 -0700202 /**
203 * Returns the identity of the first region. Note that the returned value
204 * will be null if this identifier is for a device-device or device-host
205 * link.
206 *
207 * @return first region ID
208 */
209 public RegionId regionA() {
210 return regionA;
211 }
212
213 /**
214 * Returns the identity of the second region. Note that the returned value
215 * will be null if this identifier is for a device-device or device-host
216 * link.
217 *
218 * @return second region ID
219 */
220 public RegionId regionB() {
221 return regionB;
222 }
223
Simon Huntc0f20c12016-05-09 09:30:20 -0700224 @Override
225 public boolean equals(Object o) {
226 if (this == o) {
227 return true;
228 }
229 if (o == null || getClass() != o.getClass()) {
230 return false;
231 }
232
233 UiLinkId uiLinkId = (UiLinkId) o;
234 return idStr.equals(uiLinkId.idStr);
235 }
236
237 @Override
238 public int hashCode() {
239 return idStr.hashCode();
240 }
241
242 /**
243 * Returns the direction of the given link, or null if this link ID does
244 * not correspond to the given link.
245 *
246 * @param link the link to examine
247 * @return corresponding direction
248 */
249 Direction directionOf(Link link) {
250 ConnectPoint src = link.src();
251 ElementId srcId = src.elementId();
Simon Huntc13082f2016-08-03 21:20:23 -0700252 return elementA.equals(srcId) ? Direction.A_TO_B
253 : elementB.equals(srcId) ? Direction.B_TO_A
Simon Huntc0f20c12016-05-09 09:30:20 -0700254 : null;
255 }
256
257 /**
258 * Generates the canonical link identifier for the given link.
259 *
260 * @param link link for which the identifier is required
261 * @return link identifier
Simon Hunt0e161092017-05-08 17:41:38 -0700262 * @throws NullPointerException if src or dst connect point is null
Simon Huntc0f20c12016-05-09 09:30:20 -0700263 */
264 public static UiLinkId uiLinkId(Link link) {
Simon Hunt0e161092017-05-08 17:41:38 -0700265 return canonicalizeIdentifier(link.src(), link.dst());
266 }
267
268 /**
269 * Creates the canonical link identifier from the given link key.
270 *
271 * @param lk link key
272 * @return equivalent link identifier
273 * @throws NullPointerException if src or dst connect point is null
274 */
275 public static UiLinkId uiLinkId(LinkKey lk) {
276 return canonicalizeIdentifier(lk.src(), lk.dst());
277 }
278
279 private static UiLinkId canonicalizeIdentifier(ConnectPoint src, ConnectPoint dst) {
Simon Huntc0f20c12016-05-09 09:30:20 -0700280 if (src == null || dst == null) {
Simon Huntb0582492016-09-20 18:26:38 -0700281 throw new NullPointerException(
Simon Hunt0e161092017-05-08 17:41:38 -0700282 "null src or dst connect point (illegal for UiLinkId)");
Simon Huntc0f20c12016-05-09 09:30:20 -0700283 }
Simon Huntc0f20c12016-05-09 09:30:20 -0700284 ElementId srcId = src.elementId();
285 ElementId dstId = dst.elementId();
Simon Huntc0f20c12016-05-09 09:30:20 -0700286
287 // canonicalize
288 int comp = srcId.toString().compareTo(dstId.toString());
Simon Hunt58a0dd02016-05-17 11:54:23 -0700289 return comp <= 0 ? new UiLinkId(srcId, src.port(), dstId, dst.port())
290 : new UiLinkId(dstId, dst.port(), srcId, src.port());
Simon Huntc0f20c12016-05-09 09:30:20 -0700291 }
Simon Huntc13082f2016-08-03 21:20:23 -0700292
293 /**
294 * Generates the canonical link identifier for a link between the
295 * specified region nodes.
296 *
297 * @param one the first region ID
298 * @param two the second region ID
299 * @return link identifier
300 * @throws NullPointerException if any of the required fields are null
301 * @throws IllegalArgumentException if the identifiers are identical
302 */
303 public static UiLinkId uiLinkId(RegionId one, RegionId two) {
304 checkNotNull(one, E_REGION_ID_NULL);
305 checkNotNull(two, E_REGION_ID_NULL);
306 checkArgument(!one.equals(two), E_IDENTICAL);
307
308 boolean flip = REGION_ID_COMPARATOR.compare(one, two) > 0;
309 return flip ? new UiLinkId(two, one) : new UiLinkId(one, two);
310 }
311
312 /**
313 * Generates the canonical link identifier for a link between the specified
314 * region and device/port.
315 *
316 * @param regionId region ID
317 * @param deviceId device ID
318 * @param portNumber port number
319 * @return link identifier
320 * @throws NullPointerException if any of the required fields are null
321 */
322 public static UiLinkId uiLinkId(RegionId regionId, DeviceId deviceId,
323 PortNumber portNumber) {
324 checkNotNull(regionId, E_REGION_ID_NULL);
325 checkNotNull(deviceId, E_DEVICE_ID_NULL);
326 checkNotNull(portNumber, E_PORT_NULL);
327
328 return new UiLinkId(regionId, deviceId, portNumber);
329 }
Simon Huntc0f20c12016-05-09 09:30:20 -0700330}