LinkStore bugfix. avoid DIRECT -> INDIRECT transition

Change-Id: If2a4c3e5e33f705a73374010cd7941167cef1aaf
diff --git a/core/store/dist/src/main/java/org/onlab/onos/store/link/impl/GossipLinkStore.java b/core/store/dist/src/main/java/org/onlab/onos/store/link/impl/GossipLinkStore.java
index 312d072..3693d59 100644
--- a/core/store/dist/src/main/java/org/onlab/onos/store/link/impl/GossipLinkStore.java
+++ b/core/store/dist/src/main/java/org/onlab/onos/store/link/impl/GossipLinkStore.java
@@ -23,9 +23,9 @@
 import org.onlab.onos.net.DefaultLink;
 import org.onlab.onos.net.DeviceId;
 import org.onlab.onos.net.Link;
-import org.onlab.onos.net.SparseAnnotations;
 import org.onlab.onos.net.Link.Type;
 import org.onlab.onos.net.LinkKey;
+import org.onlab.onos.net.SparseAnnotations;
 import org.onlab.onos.net.device.DeviceClockService;
 import org.onlab.onos.net.link.DefaultLinkDescription;
 import org.onlab.onos.net.link.LinkDescription;
@@ -263,8 +263,8 @@
             ProviderId providerId,
             Timestamped<LinkDescription> linkDescription) {
 
-        LinkKey key = linkKey(linkDescription.value().src(),
-                              linkDescription.value().dst());
+        final LinkKey key = linkKey(linkDescription.value().src(),
+                                    linkDescription.value().dst());
         Map<ProviderId, Timestamped<LinkDescription>> descs = getOrCreateLinkDescriptions(key);
 
         synchronized (descs) {
@@ -275,6 +275,7 @@
                 if (linkDescription.isNewer(linkRemovedTimestamp)) {
                     removedLinks.remove(key);
                 } else {
+                    log.trace("Link {} was already removed ignoring.", key);
                     return null;
                 }
             }
@@ -299,17 +300,25 @@
         // merge existing annotations
         Timestamped<LinkDescription> existingLinkDescription = descs.get(providerId);
         if (existingLinkDescription != null && existingLinkDescription.isNewer(linkDescription)) {
+            log.trace("local info is more up-to-date, ignoring {}.", linkDescription);
             return null;
         }
         Timestamped<LinkDescription> newLinkDescription = linkDescription;
         if (existingLinkDescription != null) {
+            // we only allow transition from INDIRECT -> DIRECT
+            final Type newType;
+            if (existingLinkDescription.value().type() == DIRECT) {
+                newType = DIRECT;
+            } else {
+                newType = linkDescription.value().type();
+            }
             SparseAnnotations merged = union(existingLinkDescription.value().annotations(),
                     linkDescription.value().annotations());
             newLinkDescription = new Timestamped<LinkDescription>(
                     new DefaultLinkDescription(
                         linkDescription.value().src(),
                         linkDescription.value().dst(),
-                        linkDescription.value().type(), merged),
+                        newType, merged),
                     linkDescription.timestamp());
         }
         return descs.put(providerId, newLinkDescription);
@@ -343,6 +352,8 @@
             return null;
         }
 
+        // Note: INDIRECT -> DIRECT transition only
+        // so that BDDP discovered Link will not overwrite LDDP Link
         if ((oldLink.type() == INDIRECT && newLink.type() == DIRECT) ||
             !AnnotationsUtil.isEqual(oldLink.annotations(), newLink.annotations())) {