Fix to enable adding INDIRECT link via BasicLinkConfig

- addConfig will create and 'advertise' a new default Config object.
  In the case of BasicLinkConfig, default link type will be DIRECT.
  Link subsystem ignores link transition from DIRECT to INDIRECT
  in order to prefer LLDP info over BDDP info.
  As a result it is difficult to create an INDIRECT link
  via Java API calls.

Change-Id: Id736f3a8332b7558387c3eb7598e1239779c6fe8
diff --git a/apps/newoptical/src/main/java/org/onosproject/newoptical/OpticalPathProvisioner.java b/apps/newoptical/src/main/java/org/onosproject/newoptical/OpticalPathProvisioner.java
index 1a0b54f..4a77e6a 100644
--- a/apps/newoptical/src/main/java/org/onosproject/newoptical/OpticalPathProvisioner.java
+++ b/apps/newoptical/src/main/java/org/onosproject/newoptical/OpticalPathProvisioner.java
@@ -43,6 +43,7 @@
 import org.onosproject.net.Device;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.Link;
+import org.onosproject.net.LinkKey;
 import org.onosproject.net.Path;
 import org.onosproject.net.Port;
 import org.onosproject.net.config.NetworkConfigService;
@@ -843,14 +844,26 @@
             // inject expected link or durable link
             // if packet device cannot advertise packet link
             try {
+                // cannot call addConfig.
+                // it will create default BasicLinkConfig,
+                // which will end up advertising DIRECT links and
+                // DIRECT Link type cannot transition from DIRECT to INDIRECT
+                LinkKey lnkKey = linkKey(packetSrc, packetDst);
                 BasicLinkConfig lnkCfg = networkConfigService
-                        .addConfig(linkKey(packetSrc, packetDst),
-                                   BasicLinkConfig.class);
+                        .getConfig(lnkKey, BasicLinkConfig.class);
+                if (lnkCfg == null) {
+                    lnkCfg = new BasicLinkConfig(lnkKey);
+                }
                 lnkCfg.isAllowed(true);
                 lnkCfg.isDurable(true);
                 lnkCfg.type(Link.Type.INDIRECT);
                 lnkCfg.isBidirectional(false);
-                lnkCfg.apply();
+                // cannot call apply against manually created instance
+                //lnkCfg.apply();
+                networkConfigService.applyConfig(lnkKey,
+                                                 BasicLinkConfig.class,
+                                                 lnkCfg.node());
+
             } catch (Exception ex) {
                 log.error("Applying BasicLinkConfig failed", ex);
             }
diff --git a/core/api/src/main/java/org/onosproject/net/config/basics/BasicLinkConfig.java b/core/api/src/main/java/org/onosproject/net/config/basics/BasicLinkConfig.java
index 6a5e026..e9fea14 100644
--- a/core/api/src/main/java/org/onosproject/net/config/basics/BasicLinkConfig.java
+++ b/core/api/src/main/java/org/onosproject/net/config/basics/BasicLinkConfig.java
@@ -16,8 +16,11 @@
 package org.onosproject.net.config.basics;
 
 import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
 import org.onosproject.net.Link;
 import org.onosproject.net.LinkKey;
+import org.onosproject.net.config.inject.DeviceInjectionConfig;
 
 import java.time.Duration;
 
@@ -28,6 +31,12 @@
  */
 public final class BasicLinkConfig extends AllowedEntityConfig<LinkKey> {
 
+    /**
+     * Configuration key for {@link DeviceInjectionConfig}.
+     */
+    public static final String CONFIG_KEY = "basic";
+
+
     public static final String TYPE = "type";
     public static final String METRIC = "metric";
     public static final String LATENCY = "latency";
@@ -167,4 +176,27 @@
     public BasicLinkConfig isBidirectional(Boolean isBidirectional) {
         return (BasicLinkConfig) setOrClear(IS_BIDIRECTIONAL, isBidirectional);
     }
+
+    /**
+     * Create a {@link BasicLinkConfig} for specified Device.
+     * <p>
+     * Note: created instance is not bound to NetworkConfigService,
+     * cannot use {@link #apply()}. Must be passed to the service
+     * using NetworkConfigService#applyConfig
+     *
+     * @param linkKey subject of this Config
+     */
+    public BasicLinkConfig(LinkKey linkKey) {
+        ObjectMapper mapper = new ObjectMapper();
+        init(linkKey, CONFIG_KEY, mapper.createObjectNode(), mapper, null);
+    }
+
+    /**
+     * Create a {@link BasicLinkConfig} instance.
+     * <p>
+     * Note: created instance needs to be initialized by #init(..) before using.
+     */
+    public BasicLinkConfig() {
+        super();
+    }
 }
diff --git a/core/net/src/main/java/org/onosproject/net/config/impl/BasicNetworkConfigs.java b/core/net/src/main/java/org/onosproject/net/config/impl/BasicNetworkConfigs.java
index 5cabfbd..630fc79 100644
--- a/core/net/src/main/java/org/onosproject/net/config/impl/BasicNetworkConfigs.java
+++ b/core/net/src/main/java/org/onosproject/net/config/impl/BasicNetworkConfigs.java
@@ -92,7 +92,7 @@
             },
             new ConfigFactory<LinkKey, BasicLinkConfig>(LINK_SUBJECT_FACTORY,
                     BasicLinkConfig.class,
-                    BASIC) {
+                    BasicLinkConfig.CONFIG_KEY) {
                 @Override
                 public BasicLinkConfig createConfig() {
                     return new BasicLinkConfig();