ONOS-4971: Synthetic Link Data -- WIP

- Breaking out UiLink to subclasses for device links, host links, region links, region-device links,
    - (soon, also peer links).
- Augmenting UiLinkId to include regions as endpoints.
- Introduced UiSynthLink to encapsulate synthetic links bound to regions.
- Model Cache now computes synthetic links from the underlying link data.
- Added endPointA/B() and type() methods to UiLink.
- Updated topo2CurrentRegion response to include synth-links for the region.

Change-Id: Ifa62a15fbe0a58b134d92278b201fa7a72cbfa83
diff --git a/core/api/src/main/java/org/onosproject/ui/model/topo/UiDeviceLink.java b/core/api/src/main/java/org/onosproject/ui/model/topo/UiDeviceLink.java
new file mode 100644
index 0000000..4575678
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/ui/model/topo/UiDeviceLink.java
@@ -0,0 +1,180 @@
+/*
+ * 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.DeviceId;
+import org.onosproject.net.Link;
+import org.onosproject.net.PortNumber;
+
+/**
+ * Represents a link between two devices; that is, an infrastructure link.
+ */
+public class UiDeviceLink extends UiLink {
+
+    private static final String E_UNASSOC =
+            "backing link not associated with this UI device link: ";
+
+    // devices and ports at either end of this link
+    private DeviceId deviceA;
+    private DeviceId deviceB;
+    private PortNumber portA;
+    private PortNumber portB;
+
+    // two unidirectional links underlying this link...
+    private Link linkAtoB;
+    private Link linkBtoA;
+
+
+    /**
+     * Creates a device to device UI link.
+     *
+     * @param topology parent topology
+     * @param id       canonicalized link identifier
+     */
+    public UiDeviceLink(UiTopology topology, UiLinkId id) {
+        super(topology, id);
+    }
+
+    @Override
+    public String endPointA() {
+        return deviceA + UiLinkId.ID_PORT_DELIMITER + portA;
+    }
+
+    @Override
+    public String endPointB() {
+        return deviceB + UiLinkId.ID_PORT_DELIMITER + portB;
+    }
+
+
+    @Override
+    protected void destroy() {
+        deviceA = null;
+        deviceB = null;
+        portA = null;
+        portB = null;
+        linkAtoB = null;
+        linkBtoA = null;
+    }
+
+
+    /**
+     * Attaches the given backing link to this UI link. This method will
+     * throw an exception if this UI link is not representative of the
+     * supplied link.
+     *
+     * @param link backing link to attach
+     * @throws IllegalArgumentException if the link is not appropriate
+     */
+    public void attachBackingLink(Link link) {
+        UiLinkId.Direction d = id.directionOf(link);
+
+        if (d == UiLinkId.Direction.A_TO_B) {
+            linkAtoB = link;
+            deviceA = link.src().deviceId();
+            portA = link.src().port();
+            deviceB = link.dst().deviceId();
+            portB = link.dst().port();
+
+        } else if (d == UiLinkId.Direction.B_TO_A) {
+            linkBtoA = link;
+            deviceB = link.src().deviceId();
+            portB = link.src().port();
+            deviceA = link.dst().deviceId();
+            portA = link.dst().port();
+
+        } else {
+            throw new IllegalArgumentException(E_UNASSOC + link);
+        }
+    }
+
+    /**
+     * Detaches the given backing link from this UI link, returning true if the
+     * reverse link is still attached, or false otherwise.
+     *
+     * @param link the backing link to detach
+     * @return true if other link still attached, false otherwise
+     * @throws IllegalArgumentException if the link is not appropriate
+     */
+    public boolean detachBackingLink(Link link) {
+        UiLinkId.Direction d = id.directionOf(link);
+        if (d == UiLinkId.Direction.A_TO_B) {
+            linkAtoB = null;
+            return linkBtoA != null;
+        }
+        if (d == UiLinkId.Direction.B_TO_A) {
+            linkBtoA = null;
+            return linkAtoB != null;
+        }
+        throw new IllegalArgumentException(E_UNASSOC + link);
+    }
+
+
+    /**
+     * Returns the identity of device A.
+     *
+     * @return device A ID
+     */
+    public DeviceId deviceA() {
+        return deviceA;
+    }
+
+    /**
+     * Returns the port number of device A.
+     *
+     * @return port A
+     */
+    public PortNumber portA() {
+        return portA;
+    }
+
+    /**
+     * Returns the identity of device B.
+     *
+     * @return device B ID
+     */
+    public DeviceId deviceB() {
+        return deviceB;
+    }
+
+    /**
+     * Returns the port number of device B.
+     *
+     * @return port B
+     */
+    public PortNumber portB() {
+        return portB;
+    }
+
+    /**
+     * Returns backing link from A to B.
+     *
+     * @return backing link A to B
+     */
+    public Link linkAtoB() {
+        return linkAtoB;
+    }
+
+    /**
+     * Returns backing link from B to A.
+     *
+     * @return backing link B to A
+     */
+    public Link linkBtoA() {
+        return linkBtoA;
+    }
+
+}