Add device config change request using NetCfg

Change-Id: I01ae9caf298e606333ea31b2b480d744a2815c76
diff --git a/apps/odtn/service/src/main/java/org/onosproject/odtn/impl/ServiceApplicationComponent.java b/apps/odtn/service/src/main/java/org/onosproject/odtn/impl/ServiceApplicationComponent.java
index 48057c8..a663cc8 100644
--- a/apps/odtn/service/src/main/java/org/onosproject/odtn/impl/ServiceApplicationComponent.java
+++ b/apps/odtn/service/src/main/java/org/onosproject/odtn/impl/ServiceApplicationComponent.java
@@ -25,11 +25,13 @@
 import org.apache.felix.scr.annotations.Deactivate;
 import org.apache.felix.scr.annotations.Reference;
 import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.onosproject.net.ConnectPoint;
 import org.onosproject.net.Link;
+import org.onosproject.net.config.ConfigFactory;
 import org.onosproject.net.config.NetworkConfigEvent;
 import org.onosproject.net.config.NetworkConfigListener;
+import org.onosproject.net.config.NetworkConfigRegistry;
 import org.onosproject.net.config.NetworkConfigService;
-import org.onosproject.net.config.NetworkConfigStoreDelegate;
 import org.onosproject.net.device.DeviceEvent;
 import org.onosproject.net.device.DeviceListener;
 import org.onosproject.net.device.DeviceService;
@@ -38,15 +40,14 @@
 import org.onosproject.net.link.LinkService;
 import org.onosproject.odtn.TapiResolver;
 import org.onosproject.odtn.TapiTopologyManager;
+import org.onosproject.odtn.config.TerminalDeviceConfig;
 import org.onosproject.odtn.internal.DcsBasedTapiCommonRpc;
 import org.onosproject.odtn.internal.DcsBasedTapiConnectivityRpc;
 import org.onosproject.odtn.internal.DcsBasedTapiDataProducer;
 import org.onosproject.odtn.internal.TapiDataProducer;
-import org.onosproject.store.AbstractStore;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-
 // DCS / onos-yang-tools
 import org.onosproject.config.DynamicConfigEvent;
 import org.onosproject.config.DynamicConfigListener;
@@ -55,6 +56,10 @@
 
 import static org.onosproject.config.DynamicConfigEvent.Type.NODE_ADDED;
 import static org.onosproject.config.DynamicConfigEvent.Type.NODE_DELETED;
