From 240073b8341f4141ee7bd01e4f0fd691a932579f Mon Sep 17 00:00:00 2001
From: highstreetherbert <herbert.eiselt@highstreet-technologies.com>
Date: Thu, 16 Jul 2020 16:50:21 +0200
Subject: SDN-R Sodium compliant netconfnode-state-service and devicemanager

Adapted tests

Issue-ID: CCSDK-2570
Signed-off-by: highstreetherbert <herbert.eiselt@highstreet-technologies.com>
Change-Id: I38e6f987f022a530e9e2851dd09eed32e7273fef
Signed-off-by: highstreetherbert <herbert.eiselt@highstreet-technologies.com>
---
 .../impl/NetconfAccessorImpl.java                  |  27 +-
 .../impl/NetconfAccessorManager.java               |  60 +++++
 .../impl/NetconfNodeStateServiceImpl.java          | 280 ++++++++++++---------
 .../impl/conf/NetconfStateConfig.java              |  82 ++++++
 4 files changed, 322 insertions(+), 127 deletions(-)
 create mode 100644 sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/NetconfAccessorManager.java
 create mode 100644 sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/conf/NetconfStateConfig.java

(limited to 'sdnr/wt/netconfnode-state-service/provider/src/main/java')

diff --git a/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/NetconfAccessorImpl.java b/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/NetconfAccessorImpl.java
index 433b34e49..275da397d 100644
--- a/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/NetconfAccessorImpl.java
+++ b/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/NetconfAccessorImpl.java
@@ -1,8 +1,8 @@
-/**
+/*
  * ============LICENSE_START========================================================================
  * ONAP : ccsdk feature sdnr wt
  * =================================================================================================
- * Copyright (C) 2019 highstreet technologies GmbH Intellectual Property. All rights reserved.
+ * Copyright (C) 2020 highstreet technologies GmbH Intellectual Property. All rights reserved.
  * =================================================================================================
  * 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
@@ -36,12 +36,18 @@ import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netconf.notification.
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netconf.notification._1._0.rev080714.StreamNameType;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNode;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNodeConnectionStatus.ConnectionStatus;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.network.topology.topology.topology.types.TopologyNetconf;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
 import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.binding.NotificationListener;
+import org.opendaylight.yangtools.yang.common.RpcError.ErrorType;
 import org.opendaylight.yangtools.yang.common.RpcResult;
 import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
-import org.opendaylight.yangtools.yang.common.RpcError.ErrorType;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -49,6 +55,10 @@ public class NetconfAccessorImpl implements NetconfAccessor {
 
     private static final Logger log = LoggerFactory.getLogger(NetconfAccessorImpl.class);
 
+    private static final @NonNull InstanceIdentifier<Topology> NETCONF_TOPO_IID =
+            InstanceIdentifier.create(NetworkTopology.class).child(Topology.class,
+                    new TopologyKey(new TopologyId(TopologyNetconf.QNAME.getLocalName())));
+
     private final NodeId nodeId;
     private final DataBroker dataBroker;
     private final TransactionUtils transactionUtils;
@@ -58,7 +68,7 @@ public class NetconfAccessorImpl implements NetconfAccessor {
 
     /**
      * Contains all data to access and manage netconf device
-     * 
+     *
      * @param nodeId of managed netconf node
      * @param netconfNode information
      * @param dataBroker to access node
@@ -75,7 +85,14 @@ public class NetconfAccessorImpl implements NetconfAccessor {
         this.transactionUtils = transactionUtils;
 
         ConnectionStatus csts = netconfNode != null ? netconfNode.getConnectionStatus() : null;
-        this.capabilities = Capabilities.getAvailableCapabilities(csts != null ? netconfNode : null);
+        if (csts == null) {
+            throw new IllegalStateException(String.format("connection status for %s is not connected", nodeId));
+        }
+        Capabilities tmp = Capabilities.getAvailableCapabilities(netconfNode);
+        if (tmp.getCapabilities().size() <= 0) {
+            throw new IllegalStateException(String.format("no capabilities found for %s", nodeId));
+        }
+        this.capabilities = tmp;
     }
 
     /**
diff --git a/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/NetconfAccessorManager.java b/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/NetconfAccessorManager.java
new file mode 100644
index 000000000..9fad32477
--- /dev/null
+++ b/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/NetconfAccessorManager.java
@@ -0,0 +1,60 @@
+/*
+ * ============LICENSE_START========================================================================
+ * ONAP : ccsdk feature sdnr wt
+ * =================================================================================================
+ * Copyright (C) 2019 highstreet technologies GmbH Intellectual Property. All rights reserved.
+ * =================================================================================================
+ * 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.
+ * ============LICENSE_END==========================================================================
+ */
+package org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.impl;
+
+import java.util.Objects;
+import java.util.concurrent.ConcurrentHashMap;
+import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.NetconfAccessor;
+import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.TransactionUtils;
+import org.opendaylight.mdsal.binding.api.DataBroker;
+import org.opendaylight.mdsal.binding.api.MountPoint;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNode;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class NetconfAccessorManager {
+
+    private static final Logger log = LoggerFactory.getLogger(NetconfNodeStateServiceImpl.class);
+
+    private static final TransactionUtils TRANSACTIONUTILS = new GenericTransactionUtils();
+    private final ConcurrentHashMap<String, NetconfAccessorImpl> accessorList;
+
+    public NetconfAccessorManager() {
+        accessorList = new ConcurrentHashMap<>();
+    }
+
+    public NetconfAccessor getAccessor(NodeId nNodeId, NetconfNode netconfNode, DataBroker netconfNodeDataBroker,
+            MountPoint mountPoint) {
+        NetconfAccessorImpl res =
+                new NetconfAccessorImpl(nNodeId, netconfNode, netconfNodeDataBroker, mountPoint, TRANSACTIONUTILS);
+        NetconfAccessor previouse = accessorList.put(nNodeId.getValue(), res);
+        if (Objects.nonNull(previouse)) {
+            log.warn("Accessor with name already available. Replaced with new one.");
+        }
+        return res;
+    }
+
+    public boolean containes(NodeId nNodeId) {
+        return accessorList.containsKey(nNodeId.getValue());
+    }
+
+    public void removeAccessor(NodeId nNodeId) {
+        accessorList.remove(nNodeId.getValue());
+    }
+}
diff --git a/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/NetconfNodeStateServiceImpl.java b/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/NetconfNodeStateServiceImpl.java
index c190346c4..15a274dc4 100644
--- a/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/NetconfNodeStateServiceImpl.java
+++ b/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/NetconfNodeStateServiceImpl.java
@@ -18,21 +18,26 @@
 package org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.impl;
 
 import java.util.Collection;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.Optional;
 import java.util.concurrent.CopyOnWriteArrayList;
