Fixed issue with canonicalization of link identifiers.
- added asId() to LinkKey
- BiLink.linkId() now returns LinkKey.asId()

Change-Id: Ie9069ca5302f09fca9e213ce33fa87bd8868e752
diff --git a/core/api/src/main/java/org/onosproject/net/LinkKey.java b/core/api/src/main/java/org/onosproject/net/LinkKey.java
index 0b0d5fb..5a2566f 100644
--- a/core/api/src/main/java/org/onosproject/net/LinkKey.java
+++ b/core/api/src/main/java/org/onosproject/net/LinkKey.java
@@ -15,13 +15,12 @@
  */
 package org.onosproject.net;
 
-import static com.google.common.base.Preconditions.checkNotNull;
+import com.google.common.base.MoreObjects;
+import org.onosproject.net.link.LinkDescription;
 
 import java.util.Objects;
 
-import org.onosproject.net.link.LinkDescription;
-
-import com.google.common.base.MoreObjects;
+import static com.google.common.base.Preconditions.checkNotNull;
 
 // TODO Consider renaming.
 // it's an identifier for a Link, but it's not ElementId, so not using LinkId.
@@ -31,10 +30,23 @@
  */
 public final class LinkKey {
 
+    private static final String DELIM = "-";
+
     private final ConnectPoint src;
     private final ConnectPoint dst;
 
     /**
+     * Creates a link identifier with source and destination connection point.
+     *
+     * @param src source connection point
+     * @param dst destination connection point
+     */
+    private LinkKey(ConnectPoint src, ConnectPoint dst) {
+        this.src = checkNotNull(src);
+        this.dst = checkNotNull(dst);
+    }
+
+    /**
      * Returns source connection point.
      *
      * @return source connection point
@@ -53,14 +65,38 @@
     }
 
     /**
-     * Creates a link identifier with source and destination connection point.
+     * Returns a string suitable to be used as an identifier.
      *
-     * @param src source connection point
-     * @param dst destination connection point
+     * @return string as identifier
      */
-    private LinkKey(ConnectPoint src, ConnectPoint dst) {
-        this.src = checkNotNull(src);
-        this.dst = checkNotNull(dst);
+    public String asId() {
+        return src + DELIM + dst;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(src, dst);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj instanceof LinkKey) {
+            final LinkKey other = (LinkKey) obj;
+            return Objects.equals(this.src, other.src) &&
+                    Objects.equals(this.dst, other.dst);
+        }
+        return false;
+    }
+
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(getClass())
+                .add("src", src)
+                .add("dst", dst)
+                .toString();
     }
 
     /**
@@ -94,29 +130,4 @@
         return new LinkKey(link.src(), link.dst());
     }
 
-    @Override
-    public int hashCode() {
-        return Objects.hash(src, dst);
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (this == obj) {
-            return true;
-        }
-        if (obj instanceof LinkKey) {
-            final LinkKey other = (LinkKey) obj;
-            return Objects.equals(this.src, other.src) &&
-                    Objects.equals(this.dst, other.dst);
-        }
-        return false;
-    }
-
-    @Override
-    public String toString() {
-        return MoreObjects.toStringHelper(getClass())
-                .add("src", src)
-                .add("dst", dst)
-                .toString();
-    }
 }
diff --git a/core/api/src/main/java/org/onosproject/ui/topo/BiLink.java b/core/api/src/main/java/org/onosproject/ui/topo/BiLink.java
index 16e8dc5..b50e34d 100644
--- a/core/api/src/main/java/org/onosproject/ui/topo/BiLink.java
+++ b/core/api/src/main/java/org/onosproject/ui/topo/BiLink.java
@@ -38,7 +38,7 @@
      * that the caller will have used {@link TopoUtils#canonicalLinkKey(Link)}
      * to generate the key.
      *
-     * @param key canonical key for this bi-link
+     * @param key  canonical key for this bi-link
      * @param link first link
      */
     public BiLink(LinkKey key, Link link) {
@@ -62,7 +62,7 @@
      * @return link identifier
      */
     public String linkId() {
-        return TopoUtils.compactLinkString(one);
+        return key.asId();
     }
 
     /**
@@ -92,6 +92,11 @@
         return two;
     }
 
+    @Override
+    public String toString() {
+        return key.asId();
+    }
+
     /**
      * Returns the link highlighting to use, based on this bi-link's current
      * state.
diff --git a/core/api/src/test/java/org/onosproject/net/LinkKeyTest.java b/core/api/src/test/java/org/onosproject/net/LinkKeyTest.java
index 0b036be..075f165 100644
--- a/core/api/src/test/java/org/onosproject/net/LinkKeyTest.java
+++ b/core/api/src/test/java/org/onosproject/net/LinkKeyTest.java
@@ -126,4 +126,10 @@
                                    containsString("src=1/1"),
                                    containsString("dst=2/1}")));
     }
+
+    @Test
+    public void asId() {
+        LinkKey k1 = LinkKey.linkKey(SRC1, DST2);
+        assertThat(k1.asId(), is(equalTo("1/1-2/2")));
+    }
 }
diff --git a/core/api/src/test/java/org/onosproject/ui/topo/BiLinkTest.java b/core/api/src/test/java/org/onosproject/ui/topo/BiLinkTest.java
index e7c5048..df6d3f7 100644
--- a/core/api/src/test/java/org/onosproject/ui/topo/BiLinkTest.java
+++ b/core/api/src/test/java/org/onosproject/ui/topo/BiLinkTest.java
@@ -57,5 +57,25 @@
         blink = new ConcreteLink(KEY_AB, LINK_AB);
         blink.setOther(null);
     }
+
+    @Test
+    public void canonIdentifiers() {
+        // FIRST: an assumption that the LinkKey used is canonicalized
+        //        ( See TopoUtils.canonicalLinkKey(Link) )
+        //  so in both the following cases, KEY_AB is used...
+        String expected = CP_A1 + "-" + CP_B2;
+
+        // let's assume that link [A -> B] was dealt with first...
+        blink = new ConcreteLink(KEY_AB, LINK_AB);
+        blink.setOther(LINK_BA);
+        print(blink);
+        assertEquals("non-canon AB", expected, blink.linkId());
+
+        // let's assume that link [B -> A] was dealt with first...
+        blink = new ConcreteLink(KEY_AB, LINK_BA);
+        blink.setOther(LINK_AB);
+        print(blink);
+        assertEquals("non-canon BA", expected, blink.linkId());
+    }
 }
 
diff --git a/core/api/src/test/java/org/onosproject/ui/topo/BiLinkTestBase.java b/core/api/src/test/java/org/onosproject/ui/topo/BiLinkTestBase.java
index bcfd408..77b6858 100644
--- a/core/api/src/test/java/org/onosproject/ui/topo/BiLinkTestBase.java
+++ b/core/api/src/test/java/org/onosproject/ui/topo/BiLinkTestBase.java
@@ -24,11 +24,12 @@
 import org.onosproject.net.PortNumber;
 import org.onosproject.net.driver.Behaviour;
 import org.onosproject.net.provider.ProviderId;
+import org.onosproject.ui.AbstractUiTest;
 
 /**
  * Base class for unit tests of {@link BiLink} and {@link BiLinkMap}.
  */
-public abstract class BiLinkTestBase {
+public abstract class BiLinkTestBase extends AbstractUiTest {
 
     protected static class FakeLink implements Link {
         private final ConnectPoint src;
@@ -39,29 +40,43 @@
             this.dst = dst;
         }
 
-        @Override public ConnectPoint src() {
+        @Override
+        public ConnectPoint src() {
             return src;
         }
-        @Override public ConnectPoint dst() {
+
+        @Override
+        public ConnectPoint dst() {
             return dst;
         }
 
-        @Override public Type type() {
+        @Override
+        public Type type() {
             return null;
         }
-        @Override public State state() {
+
+        @Override
+        public State state() {
             return null;
         }
-        @Override public boolean isDurable() {
+
+        @Override
+        public boolean isDurable() {
             return false;
         }
-        @Override public boolean isExpected() {
+
+        @Override
+        public boolean isExpected() {
             return false;
         }
-        @Override public Annotations annotations() {
+
+        @Override
+        public Annotations annotations() {
             return null;
         }
-        @Override public ProviderId providerId() {
+
+        @Override
+        public ProviderId providerId() {
             return null;
         }
 
@@ -94,6 +109,7 @@
         public ConcreteLink(LinkKey key, Link link) {
             super(key, link);
         }
+
         @Override
         public LinkHighlight highlight(Enum<?> type) {
             return null;
@@ -107,5 +123,4 @@
         }
     }
 
-
 }
diff --git a/core/api/src/test/java/org/onosproject/ui/topo/TopoUtilsTest.java b/core/api/src/test/java/org/onosproject/ui/topo/TopoUtilsTest.java
index f7b56eb..e8712dc 100644
--- a/core/api/src/test/java/org/onosproject/ui/topo/TopoUtilsTest.java
+++ b/core/api/src/test/java/org/onosproject/ui/topo/TopoUtilsTest.java
@@ -22,6 +22,7 @@
 import org.onosproject.net.Link;
 import org.onosproject.net.LinkKey;
 import org.onosproject.net.provider.ProviderId;
+import org.onosproject.ui.AbstractUiTest;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -31,7 +32,7 @@
 /**
  * Unit tests for {@link TopoUtils}.
  */
-public class TopoUtilsTest {
+public class TopoUtilsTest extends AbstractUiTest {
     private static final String AM_WL = "wrong label";
     private static final String AM_WM = "wrong magnitude";
     private static final String AM_CL = "clipped?";
@@ -54,6 +55,21 @@
             .providerId(ProviderId.NONE)
             .build();
 
+    private static final Link LINK_7_TO_3 = DefaultLink.builder()
+            .src(deviceConnectPoint("of:0000000000000007/2"))
+            .dst(deviceConnectPoint("of:0000000000000003/2"))
+            .type(Link.Type.DIRECT)
+            .providerId(ProviderId.NONE)
+            .build();
+
+    private static final Link LINK_3_TO_7 = DefaultLink.builder()
+            .src(deviceConnectPoint("of:0000000000000003/2"))
+            .dst(deviceConnectPoint("of:0000000000000007/2"))
+            .type(Link.Type.DIRECT)
+            .providerId(ProviderId.NONE)
+            .build();
+
+
     private TopoUtils.ValueLabel vl;
 
     @Test
@@ -76,6 +92,15 @@
     }
 
     @Test
+    public void canon723() {
+        LinkKey lk1 = TopoUtils.canonicalLinkKey(LINK_7_TO_3);
+        print(lk1);
+        LinkKey lk2 = TopoUtils.canonicalLinkKey(LINK_3_TO_7);
+        print(lk2);
+        assertEquals("not canonical 3/7", lk1, lk2);
+    }
+
+    @Test
     public void formatSmallBytes() {
         vl = TopoUtils.formatBytes(1_000L);
         assertEquals(AM_WM, TopoUtils.Magnitude.ONE, vl.magnitude());
diff --git a/web/gui/logger.sh b/web/gui/logger.sh
index 13c5883..53c3ddad 100755
--- a/web/gui/logger.sh
+++ b/web/gui/logger.sh
@@ -10,7 +10,7 @@
 log:set DEBUG org.onosproject.ui.impl.topo.Topo2TrafficMessageHandler
 log:set DEBUG org.onosproject.ui.impl.topo.Traffic2Monitor
 
-#log:set DEBUG org.onosproject.ui.impl.UiWebSocket
+log:set DEBUG org.onosproject.ui.impl.UiWebSocket
 #log:set DEBUG org.onosproject.ui.impl.UiTopoSession
 
 log:list