+import static org.onosproject.net.config.NetworkConfigEvent.Type.CONFIG_ADDED;
+import static org.onosproject.net.config.NetworkConfigEvent.Type.CONFIG_REMOVED;
+import static org.onosproject.net.config.NetworkConfigEvent.Type.CONFIG_UPDATED;
+import static org.onosproject.net.config.basics.SubjectFactories.CONNECT_POINT_SUBJECT_FACTORY;
 
 /**
  * OSGi Component for ODTN Service application.
@@ -77,6 +82,9 @@
     protected NetworkConfigService netcfgService;
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected NetworkConfigRegistry netcfgRegistry;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected RpcRegistry rpcRegistry;
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
@@ -93,12 +101,21 @@
     private final LinkListener linkListener = new InternalLinkListener();
     private final NetworkConfigListener netcfgListener = new InternalNetCfgListener();
     private TapiDataProducer dataProvider = new DcsBasedTapiDataProducer();
-    private InternalNetCfgManager netcfgStore = new InternalNetCfgManager();
 
     // Rpc Service for TAPI Connectivity
     private final DcsBasedTapiConnectivityRpc rpcTapiConnectivity = new DcsBasedTapiConnectivityRpc();
     private final DcsBasedTapiCommonRpc rpcTapiCommon = new DcsBasedTapiCommonRpc();
 
+    // FIXME create factory and register for all behaviours
+    private final ConfigFactory<ConnectPoint, TerminalDeviceConfig> factory =
+            new ConfigFactory<ConnectPoint, TerminalDeviceConfig>(CONNECT_POINT_SUBJECT_FACTORY,
+                    TerminalDeviceConfig.class, TerminalDeviceConfig.CONFIG_KEY) {
+                @Override
+                public TerminalDeviceConfig createConfig() {
+                    return new TerminalDeviceConfig();
+                }
+            };
+
 
     @Activate
     protected void activate() {
@@ -107,8 +124,10 @@
         deviceService.addListener(deviceListener);
         linkService.addListener(linkListener);
         netcfgService.addListener(netcfgListener);
+        netcfgRegistry.registerConfigFactory(factory);
         rpcRegistry.registerRpcService(rpcTapiConnectivity);
         rpcRegistry.registerRpcService(rpcTapiCommon);
+
         rpcTapiConnectivity.init();
         rpcTapiCommon.init();
     }
@@ -119,6 +138,7 @@
         log.info("Stopped");
         rpcRegistry.unregisterRpcService(rpcTapiCommon);
         rpcRegistry.unregisterRpcService(rpcTapiConnectivity);
+        netcfgRegistry.unregisterConfigFactory(factory);
         netcfgService.removeListener(netcfgListener);
         linkService.removeListener(linkListener);
         deviceService.removeListener(deviceListener);
@@ -139,8 +159,8 @@
         @Override
         public void event(DeviceEvent event) {
 
-            netcfgStore.post(event);
-
+            log.info("Device event type: {}", event.type());
+            log.info("Device event subject: {}", event.subject());
             switch (event.type()) {
                 case DEVICE_ADDED:
                     tapiTopologyManager.addDevice(event.subject());
@@ -196,30 +216,40 @@
     private class InternalNetCfgListener implements NetworkConfigListener {
 
         /**
+         * Check if the netcfg event should be further processed.
+         *
+         * @param event config event
+         * @return true if event is supported; false otherwise
+         */
+        @Override
+        public boolean isRelevant(NetworkConfigEvent event) {
+
+            if (event.type() == CONFIG_ADDED || event.type() == CONFIG_UPDATED) {
+                if (event.config().orElse(null) instanceof TerminalDeviceConfig) {
+                    return true;
+                }
+            }
+            if (event.type() == CONFIG_REMOVED) {
+                if (event.prevConfig().orElse(null) instanceof TerminalDeviceConfig) {
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        /**
          * Process an Event from the NetCfg Service.
          *
-         * @param event link event
+         * @param event event
          */
         @Override
         public void event(NetworkConfigEvent event) {
-//            Object config = event.subject();
-            log.info("config: {}", event.subject());
+
             log.info("type: {}", event.type());
+            log.info("subject: {}", event.subject());
         }
     }
 
-    private class InternalNetCfgManager
-        extends AbstractStore<NetworkConfigEvent, NetworkConfigStoreDelegate> {
-
-        public void post(Object obj) {
-            log.info("Post netcfg event : {}", obj);
-            NetworkConfigEvent.Type type = NetworkConfigEvent.Type.CONFIG_UPDATED;
-            notifyDelegate(new NetworkConfigEvent(type, obj, obj.getClass()));
-        }
-
-    }
-
-
     /**
      * Representation of internal listener, listening for dynamic config event.
      */
@@ -273,7 +303,6 @@
 //            }
         }
 
-
 //        /**
 //         * Process the event that a node has been added to the DCS.
 //         *
@@ -298,14 +327,13 @@
 //            NodeKey dataNodeKey = node.key();
 //            SchemaId schemaId = dataNodeKey.schemaId();
 
-            // Consolidate events
+        // Consolidate events
 //            if (!schemaId.namespace().contains("tapi")) {
 //                return;
 //            }
 //            log.info("namespace {}", schemaId.namespace());
 //        }
 
-
 //        /**
 //         * Process the event that a node has been deleted from the DCS.
 //         *
@@ -317,7 +345,4 @@
 
     }
 
-
-
-
 }
diff --git a/apps/odtn/service/src/main/java/org/onosproject/odtn/internal/DcsBasedTapiConnectionManager.java b/apps/odtn/service/src/main/java/org/onosproject/odtn/internal/DcsBasedTapiConnectionManager.java
index 6ddb662..b585506 100644
--- a/apps/odtn/service/src/main/java/org/onosproject/odtn/internal/DcsBasedTapiConnectionManager.java
+++ b/apps/odtn/service/src/main/java/org/onosproject/odtn/internal/DcsBasedTapiConnectionManager.java
@@ -17,15 +17,22 @@
 package org.onosproject.odtn.internal;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 
+import java.util.concurrent.atomic.AtomicReference;
 import org.onosproject.config.FailedException;
-import org.onosproject.net.device.DeviceService;
+import org.onosproject.net.config.NetworkConfigService;
+import org.onosproject.odtn.TapiResolver;
+import org.onosproject.odtn.behaviour.OdtnDeviceDescriptionDiscovery;
+import org.onosproject.odtn.utils.tapi.DcsBasedTapiObjectRefFactory;
+import org.onosproject.odtn.utils.tapi.TapiCepPair;
 import org.onosproject.odtn.utils.tapi.TapiConnection;
 import org.onosproject.odtn.utils.tapi.TapiNepPair;
 import org.onosproject.odtn.utils.tapi.TapiCepRefHandler;
 import org.onosproject.odtn.utils.tapi.TapiConnectionHandler;
 