-
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
 import javax.annotation.Nullable;
 
 import org.eclipse.jdt.annotation.NonNull;
+import org.onap.ccsdk.features.sdnr.wt.common.configuration.ConfigurationFileRepresentation;
+import org.onap.ccsdk.features.sdnr.wt.common.configuration.filechange.IConfigChangedListener;
 import org.onap.ccsdk.features.sdnr.wt.dataprovider.model.IEntityDataProvider;
 import org.onap.ccsdk.features.sdnr.wt.dataprovider.model.StatusChangedHandler.StatusKey;
 import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.NetconfAccessor;
 import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.NetconfNodeConnectListener;
 import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.NetconfNodeStateListener;
 import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.NetconfNodeStateService;
-import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.TransactionUtils;
 import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.VesNotificationListener;
+import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.impl.conf.NetconfStateConfig;
 import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.impl.conf.odlAkka.AkkaConfig;
 import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.impl.conf.odlAkka.ClusterConfig;
 import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.impl.conf.odlGeo.GeoConfig;
@@ -70,14 +75,14 @@ import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-public class NetconfNodeStateServiceImpl implements NetconfNodeStateService, RpcApigetStateCallback, AutoCloseable {
+public class NetconfNodeStateServiceImpl
+        implements NetconfNodeStateService, RpcApigetStateCallback, AutoCloseable, IConfigChangedListener {
 
     private static final Logger LOG = LoggerFactory.getLogger(NetconfNodeStateServiceImpl.class);
     private static final String APPLICATION_NAME = "NetconfNodeStateService";
     @SuppressWarnings("unused")
     private static final String CONFIGURATIONFILE = "etc/netconfnode-status-service.properties";
 
-
     @SuppressWarnings("null")
     private static final @NonNull InstanceIdentifier<Topology> NETCONF_TOPO_IID =
             InstanceIdentifier.create(NetworkTopology.class).child(Topology.class,
@@ -94,7 +99,6 @@ public class NetconfNodeStateServiceImpl implements NetconfNodeStateService, Rpc
 
     // Name of ODL controller NETCONF instance
     private static final NodeId CONTROLLER = new NodeId("controller-config");
-    private static final TransactionUtils TRANSACTIONUTILS = new GenericTransactionUtils();
 
     // -- OSGi services, provided
     private DataBroker dataBroker;
@@ -117,6 +121,9 @@ public class NetconfNodeStateServiceImpl implements NetconfNodeStateService, Rpc
     /** Indication if init() function called and fully executed **/
     private Boolean initializationSuccessful;
 
+    /** Manager accessor objects for connection **/
+    private final NetconfAccessorManager accessorManager;
+
     /** List of all registered listeners **/
     private final List<NetconfNodeConnectListener> netconfNodeConnectListenerList;
 
@@ -132,6 +139,14 @@ public class NetconfNodeStateServiceImpl implements NetconfNodeStateService, Rpc
     /** Indicates the name of the cluster **/
     private String clusterName;
 
+    /** nodeId to threadPool (size=1) for datatreechange handling) **/
+    private final Map<String, ExecutorService> handlingPool;
+
+    private boolean handleDataTreeAsync;
+
+    private ConfigurationFileRepresentation configFileRepresentation;
+    private NetconfStateConfig config;
+
     /** Blueprint **/
     public NetconfNodeStateServiceImpl() {
         LOG.info("Creating provider for {}", APPLICATION_NAME);
@@ -148,6 +163,9 @@ public class NetconfNodeStateServiceImpl implements NetconfNodeStateService, Rpc
         this.netconfNodeConnectListenerList = new CopyOnWriteArrayList<>();
         this.netconfNodeStateListenerList = new CopyOnWriteArrayList<>();
         this.vesNotificationListenerList = new CopyOnWriteArrayList<>();
+        this.accessorManager = new NetconfAccessorManager();
+        this.handlingPool = new HashMap<>();
+
     }
 
     public void setDataBroker(DataBroker dataBroker) {
@@ -182,7 +200,11 @@ public class NetconfNodeStateServiceImpl implements NetconfNodeStateService, Rpc
         // Start RPC Service
         this.rpcApiService = new NetconfnodeStateServiceRpcApiImpl(rpcProviderRegistry, vesNotificationListenerList);
         // Get configuration
-        // ConfigurationFileRepresentation config = new ConfigurationFileRepresentation(CONFIGURATIONFILE);
+        this.configFileRepresentation = new ConfigurationFileRepresentation(CONFIGURATIONFILE);
+        this.config = new NetconfStateConfig(this.configFileRepresentation);
+        this.handleDataTreeAsync = this.config.handleAsync();
+        this.configFileRepresentation.registerConfigChangedListener(this);
+
         // Akka setup
         AkkaConfig akkaConfig = getAkkaConfig();
         this.isCluster = akkaConfig == null ? false : akkaConfig.isCluster();
@@ -312,6 +334,7 @@ public class NetconfNodeStateServiceImpl implements NetconfNodeStateService, Rpc
                 element.close();
             }
         }
+        this.configFileRepresentation.unregisterConfigChangedListener(this);
     }
 
     /**
@@ -359,23 +382,15 @@ public class NetconfNodeStateServiceImpl implements NetconfNodeStateService, Rpc
             InstanceIdentifier<Node> instanceIdentifier =
                     NETCONF_TOPO_IID.child(Node.class, new NodeKey(new NodeId(mountPointNodeName)));
 
-            Optional<MountPoint> optionalMountPoint = null;
-            int timeout = 10000;
-            while (!(optionalMountPoint = mountPointService.getMountPoint(instanceIdentifier)).isPresent()
-                    && timeout > 0) {
-                LOG.info("Event listener waiting for mount point for Netconf device :: Name : {}", mountPointNodeName);
-                sleepMs(1000);
-                timeout -= 1000;
-            }
-
+            Optional<MountPoint> optionalMountPoint = mountPointService.getMountPoint(instanceIdentifier);
             if (!optionalMountPoint.isPresent()) {
-                LOG.warn("Event listener timeout while waiting for mount point for Netconf device :: Name : {} ",
-                        mountPointNodeName);
+                LOG.warn("No mountpoint available for Netconf device :: Name : {} ", mountPointNodeName);
             } else {
                 // Mountpoint is present for sure
                 MountPoint mountPoint = optionalMountPoint.get();
                 // BindingDOMDataBrokerAdapter.BUILDER_FACTORY;
-                LOG.info("Mountpoint with id: {}", mountPoint.getIdentifier());
+                LOG.info("Mountpoint with id: {} class:{}", mountPoint.getIdentifier(),
+                        mountPoint.getClass().getName());
 
                 Optional<DataBroker> optionalNetconfNodeDatabroker = mountPoint.getService(DataBroker.class);
 
@@ -384,8 +399,8 @@ public class NetconfNodeStateServiceImpl implements NetconfNodeStateService, Rpc
                 } else {
                     LOG.info("Master mountpoint {}", mountPointNodeName);
                     DataBroker netconfNodeDataBroker = optionalNetconfNodeDatabroker.get();
-                    NetconfAccessor acessor = new NetconfAccessorImpl(nNodeId, netconfNode, netconfNodeDataBroker,
-                            mountPoint, TRANSACTIONUTILS);
+                    NetconfAccessor acessor =
+                            accessorManager.getAccessor(nNodeId, netconfNode, netconfNodeDataBroker, mountPoint);
                     /*
                      * --> Call Listers for onConnect() Indication
                        for (all)
@@ -413,125 +428,152 @@ public class NetconfNodeStateServiceImpl implements NetconfNodeStateService, Rpc
      */
     private void leaveConnectedState(NodeId nNodeId, Optional<NetconfNode> optionalNetconfNode) {
         String mountPointNodeName = nNodeId.getValue();
-        LOG.info("netconfNode id {}", mountPointNodeName);
-
-        InstanceIdentifier<Node> instanceIdentifier =
-                NETCONF_TOPO_IID.child(Node.class, new NodeKey(new NodeId(mountPointNodeName)));
-        Optional<MountPoint> optionalMountPoint = mountPointService.getMountPoint(instanceIdentifier);
-        if (optionalMountPoint.isPresent()) {
-            Optional<DataBroker> optionalNetconfNodeDatabroker = optionalMountPoint.get().getService(DataBroker.class);
-            if (optionalNetconfNodeDatabroker.isPresent()) {
-                LOG.info("Master mountpoint {}", mountPointNodeName);
-                netconfNodeConnectListenerList.forEach(item -> {
-                    try {
-                        if (item != null) {
-                            item.onLeaveConnected(nNodeId, optionalNetconfNode);
-                        } else {
-                            LOG.warn("Unexpeced null item during onleave");
+        LOG.info("leaveConnectedState id {}", mountPointNodeName);
+
+        if (this.accessorManager.containes(nNodeId)) {
+            netconfNodeConnectListenerList.forEach(item -> {
+                try {
+                    if (item != null) {
+                        item.onLeaveConnected(nNodeId, optionalNetconfNode);
+                    } else {
+                        LOG.warn("Unexpeced null item during onleave");
+                    }
+                } catch (Exception e) {
+                    LOG.info("Exception during onLeaveConnected listener call", e);
+                }
+            });
+            LOG.info("Remove Master mountpoint {}", mountPointNodeName);
+            this.accessorManager.removeAccessor(nNodeId);
+        } else {
+            LOG.info("Master mountpoint already removed {}", mountPointNodeName);
+        }
+    }
+
+    // ---- onDataTreeChangedHandler
+
+    private void handleDataTreeChange(DataObjectModification<Node> root, NodeId nodeId,
+            ModificationType modificationTyp) {
+        // Move status into boolean flags for
+        boolean connectedBefore, connectedAfter, created;
+        NetconfNode nNodeAfter = getNetconfNode(root.getDataAfter());
+        connectedAfter = isConnected(nNodeAfter);
+        if (root.getDataBefore() != null) {
+            // It is an update or delete
+            NetconfNode nodeBefore = getNetconfNode(root.getDataBefore());
+            connectedBefore = isConnected(nodeBefore);
+            created = false;
+        } else {
+            // It is a create
+            connectedBefore = false;
+            created = true;
+        }
+        LOG.info("L1 NETCONF id:{} t:{} created {} before:{} after:{} akkaIsCluster:{} cl stat:{}", nodeId,
+                modificationTyp, created, connectedBefore, connectedAfter, isCluster,
+                getClusteredConnectionStatus(nNodeAfter));
+        switch (modificationTyp) {
+            case SUBTREE_MODIFIED: // Create or modify sub level node
+            case WRITE: // Create or modify top level node
+                // Treat an overwrite as an update
+                // leaveConnected state.before = connected; state.after != connected
+                // enterConnected state.after == connected
+                // => Here create or update by checking root.getDataBefore() != null
+                boolean handled = false;
+                if (created) {
+                    handled = true;
+                    netconfNodeStateListenerList.forEach(item -> {
+                        try {
+                            item.onCreated(nodeId, nNodeAfter);
+                        } catch (Exception e) {
+                            LOG.info("Exception during onCreated listener call", e);
                         }
+                    });
+                }
+                if (!connectedBefore && connectedAfter) {
+                    handled = true;
+                    enterConnectedState(nodeId, nNodeAfter);
+                }
+                if (connectedBefore && !connectedAfter) {
+                    handled = true;
+                    leaveConnectedState(nodeId, Optional.of(nNodeAfter));
+                }
+                if (!handled) {
+                    //Change if not handled by the messages before
+                    netconfNodeStateListenerList.forEach(item -> {
+                        try {
+                            item.onStateChange(nodeId, nNodeAfter);
+                        } catch (Exception e) {
+                            LOG.info("Exception during onStateChange listener call", e);
+                        }
+                    });
+                }
+                // doProcessing(update ? Action.UPDATE : Action.CREATE, nodeId, root);
+                break;
+            case DELETE:
+                // Node removed
+                // leaveconnected state.before = connected;
+                if (!connectedBefore) {
+                    leaveConnectedState(nodeId, Optional.empty());
+                }
+                netconfNodeStateListenerList.forEach(item -> {
+                    try {
+                        item.onRemoved(nodeId);
                     } catch (Exception e) {
-                        LOG.info("Exception during onLeaveConnected listener call", e);
+                        LOG.info("Exception during onRemoved listener call", e);
                     }
                 });
-            }
+                // doProcessing(Action.REMOVE, nodeId, root);
+                break;
         }
     }
 
-    // ---- onDataTreeChangedHandler
-
     private void onDataTreeChangedHandler(@NonNull Collection<DataTreeModification<Node>> changes) {
         for (final DataTreeModification<Node> change : changes) {
 
             final DataObjectModification<Node> root = change.getRootNode();
-            //if (LOG.isTraceEnabled()) {
-            LOG.info /*trace*/("Handle this modificationType:{} path:{} root:{}", root.getModificationType(),
-                    change.getRootPath(), root);
-            //}
+            if (LOG.isTraceEnabled()) {
+                LOG.trace("Handle this modificationType:{} path:{} root:{}", root.getModificationType(),
+                        change.getRootPath(), root);
+            }
 
             // Catch potential nullpointer exceptions ..
             try {
                 ModificationType modificationTyp = root.getModificationType();
                 Node node = modificationTyp == ModificationType.DELETE ? root.getDataBefore() : root.getDataAfter();
                 NodeId nodeId = node != null ? node.getNodeId() : null;
-                if (nodeId != null) {
+                if (nodeId == null) {
+                    LOG.warn("L1 without nodeid.");
+                } else {
                     if (nodeId.equals(CONTROLLER)) {
                         // Do not forward any controller related events to devicemanager
                         LOG.debug("Stop processing for [{}]", nodeId);
                     } else {
-                        if (modificationTyp != null) {
-                            switch (modificationTyp) {
-                                case SUBTREE_MODIFIED: // Create or modify sub level node
-                                case WRITE: // Create or modify top level node
-                                    // Treat an overwrite as an update
-                                    // leaveconnected state.before = connected; state.after != connected
-                                    // enterConnected state.after == connected
-                                    // => Here create or update by checking root.getDataBefore() != null
-
-                                    boolean connectedBefore, connectedAfter, created = false;
-                                    NetconfNode nNodeAfter = getNetconfNode(root.getDataAfter());
-                                    connectedAfter = isConnected(nNodeAfter);
-                                    if (root.getDataBefore() != null) {
-                                        // It is an update
-                                        NetconfNode nodeBefore = getNetconfNode(root.getDataBefore());
-                                        connectedBefore = isConnected(nodeBefore);
-                                    } else {
-                                        // It is a create
-                                        connectedBefore = false;
-                                        created = true;
+                        if (modificationTyp == null) {
+                            LOG.warn("L1 empty modification type");
+                        } else {
+                            if (this.handleDataTreeAsync) {
+                                ExecutorService executor = this.handlingPool.getOrDefault(nodeId.getValue(), null);
+                                if (executor == null) {
+                                    executor = Executors.newFixedThreadPool(5);
+                                    this.handlingPool.put(nodeId.getValue(), executor);
+                                }
+                                executor.execute(new Thread() {
+                                    @Override
+                                    public void run() {
+                                        handleDataTreeChange(root, nodeId, modificationTyp);
                                     }
+                                });
 
-                                    LOG.info(
-                                            "L1 NETCONF Node change with id:{} ConnectedBefore:{} connectedAfter {}:cluster status:{} akkaIsCluster:{}",
-                                            nodeId, connectedBefore, connectedAfter,
-                                            getClusteredConnectionStatus(nNodeAfter), isCluster);
-
-                                    if (created) {
-                                        netconfNodeStateListenerList.forEach(item -> {
-                                            try {
-                                                item.onCreated(nodeId, nNodeAfter);
-                                            } catch (Exception e) {
-                                                LOG.info("Exception during onCreated listener call", e);
-                                            }
-                                        });
-                                    }
-                                    if (!connectedBefore && connectedAfter) {
-                                        enterConnectedState(nodeId, nNodeAfter);
-                                    } else {
-                                        LOG.debug("State change {} {}", connectedBefore, connectedAfter);
-                                        if (connectedBefore && !connectedAfter) {
-                                            leaveConnectedState(nodeId, Optional.of(nNodeAfter));
-                                        }
-                                        netconfNodeStateListenerList.forEach(item -> {
-                                            try {
-                                                item.onStateChange(nodeId, nNodeAfter);
-                                            } catch (Exception e) {
-                                                LOG.info("Exception during onStateChange listener call", e);
-                                            }
-                                        });
-                                    }
-                                    // doProcessing(update ? Action.UPDATE : Action.CREATE, nodeId, root);
-                                    break;
-                                case DELETE:
-                                    // Node removed
-                                    // leaveconnected state.before = connected;
-                                    leaveConnectedState(nodeId, Optional.empty());
-                                    netconfNodeStateListenerList.forEach(item -> {
-                                        try {
-                                            item.onRemoved(nodeId);
-                                        } catch (Exception e) {
-                                            LOG.info("Exception during onRemoved listener call", e);
-                                        }
-                                    });
-                                    // doProcessing(Action.REMOVE, nodeId, root);
-                                    break;
+                            } else {
+                                handleDataTreeChange(root, nodeId, modificationTyp);
                             }
                         }
                     }
                 }
-            } catch (NullPointerException e) {
+            } catch (NullPointerException | IllegalStateException e) {
                 LOG.info("Data not available at ", e);
             }
         } //for
+        LOG.info("datatreechanged handler completed");
     }
 
     // ---- subclasses for listeners
@@ -543,7 +585,8 @@ public class NetconfNodeStateServiceImpl implements NetconfNodeStateService, Rpc
         @Override
         public void onDataTreeChanged(@NonNull Collection<DataTreeModification<Node>> changes) {
             LOG.info("L1 TreeChange enter changes:{}", changes.size());
-            new Thread(() -> onDataTreeChangedHandler(changes)).start();
+            //Debug AkkTimeout NetconfNodeStateServiceImpl.this.pool.execute(new Thread( () -> onDataTreeChangedHandler(changes)));
+            onDataTreeChangedHandler(changes);
             LOG.info("L1 TreeChange leave");
         }
     }
@@ -612,8 +655,8 @@ public class NetconfNodeStateServiceImpl implements NetconfNodeStateService, Rpc
             @NonNull
             String masterNodeName =
                     ccs == null || ccs.getNetconfMasterNode() == null ? "null" : ccs.getNetconfMasterNode();
-            LOG.debug("sdnMasterNode=" + masterNodeName + " and sdnMyNode=" + this.clusterName);
-            if (!masterNodeName.equals(this.clusterName)) {
+            LOG.debug("sdnMasterNode=" + masterNodeName + " and sdnMyNode=" + clusterName);
+            if (!masterNodeName.equals(clusterName)) {
                 LOG.debug("netconf change but me is not master for this node");
                 return false;
             }
@@ -621,16 +664,9 @@ public class NetconfNodeStateServiceImpl implements NetconfNodeStateService, Rpc
         return true;
     }
 
+    @Override
+    public void onConfigChanged() {
+        this.handleDataTreeAsync = this.config.handleAsync();
 
-    private void sleepMs(int milliseconds) {
-        try {
-            Thread.sleep(milliseconds);
-        } catch (InterruptedException e) {
-            LOG.debug("Interrupted sleep");
-            // Restore interrupted state...
-            Thread.currentThread().interrupt();
-        }
     }
-
-
 }
diff --git a/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/conf/NetconfStateConfig.java b/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/conf/NetconfStateConfig.java
new file mode 100644
index 000000000..117e0892f
--- /dev/null
+++ b/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/conf/NetconfStateConfig.java
@@ -0,0 +1,82 @@
+/*
+ * ============LICENSE_START=======================================================
+ * ONAP : ccsdk features
+ * ================================================================================
+ * Copyright (C) 2020 highstreet technologies GmbH Intellectual Property.
+ * All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ *
+ */
+package org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.impl.conf;
+
+/**
+ * @author Michael Dürre
+ *
+ */
+
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.onap.ccsdk.features.sdnr.wt.common.configuration.Configuration;
+import org.onap.ccsdk.features.sdnr.wt.common.configuration.ConfigurationFileRepresentation;
+import org.onap.ccsdk.features.sdnr.wt.common.configuration.filechange.IConfigChangedListener;
+import org.onap.ccsdk.features.sdnr.wt.common.database.config.HostInfo;
+import org.onap.ccsdk.features.sdnr.wt.common.database.config.HostInfo.Protocol;
+import org.onap.ccsdk.features.sdnr.wt.dataprovider.model.IEsConfig;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class NetconfStateConfig implements Configuration {
+
+    private static final Logger LOG = LoggerFactory.getLogger(NetconfStateConfig.class);
+
+    public static final String SECTION_MARKER_NCSTATE = "netconfstate";
+
+    private static final String PROPERTY_KEY_HANDLEASYNC = "asynchandling";
+
+    private static final Object DEFAULT_VALUE_TRUSTALLCERTS = false;
+
+
+
+    private final ConfigurationFileRepresentation configuration;
+
+    public NetconfStateConfig(ConfigurationFileRepresentation configuration) {
+
+        this.configuration = configuration;
+        this.configuration.addSection(SECTION_MARKER_NCSTATE);
+        defaults();
+    }
+
+
+    public boolean handleAsync() {
+        return configuration.getPropertyBoolean(SECTION_MARKER_NCSTATE, PROPERTY_KEY_HANDLEASYNC);
+    }
+
+    @Override
+    public String getSectionName() {
+        return SECTION_MARKER_NCSTATE;
+    }
+
+    @Override
+    public synchronized void defaults() {
+        // Add default if not available  
+        configuration.setPropertyIfNotAvailable(SECTION_MARKER_NCSTATE, PROPERTY_KEY_HANDLEASYNC,
+                DEFAULT_VALUE_TRUSTALLCERTS);
+
+    }
+}
-- 
cgit