blob: c8dae05be0017c1fd7ad46ae64b50467e0873149 [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
19import org.onosproject.net.ConnectPoint;
Simon Huntc13082f2016-08-03 21:20:23 -070020import org.onosproject.net.DeviceId;
Simon Huntc0f20c12016-05-09 09:30:20 -070021import org.onosproject.net.ElementId;
Simon Huntb7fd0802016-10-27 12:21:40 -070022import org.onosproject.net.HostId;
Simon Huntc0f20c12016-05-09 09:30:20 -070023import org.onosproject.net.Link;
Simon Hunt58a0dd02016-05-17 11:54:23 -070024import org.onosproject.net.PortNumber;
Simon Huntc13082f2016-08-03 21:20:23 -070025import org.onosproject.net.region.RegionId;
26
27import java.util.Comparator;
28
29import static com.google.common.base.Preconditions.checkArgument;
30import static com.google.common.base.Preconditions.checkNotNull;
Simon Huntc0f20c12016-05-09 09:30:20 -070031
32/**
33 * A canonical representation of an identifier for {@link UiLink}s.
34 */
35public final class UiLinkId {
36
Simon Huntc13082f2016-08-03 21:20:23 -070037 private static final String E_PORT_NULL = "Port number cannot be null";
38 private static final String E_DEVICE_ID_NULL = "Device ID cannot be null";
39 private static final String E_REGION_ID_NULL = "Region ID cannot be null";
40 private static final String E_IDENTICAL = "Region IDs cannot be same";
41
42 private static final Comparator<RegionId> REGION_ID_COMPARATOR =
43 (o1, o2) -> o1.toString().compareTo(o2.toString());
44
Simon Huntc0f20c12016-05-09 09:30:20 -070045 /**
46 * Designates the directionality of an underlying (uni-directional) link.
47 */
48 public enum Direction {
49 A_TO_B,
50 B_TO_A
51 }
52
Simon Huntb7fd0802016-10-27 12:21:40 -070053 static final String CP_DELIMITER = "~";
Simon Huntc13082f2016-08-03 21:20:23 -070054 static final String ID_PORT_DELIMITER = "/";
Simon Huntc0f20c12016-05-09 09:30:20 -070055
Simon Huntc13082f2016-08-03 21:20:23 -070056 private final RegionId regionA;
57 private final ElementId elementA;
Simon Hunt58a0dd02016-05-17 11:54:23 -070058 private final PortNumber portA;
Simon Huntc13082f2016-08-03 21:20:23 -070059
60 private final RegionId regionB;
61 private final ElementId elementB;
Simon Hunt58a0dd02016-05-17 11:54:23 -070062 private final PortNumber portB;
63
Simon Huntc0f20c12016-05-09 09:30:20 -070064 private final String idStr;
Simon Huntb7fd0802016-10-27 12:21:40 -070065 private final String idA;
66 private final String idB;
Simon Huntc0f20c12016-05-09 09:30:20 -070067
68 /**
69 * Creates a UI link identifier. It is expected that A comes before B when
70 * the two identifiers are naturally sorted, thus providing a representation
71 * which is invariant to whether A or B is source or destination of the
72 * underlying link.
73 *
Simon Huntc13082f2016-08-03 21:20:23 -070074 * @param a first element ID
Simon Hunt58a0dd02016-05-17 11:54:23 -070075 * @param pa first element port
Simon Huntc13082f2016-08-03 21:20:23 -070076 * @param b second element ID
Simon Hunt58a0dd02016-05-17 11:54:23 -070077 * @param pb second element port
Simon Huntc0f20c12016-05-09 09:30:20 -070078 */
Simon Hunt58a0dd02016-05-17 11:54:23 -070079 private UiLinkId(ElementId a, PortNumber pa, ElementId b, PortNumber pb) {
Simon Huntc13082f2016-08-03 21:20:23 -070080 elementA = a;
Simon Hunt58a0dd02016-05-17 11:54:23 -070081 portA = pa;
Simon Huntc13082f2016-08-03 21:20:23 -070082 elementB = b;
Simon Hunt58a0dd02016-05-17 11:54:23 -070083 portB = pb;
Simon Huntc0f20c12016-05-09 09:30:20 -070084
Simon Huntc13082f2016-08-03 21:20:23 -070085 regionA = null;
86 regionB = null;
87
Simon Huntb7fd0802016-10-27 12:21:40 -070088 // NOTE: for edgelinks, hosts are always element A
89 idA = (a instanceof HostId) ? a.toString() : a + ID_PORT_DELIMITER + pa;
90 idB = b + ID_PORT_DELIMITER + pb;
91 idStr = idA + CP_DELIMITER + idB;
Simon Huntc0f20c12016-05-09 09:30:20 -070092 }
93
Simon Huntc13082f2016-08-03 21:20:23 -070094 /**
95 * Creates a UI link identifier. It is expected that A comes before B when
96 * the two identifiers are naturally sorted.
97 *
98 * @param a first region ID
99 * @param b second region ID
100 */
101 private UiLinkId(RegionId a, RegionId b) {
102 regionA = a;
103 regionB = b;
104
105 elementA = null;
106 elementB = null;
107 portA = null;
108 portB = null;
109
Simon Huntb7fd0802016-10-27 12:21:40 -0700110 idA = a.toString();
111 idB = b.toString();
112 idStr = idA + CP_DELIMITER + idB;
Simon Huntc13082f2016-08-03 21:20:23 -0700113 }
114
115 /**
116 * Creates a UI link identifier, with region at one end and a device/port
117 * at the other.
118 *
119 * @param r region ID
120 * @param d device ID
121 * @param p port number
122 */
123 private UiLinkId(RegionId r, DeviceId d, PortNumber p) {
124 regionA = r;
125 elementB = d;
126 portB = p;
127
128 regionB = null;
129 elementA = null;
130 portA = null;
131
Simon Huntb7fd0802016-10-27 12:21:40 -0700132 idA = r.toString();
133 idB = elementB + ID_PORT_DELIMITER + portB;
134 idStr = idA + CP_DELIMITER + idB;
Simon Huntc13082f2016-08-03 21:20:23 -0700135 }
136
Simon Huntc0f20c12016-05-09 09:30:20 -0700137 @Override
138 public String toString() {
139 return idStr;
140 }
141
142 /**
Simon Huntb7fd0802016-10-27 12:21:40 -0700143 * String representation of endpoint A.
144 *
145 * @return string rep of endpoint A
146 */
147 public String idA() {
148 return idA;
149 }
150
151 /**
152 * String representation of endpoint B.
153 *
154 * @return string rep of endpoint B
155 */
156 public String idB() {
157 return idB;
158 }
159
160 /**
Simon Huntc13082f2016-08-03 21:20:23 -0700161 * Returns the identifier of the first element. Note that the returned
162 * value will be null if this identifier is for a region-region link.
Simon Huntc0f20c12016-05-09 09:30:20 -0700163 *
164 * @return first element identity
165 */
166 public ElementId elementA() {
Simon Huntc13082f2016-08-03 21:20:23 -0700167 return elementA;
Simon Huntc0f20c12016-05-09 09:30:20 -0700168 }
169
170 /**
Simon Huntc13082f2016-08-03 21:20:23 -0700171 * Returns the port of the first element. Note that the returned
172 * value will be null if this identifier is for a region-region link.
Simon Hunt58a0dd02016-05-17 11:54:23 -0700173 *
174 * @return first element port
175 */
176 public PortNumber portA() {
177 return portA;
178 }
179
180 /**
Simon Huntc13082f2016-08-03 21:20:23 -0700181 * Returns the identifier of the second element. Note that the returned
182 * value will be null if this identifier is for a region-region link.
Simon Huntc0f20c12016-05-09 09:30:20 -0700183 *
184 * @return second element identity
185 */
186 public ElementId elementB() {
Simon Huntc13082f2016-08-03 21:20:23 -0700187 return elementB;
Simon Huntc0f20c12016-05-09 09:30:20 -0700188 }
189
Simon Hunt58a0dd02016-05-17 11:54:23 -0700190 /**
Simon Huntc13082f2016-08-03 21:20:23 -0700191 * Returns the port of the second element. Note that the returned
192 * value will be null if this identifier is for a region-region link.
Simon Hunt58a0dd02016-05-17 11:54:23 -0700193 *
194 * @return second element port
195 */
196 public PortNumber portB() {
197 return portB;
198 }
199
Simon Huntc13082f2016-08-03 21:20:23 -0700200 /**
201 * Returns the identity of the first region. Note that the returned value
202 * will be null if this identifier is for a device-device or device-host
203 * link.
204 *
205 * @return first region ID
206 */
207 public RegionId regionA() {
208 return regionA;
209 }
210
211 /**
212 * Returns the identity of the second region. Note that the returned value
213 * will be null if this identifier is for a device-device or device-host
214 * link.
215 *
216 * @return second region ID
217 */
218 public RegionId regionB() {
219 return regionB;
220 }
221
Simon Huntc0f20c12016-05-09 09:30:20 -0700222 @Override
223 public boolean equals(Object o) {
224 if (this == o) {
225 return true;
226 }
227 if (o == null || getClass() != o.getClass()) {
228 return false;
229 }
230
231 UiLinkId uiLinkId = (UiLinkId) o;
232 return idStr.equals(uiLinkId.idStr);
233 }
234
235 @Override
236 public int hashCode() {
237 return idStr.hashCode();
238 }
239
240 /**
241 * Returns the direction of the given link, or null if this link ID does
242 * not correspond to the given link.
243 *
244 * @param link the link to examine
245 * @return corresponding direction
246 */
247 Direction directionOf(Link link) {
248 ConnectPoint src = link.src();
249 ElementId srcId = src.elementId();
Simon Huntc13082f2016-08-03 21:20:23 -0700250 return elementA.equals(srcId) ? Direction.A_TO_B
251 : elementB.equals(srcId) ? Direction.B_TO_A
Simon Huntc0f20c12016-05-09 09:30:20 -0700252 : null;
253 }
254
255 /**
256 * Generates the canonical link identifier for the given link.
257 *
258 * @param link link for which the identifier is required
259 * @return link identifier
260 * @throws NullPointerException if any of the required fields are null
261 */
262 public static UiLinkId uiLinkId(Link link) {
263 ConnectPoint src = link.src();
264 ConnectPoint dst = link.dst();
265 if (src == null || dst == null) {
Simon Huntb0582492016-09-20 18:26:38 -0700266 throw new NullPointerException(
267 "null src or dst connect point: " + link);
Simon Huntc0f20c12016-05-09 09:30:20 -0700268 }
269
270 ElementId srcId = src.elementId();
271 ElementId dstId = dst.elementId();
Simon Huntc0f20c12016-05-09 09:30:20 -0700272
273 // canonicalize
274 int comp = srcId.toString().compareTo(dstId.toString());
Simon Hunt58a0dd02016-05-17 11:54:23 -0700275 return comp <= 0 ? new UiLinkId(srcId, src.port(), dstId, dst.port())
276 : new UiLinkId(dstId, dst.port(), srcId, src.port());
Simon Huntc0f20c12016-05-09 09:30:20 -0700277 }
Simon Huntc13082f2016-08-03 21:20:23 -0700278
279 /**
280 * Generates the canonical link identifier for a link between the
281 * specified region nodes.
282 *
283 * @param one the first region ID
284 * @param two the second region ID
285 * @return link identifier
286 * @throws NullPointerException if any of the required fields are null
287 * @throws IllegalArgumentException if the identifiers are identical
288 */
289 public static UiLinkId uiLinkId(RegionId one, RegionId two) {
290 checkNotNull(one, E_REGION_ID_NULL);
291 checkNotNull(two, E_REGION_ID_NULL);
292 checkArgument(!one.equals(two), E_IDENTICAL);
293
294 boolean flip = REGION_ID_COMPARATOR.compare(one, two) > 0;
295 return flip ? new UiLinkId(two, one) : new UiLinkId(one, two);
296 }
297
298 /**
299 * Generates the canonical link identifier for a link between the specified
300 * region and device/port.
301 *
302 * @param regionId region ID
303 * @param deviceId device ID
304 * @param portNumber port number
305 * @return link identifier
306 * @throws NullPointerException if any of the required fields are null
307 */
308 public static UiLinkId uiLinkId(RegionId regionId, DeviceId deviceId,
309 PortNumber portNumber) {
310 checkNotNull(regionId, E_REGION_ID_NULL);
311 checkNotNull(deviceId, E_DEVICE_ID_NULL);
312 checkNotNull(portNumber, E_PORT_NULL);
313
314 return new UiLinkId(regionId, deviceId, portNumber);
315 }
Simon Huntc0f20c12016-05-09 09:30:20 -0700316}