+import org.onosproject.odtn.utils.tapi.TapiNepRef;
 import org.onosproject.odtn.utils.tapi.TapiRouteHandler;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -35,13 +42,15 @@
 /**
  * DCS-dependent Tapi connection manager implementation.
  */
-public class DcsBasedTapiConnectionManager implements TapiConnectionManager {
+public final class DcsBasedTapiConnectionManager implements TapiConnectionManager {
 
     private final Logger log = LoggerFactory.getLogger(getClass());
     protected TapiPathComputer connectionController;
-    private DeviceService deviceService;
+    private TapiResolver resolver;
+    private NetworkConfigService netcfgService;
 
     private List<DcsBasedTapiConnectionManager> connectionManagerList = new ArrayList<>();
+    private TapiConnection connection = null;
     private TapiConnectionHandler connectionHandler = TapiConnectionHandler.create();
     private Operation op = null;
 
@@ -51,10 +60,14 @@
         DELETE
     }
 
+    private DcsBasedTapiConnectionManager() {
+    }
+
     public static DcsBasedTapiConnectionManager create() {
         DcsBasedTapiConnectionManager self = new DcsBasedTapiConnectionManager();
         self.connectionController = DefaultTapiPathComputer.create();
-        self.deviceService = getService(DeviceService.class);
+        self.resolver = getService(TapiResolver.class);
+        self.netcfgService = getService(NetworkConfigService.class);
         return self;
     }
 
@@ -72,22 +85,20 @@
     @Override
     public void deleteConnection(TapiConnectionHandler connectionHandler) {
 
-        // read target to be deleted
-        this.connectionHandler = connectionHandler;
-        this.connectionHandler.read();
-        log.info("model: {}", connectionHandler.getModelObject());
-
         deleteConnectionRecursively(connectionHandler);
     }
 
     @Override
     public void apply() {
         connectionManagerList.forEach(DcsBasedTapiConnectionManager::apply);
+
         switch (op) {
             case CREATE:
+                notifyDeviceConfigChange(true);
                 connectionHandler.add();
                 break;
             case DELETE:
+                notifyDeviceConfigChange(false);
                 connectionHandler.remove();
                 break;
             default:
@@ -96,6 +107,37 @@
     }
 
     /**
+     * Emit NetworkConfig event with parameters for device config,
+     * to notify configuration change to device drivers.
+     */
+    private void notifyDeviceConfigChange(boolean enable) {
+        if (!this.connection.getCeps().isSameNode()) {
+            return;
+        }
+
+        TapiNepRef left = this.connection.getCeps().left().getNepRef();
+        TapiNepRef right = this.connection.getCeps().right().getNepRef();
+
+        // update with latest data in DCS
+        left = resolver.getNepRef(left);
+        right = resolver.getNepRef(right);
+
+        AtomicReference<TapiNepRef> line = new AtomicReference<>();
+        AtomicReference<TapiNepRef> client = new AtomicReference<>();
+        Arrays.asList(left, right).forEach(nep -> {
+            if (nep.getPortType() == OdtnDeviceDescriptionDiscovery.OdtnPortType.LINE) {
+                line.set(nep);
+            }
+            if (nep.getPortType() == OdtnDeviceDescriptionDiscovery.OdtnPortType.CLIENT) {
+                client.set(nep);
+            }
+        });
+
+        DeviceConfigEventEmitter eventEmitter = DeviceConfigEventEmitter.create();
+        eventEmitter.emit(line.get(), client.get(), enable);
+    }
+
+    /**
      * Generate TAPI connection and its under connections recursively
      * and add them to creation queue.
      *
@@ -104,6 +146,7 @@
     private void createConnectionRecursively(TapiConnection connection) {
         op = Operation.CREATE;
         connectionManagerList.clear();
+        this.connection = connection;
 
         TapiRouteHandler routeBuilder = TapiRouteHandler.create();
 
@@ -136,6 +179,16 @@
         op = Operation.DELETE;
         connectionManagerList.clear();
 
+        // read target to be deleted
+        connectionHandler.read();
+        log.info("model: {}", connectionHandler.getModelObject());
+
+        this.connection = TapiConnection.create(
+                TapiCepPair.create(
+                        DcsBasedTapiObjectRefFactory.create(connectionHandler.getCeps().get(0)),
+                        DcsBasedTapiObjectRefFactory.create(connectionHandler.getCeps().get(1)))
+        );
+
         this.connectionHandler = connectionHandler;
         this.connectionHandler.getLowerConnections().forEach(lowerConnectionHandler -> {
             delegateConnectionDeletion(lowerConnectionHandler);
@@ -157,7 +210,7 @@
     /**
      * Delegate lower-connection deletion to other corresponding TapiConnectionManager of each Nodes.
      *
-     * @param connectionHandler  connectionHandler of connection to be deleted
+     * @param connectionHandler connectionHandler of connection to be deleted
      */
     private void delegateConnectionDeletion(TapiConnectionHandler connectionHandler) {
         log.info("model: {}", connectionHandler.getModelObject());
diff --git a/apps/odtn/service/src/main/java/org/onosproject/odtn/internal/DcsBasedTapiDataProducer.java b/apps/odtn/service/src/main/java/org/onosproject/odtn/internal/DcsBasedTapiDataProducer.java
index 726d002..4adc3d2 100644
--- a/apps/odtn/service/src/main/java/org/onosproject/odtn/internal/DcsBasedTapiDataProducer.java
+++ b/apps/odtn/service/src/main/java/org/onosproject/odtn/internal/DcsBasedTapiDataProducer.java
@@ -27,8 +27,7 @@
 import org.onosproject.config.Filter;
 import org.onosproject.net.ConnectPoint;
 import org.onosproject.net.DeviceId;
-import org.onosproject.odtn.utils.tapi.DcsBasedTapiNepRef;
-import org.onosproject.odtn.utils.tapi.DcsBasedTapiNodeRef;
+import org.onosproject.odtn.utils.tapi.DcsBasedTapiObjectRefFactory;
 import org.onosproject.odtn.utils.tapi.TapiNepRef;
 import org.onosproject.odtn.utils.tapi.TapiNodeRef;
 import org.onosproject.yang.gen.v1.tapicommon.rev20180307.tapicommon.DefaultContext;
@@ -122,7 +121,7 @@
         }
         return topology.node().stream()
                 .map(node -> {
-                    DcsBasedTapiNodeRef nodeRef = DcsBasedTapiNodeRef.create(topology, node);
+                    TapiNodeRef nodeRef = DcsBasedTapiObjectRefFactory.create(topology, node);
                     if (node.name() != null) {
                         String deviceId = node.name().stream()
                                 .filter(kv -> kv.valueName().equals(DEVICE_ID))
@@ -155,7 +154,7 @@
                             }
                             return node.ownedNodeEdgePoint().stream()
                                     .map(nep -> {
-                                        TapiNepRef nepRef = DcsBasedTapiNepRef.create(topology, node, nep);
+                                        TapiNepRef nepRef = DcsBasedTapiObjectRefFactory.create(topology, node, nep);
                                         if (nep.name() != null) {
                                             Map<String, String> kvs = new HashMap<>();
                                             nep.name().forEach(kv -> kvs.put(kv.valueName(), kv.value()));
diff --git a/apps/odtn/service/src/main/java/org/onosproject/odtn/internal/DeviceConfigEventEmitter.java b/apps/odtn/service/src/main/java/org/onosproject/odtn/internal/DeviceConfigEventEmitter.java
new file mode 100644
index 0000000..32121ae
--- /dev/null
+++ b/apps/odtn/service/src/main/java/org/onosproject/odtn/internal/DeviceConfigEventEmitter.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * 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.odtn.internal;
+
+import org.onosproject.net.config.NetworkConfigService;
+import org.onosproject.odtn.config.TerminalDeviceConfig;
+import org.onosproject.odtn.utils.tapi.TapiNepRef;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import static org.onlab.osgi.DefaultServiceDirectory.getService;
+
+public final class DeviceConfigEventEmitter {
+
+    private final Logger log = LoggerFactory.getLogger(getClass());
+
+    private NetworkConfigService netcfgService;
+
+    private DeviceConfigEventEmitter() {
+    }
+
+    public static DeviceConfigEventEmitter create() {
+        DeviceConfigEventEmitter self = new DeviceConfigEventEmitter();
+        self.netcfgService = getService(NetworkConfigService.class);
+        return self;
+    }
+
+    /**
+     * Emit NetworkConfig event with parameters for device config.
+     *
+     * @param line   side NodeEdgePoint of connection
+     * @param client side NodeEdgePoint of connection
+     * @param enable or disable
+     */
+    public void emit(TapiNepRef line, TapiNepRef client, boolean enable) {
+
+        // FIXME Config class should be implemented as behaviour to support
+        //       multi device types.
+        TerminalDeviceConfig cfg = TerminalDeviceConfig.create(line, client);
+        if (enable) {
+            cfg.enable();
+        } else {
+            cfg.disable();
+        }
+        netcfgService.applyConfig(line.getConnectPoint(), TerminalDeviceConfig.class, cfg.node());
+    }
+
+}