blob: c8dae05be0017c1fd7ad46ae64b50467e0873149 [file] [log] [blame]
/*
* Copyright 2016-present Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onosproject.ui.model.topo;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.DeviceId;
import org.onosproject.net.ElementId;
import org.onosproject.net.HostId;
import org.onosproject.net.Link;
import org.onosproject.net.PortNumber;
import org.onosproject.net.region.RegionId;
import java.util.Comparator;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* A canonical representation of an identifier for {@link UiLink}s.
*/
public final class UiLinkId {
private static final String E_PORT_NULL = "Port number cannot be null";
private static final String E_DEVICE_ID_NULL = "Device ID cannot be null";
private static final String E_REGION_ID_NULL = "Region ID cannot be null";
private static final String E_IDENTICAL = "Region IDs cannot be same";
private static final Comparator<RegionId> REGION_ID_COMPARATOR =
(o1, o2) -> o1.toString().compareTo(o2.toString());
/**
* Designates the directionality of an underlying (uni-directional) link.
*/
public enum Direction {
A_TO_B,
B_TO_A
}
static final String CP_DELIMITER = "~";
static final String ID_PORT_DELIMITER = "/";
private final RegionId regionA;
private final ElementId elementA;
private final PortNumber portA;
private final RegionId regionB;
private final ElementId elementB;
private final PortNumber portB;
private final String idStr;
private final String idA;
private final String idB;
/**
* Creates a UI link identifier. It is expected that A comes before B when
* the two identifiers are naturally sorted, thus providing a representation
* which is invariant to whether A or B is source or destination of the
* underlying link.
*
* @param a first element ID
* @param pa first element port
* @param b second element ID
* @param pb second element port
*/
private UiLinkId(ElementId a, PortNumber pa, ElementId b, PortNumber pb) {
elementA = a;
portA = pa;
elementB = b;
portB = pb;
regionA = null;
regionB = null;
// NOTE: for edgelinks, hosts are always element A
idA = (a instanceof HostId) ? a.toString() : a + ID_PORT_DELIMITER + pa;
idB = b + ID_PORT_DELIMITER + pb;
idStr = idA + CP_DELIMITER + idB;
}
/**
* Creates a UI link identifier. It is expected that A comes before B when
* the two identifiers are naturally sorted.
*
* @param a first region ID
* @param b second region ID
*/
private UiLinkId(RegionId a, RegionId b) {
regionA = a;
regionB = b;
elementA = null;
elementB = null;
portA = null;
portB = null;
idA = a.toString();
idB = b.toString();
idStr = idA + CP_DELIMITER + idB;
}
/**
* Creates a UI link identifier, with region at one end and a device/port
* at the other.
*
* @param r region ID
* @param d device ID
* @param p port number
*/
private UiLinkId(RegionId r, DeviceId d, PortNumber p) {
regionA = r;
elementB = d;
portB = p;
regionB = null;
elementA = null;
portA = null;
idA = r.toString();
idB = elementB + ID_PORT_DELIMITER + portB;
idStr = idA + CP_DELIMITER + idB;
}
@Override
public String toString() {
return idStr;
}
/**
* String representation of endpoint A.
*
* @return string rep of endpoint A
*/
public String idA() {
return idA;
}
/**
* String representation of endpoint B.
*
* @return string rep of endpoint B
*/
public String idB() {
return idB;
}
/**
* Returns the identifier of the first element. Note that the returned
* value will be null if this identifier is for a region-region link.
*
* @return first element identity
*/
public ElementId elementA() {
return elementA;
}
/**
* Returns the port of the first element. Note that the returned
* value will be null if this identifier is for a region-region link.
*
* @return first element port
*/
public PortNumber portA() {
return portA;
}
/**
* Returns the identifier of the second element. Note that the returned
* value will be null if this identifier is for a region-region link.
*
* @return second element identity
*/
public ElementId elementB() {
return elementB;
}
/**
* Returns the port of the second element. Note that the returned
* value will be null if this identifier is for a region-region link.
*
* @return second element port
*/
public PortNumber portB() {
return portB;
}
/**
* Returns the identity of the first region. Note that the returned value
* will be null if this identifier is for a device-device or device-host
* link.
*
* @return first region ID
*/
public RegionId regionA() {
return regionA;
}
/**
* Returns the identity of the second region. Note that the returned value
* will be null if this identifier is for a device-device or device-host
* link.
*
* @return second region ID
*/
public RegionId regionB() {
return regionB;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
UiLinkId uiLinkId = (UiLinkId) o;
return idStr.equals(uiLinkId.idStr);
}
@Override
public int hashCode() {
return idStr.hashCode();
}
/**
* Returns the direction of the given link, or null if this link ID does
* not correspond to the given link.
*
* @param link the link to examine
* @return corresponding direction
*/
Direction directionOf(Link link) {
ConnectPoint src = link.src();
ElementId srcId = src.elementId();
return elementA.equals(srcId) ? Direction.A_TO_B
: elementB.equals(srcId) ? Direction.B_TO_A
: null;
}
/**
* Generates the canonical link identifier for the given link.
*
* @param link link for which the identifier is required
* @return link identifier
* @throws NullPointerException if any of the required fields are null
*/
public static UiLinkId uiLinkId(Link link) {
ConnectPoint src = link.src();
ConnectPoint dst = link.dst();
if (src == null || dst == null) {
throw new NullPointerException(
"null src or dst connect point: " + link);
}
ElementId srcId = src.elementId();
ElementId dstId = dst.elementId();
// canonicalize
int comp = srcId.toString().compareTo(dstId.toString());
return comp <= 0 ? new UiLinkId(srcId, src.port(), dstId, dst.port())
: new UiLinkId(dstId, dst.port(), srcId, src.port());
}
/**
* Generates the canonical link identifier for a link between the
* specified region nodes.
*
* @param one the first region ID
* @param two the second region ID
* @return link identifier
* @throws NullPointerException if any of the required fields are null
* @throws IllegalArgumentException if the identifiers are identical
*/
public static UiLinkId uiLinkId(RegionId one, RegionId two) {
checkNotNull(one, E_REGION_ID_NULL);
checkNotNull(two, E_REGION_ID_NULL);
checkArgument(!one.equals(two), E_IDENTICAL);
boolean flip = REGION_ID_COMPARATOR.compare(one, two) > 0;
return flip ? new UiLinkId(two, one) : new UiLinkId(one, two);
}
/**
* Generates the canonical link identifier for a link between the specified
* region and device/port.
*
* @param regionId region ID
* @param deviceId device ID
* @param portNumber port number
* @return link identifier
* @throws NullPointerException if any of the required fields are null
*/
public static UiLinkId uiLinkId(RegionId regionId, DeviceId deviceId,
PortNumber portNumber) {
checkNotNull(regionId, E_REGION_ID_NULL);
checkNotNull(deviceId, E_DEVICE_ID_NULL);
checkNotNull(portNumber, E_PORT_NULL);
return new UiLinkId(regionId, deviceId, portNumber);
}
}