2  * ============LICENSE_START========================================================================
 
   3  * ONAP : ccsdk feature sdnr wt
 
   4  * =================================================================================================
 
   5  * Copyright (C) 2019 highstreet technologies GmbH Intellectual Property. All rights reserved.
 
   6  * =================================================================================================
 
   7  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
 
   8  * in compliance with the License. You may obtain a copy of the License at
 
  10  * http://www.apache.org/licenses/LICENSE-2.0
 
  12  * Unless required by applicable law or agreed to in writing, software distributed under the License
 
  13  * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
 
  14  * or implied. See the License for the specific language governing permissions and limitations under
 
  16  * ============LICENSE_END==========================================================================
 
  18 package org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.impl;
 
  20 import java.util.Collection;
 
  21 import java.util.List;
 
  22 import java.util.Optional;
 
  23 import java.util.concurrent.CopyOnWriteArrayList;
 
  25 import javax.annotation.Nullable;
 
  27 import org.eclipse.jdt.annotation.NonNull;
 
  28 import org.onap.ccsdk.features.sdnr.wt.dataprovider.model.IEntityDataProvider;
 
  29 import org.onap.ccsdk.features.sdnr.wt.dataprovider.model.StatusChangedHandler.StatusKey;
 
  30 import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.NetconfAccessor;
 
  31 import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.NetconfNodeConnectListener;
 
  32 import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.NetconfNodeStateListener;
 
  33 import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.NetconfNodeStateService;
 
  34 import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.TransactionUtils;
 
  35 import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.VesNotificationListener;
 
  36 import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.impl.conf.odlAkka.AkkaConfig;
 
  37 import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.impl.conf.odlAkka.ClusterConfig;
 
  38 import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.impl.conf.odlGeo.GeoConfig;
 
  39 import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.impl.rpc.NetconfnodeStateServiceRpcApiImpl;
 
  40 import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.impl.rpc.RpcApigetStateCallback;
 
  41 import org.opendaylight.mdsal.binding.api.ClusteredDataTreeChangeListener;
 
  42 import org.opendaylight.mdsal.binding.api.DataBroker;
 
  43 import org.opendaylight.mdsal.binding.api.DataObjectModification;
 
  44 import org.opendaylight.mdsal.binding.api.DataObjectModification.ModificationType;
 
  45 import org.opendaylight.mdsal.binding.api.DataTreeChangeListener;
 
  46 import org.opendaylight.mdsal.binding.api.DataTreeIdentifier;
 
  47 import org.opendaylight.mdsal.binding.api.DataTreeModification;
 
  48 import org.opendaylight.mdsal.binding.api.MountPoint;
 
  49 import org.opendaylight.mdsal.binding.api.MountPointService;
 
  50 import org.opendaylight.mdsal.binding.api.NotificationPublishService;
 
  51 import org.opendaylight.mdsal.binding.api.RpcProviderService;
 
  52 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
 
  53 import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceProvider;
 
  54 import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceRegistration;
 
  55 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNode;
 
  56 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNodeConnectionStatus.ConnectionStatus;
 
  57 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.connection.status.ClusteredConnectionStatus;
 
  58 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.network.topology.topology.topology.types.TopologyNetconf;
 
  59 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netconfnode.state.rev191011.GetStatusInput;
 
  60 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netconfnode.state.rev191011.GetStatusOutputBuilder;
 
  61 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
 
  62 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
 
  63 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
 
  64 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
 
  65 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
 
  66 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
 
  67 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey;
 
  68 import org.opendaylight.yangtools.concepts.ListenerRegistration;
 
  69 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 
  70 import org.slf4j.Logger;
 
  71 import org.slf4j.LoggerFactory;
 
  73 public class NetconfNodeStateServiceImpl implements NetconfNodeStateService, RpcApigetStateCallback, AutoCloseable {
 
  75     private static final Logger LOG = LoggerFactory.getLogger(NetconfNodeStateServiceImpl.class);
 
  76     private static final String APPLICATION_NAME = "NetconfNodeStateService";
 
  77     @SuppressWarnings("unused")
 
  78     private static final String CONFIGURATIONFILE = "etc/netconfnode-status-service.properties";
 
  81     @SuppressWarnings("null")
 
  82     private static final @NonNull InstanceIdentifier<Topology> NETCONF_TOPO_IID =
 
  83             InstanceIdentifier.create(NetworkTopology.class).child(Topology.class,
 
  84                     new TopologyKey(new TopologyId(TopologyNetconf.QNAME.getLocalName())));
 
  86     @SuppressWarnings("null")
 
  87     private static final @NonNull InstanceIdentifier<Node> NETCONF_NODE_TOPO_IID =
 
  88             InstanceIdentifier.create(NetworkTopology.class)
 
  89                     .child(Topology.class, new TopologyKey(new TopologyId(TopologyNetconf.QNAME.getLocalName())))
 
  92     private static final DataTreeIdentifier<Node> NETCONF_NODE_TOPO_TREE_ID =
 
  93             DataTreeIdentifier.create(LogicalDatastoreType.OPERATIONAL, NETCONF_NODE_TOPO_IID);
 
  95     // Name of ODL controller NETCONF instance
 
  96     private static final NodeId CONTROLLER = new NodeId("controller-config");
 
  97     private static final TransactionUtils TRANSACTIONUTILS = new GenericTransactionUtils();
 
  99     // -- OSGi services, provided
 
 100     private DataBroker dataBroker;
 
 101     private MountPointService mountPointService;
 
 102     private RpcProviderService rpcProviderRegistry;
 
 103     private IEntityDataProvider iEntityDataProvider;
 
 104     @SuppressWarnings("unused")
 
 105     private NotificationPublishService notificationPublishService;
 
 106     @SuppressWarnings("unused")
 
 107     private ClusterSingletonServiceProvider clusterSingletonServiceProvider;
 
 110     private ListenerRegistration<L1> listenerL1;
 
 111     private ListenerRegistration<L2> listenerL2;
 
 112     @SuppressWarnings("unused")
 
 113     private ClusterSingletonServiceRegistration cssRegistration;
 
 115     private NetconfnodeStateServiceRpcApiImpl rpcApiService;
 
 117     /** Indication if init() function called and fully executed **/
 
 118     private Boolean initializationSuccessful;
 
 120     /** List of all registered listeners **/
 
 121     private final List<NetconfNodeConnectListener> netconfNodeConnectListenerList;
 
 123     /** List of all registered listeners **/
 
 124     private final List<NetconfNodeStateListener> netconfNodeStateListenerList;
 
 126     /** List of all registered listeners **/
 
 127     private final List<VesNotificationListener> vesNotificationListenerList;
 
 129     /** Indicates if running in cluster configuration **/
 
 130     private boolean isCluster;
 
 132     /** Indicates the name of the cluster **/
 
 133     private String clusterName;
 
 136     public NetconfNodeStateServiceImpl() {
 
 137         LOG.info("Creating provider for {}", APPLICATION_NAME);
 
 139         this.dataBroker = null;
 
 140         this.mountPointService = null;
 
 141         this.rpcProviderRegistry = null;
 
 142         this.notificationPublishService = null;
 
 143         this.clusterSingletonServiceProvider = null;
 
 145         this.listenerL1 = null;
 
 146         this.listenerL2 = null;
 
 147         this.initializationSuccessful = false;
 
 148         this.netconfNodeConnectListenerList = new CopyOnWriteArrayList<>();
 
 149         this.netconfNodeStateListenerList = new CopyOnWriteArrayList<>();
 
 150         this.vesNotificationListenerList = new CopyOnWriteArrayList<>();
 
 153     public void setDataBroker(DataBroker dataBroker) {
 
 154         this.dataBroker = dataBroker;
 
 157     public void setRpcProviderRegistry(RpcProviderService rpcProviderRegistry) {
 
 158         this.rpcProviderRegistry = rpcProviderRegistry;
 
 161     public void setNotificationPublishService(NotificationPublishService notificationPublishService) {
 
 162         this.notificationPublishService = notificationPublishService;
 
 165     public void setMountPointService(MountPointService mountPointService) {
 
 166         this.mountPointService = mountPointService;
 
 169     public void setClusterSingletonService(ClusterSingletonServiceProvider clusterSingletonService) {
 
 170         this.clusterSingletonServiceProvider = clusterSingletonService;
 
 173     public void setEntityDataProvider(IEntityDataProvider iEntityDataProvider) {
 
 174         this.iEntityDataProvider = iEntityDataProvider;
 
 177     /** Blueprint initialization **/
 
 180         LOG.info("Session Initiated start {}", APPLICATION_NAME);
 
 183         this.rpcApiService = new NetconfnodeStateServiceRpcApiImpl(rpcProviderRegistry, vesNotificationListenerList);
 
 185         // ConfigurationFileRepresentation config = new ConfigurationFileRepresentation(CONFIGURATIONFILE);
 
 187         AkkaConfig akkaConfig = getAkkaConfig();
 
 188         this.isCluster = akkaConfig == null ? false : akkaConfig.isCluster();
 
 189         this.clusterName = akkaConfig == null ? "" : akkaConfig.getClusterConfig().getClusterSeedNodeName("abc");
 
 191         // Provide status information
 
 192         ClusterConfig cc = akkaConfig == null ? null : akkaConfig.getClusterConfig();
 
 193         this.iEntityDataProvider.setStatus(StatusKey.CLUSTER_SIZE,
 
 194                 cc == null ? "1" : String.format("%d", cc.getClusterSize()));
 
 196         // RPC Service for specific services
 
 197         this.rpcApiService.setStatusCallback(this);
 
 199         LOG.debug("start NetconfSubscriptionManager Service");
 
 200         //this.netconfChangeListener = new NetconfChangeListener(this, dataBroker);
 
 201         //this.netconfChangeListener.register();
 
 202         //DataTreeIdentifier<Node> treeId = new DataTreeIdentifier<>(LogicalDatastoreType.OPERATIONAL, NETCONF_NODE_TOPO_IID);
 
 204         listenerL1 = dataBroker.registerDataTreeChangeListener(NETCONF_NODE_TOPO_TREE_ID, new L1());
 
 205         listenerL2 = dataBroker.registerDataTreeChangeListener(NETCONF_NODE_TOPO_TREE_ID, new L2());
 
 207         this.initializationSuccessful = true;
 
 209         LOG.info("Session Initiated end. Initialization done {}", initializationSuccessful);
 
 213     /** Blueprint destroy-method method */
 
 214     public void destroy() {
 
 221      * @return NetconfnodeStateServiceRpcApiImpl
 
 223     public NetconfnodeStateServiceRpcApiImpl getNetconfnodeStateServiceRpcApiImpl() {
 
 224         return rpcApiService;
 
 228     public GetStatusOutputBuilder getStatus(GetStatusInput input) {
 
 229         return new GetStatusOutputBuilder();
 
 233     public <L extends NetconfNodeConnectListener> @NonNull ListenerRegistration<L> registerNetconfNodeConnectListener(
 
 234             final @NonNull L netconfNodeConnectListener) {
 
 235         LOG.info("Register connect listener {}", netconfNodeConnectListener.getClass().getName());
 
 236         netconfNodeConnectListenerList.add(netconfNodeConnectListener);
 
 238         return new ListenerRegistration<L>() {
 
 240             public @NonNull L getInstance() {
 
 241                 return netconfNodeConnectListener;
 
 245             public void close() {
 
 246                 LOG.info("Remove connect listener {}", netconfNodeConnectListener);
 
 247                 netconfNodeConnectListenerList.remove(netconfNodeConnectListener);
 
 253     public <L extends NetconfNodeStateListener> @NonNull ListenerRegistration<L> registerNetconfNodeStateListener(
 
 254             @NonNull L netconfNodeStateListener) {
 
 255         LOG.info("Register state listener {}", netconfNodeStateListener.getClass().getName());
 
 256         netconfNodeStateListenerList.add(netconfNodeStateListener);
 
 258         return new ListenerRegistration<L>() {
 
 260             public @NonNull L getInstance() {
 
 261                 return netconfNodeStateListener;
 
 265             public void close() {
 
 266                 LOG.info("Remove state listener {}", netconfNodeStateListener);
 
 267                 netconfNodeStateListenerList.remove(netconfNodeStateListener);
 
 273     public <L extends VesNotificationListener> @NonNull ListenerRegistration<L> registerVesNotifications(
 
 274             @NonNull L vesNotificationListener) {
 
 275         LOG.info("Register Ves notification listener {}", vesNotificationListener.getClass().getName());
 
 276         vesNotificationListenerList.add(vesNotificationListener);
 
 278         return new ListenerRegistration<L>() {
 
 280             public @NonNull L getInstance() {
 
 281                 return vesNotificationListener;
 
 285             public void close() {
 
 286                 LOG.info("Remove Ves notification listener {}", vesNotificationListener);
 
 287                 vesNotificationListenerList.remove(vesNotificationListener);
 
 293     public void close() {
 
 294         LOG.info("Closing start ...");
 
 296             close(rpcApiService, listenerL1, listenerL2);
 
 297         } catch (Exception e) {
 
 298             LOG.debug("Closing", e);
 
 300         LOG.info("Closing done");
 
 304      * Used to close all Services, that should support AutoCloseable Pattern
 
 309     private void close(AutoCloseable... toCloseList) throws Exception {
 
 310         for (AutoCloseable element : toCloseList) {
 
 311             if (element != null) {
 
 318      * Indication if init() of this bundle successfully done.
 
 320      * @return true if init() was successful. False if not done or not successful.
 
 322     public boolean isInitializationSuccessful() {
 
 323         return this.initializationSuccessful;
 
 326     /*-------------------------------------------------------------------------------------------
 
 327      * Functions for interface DeviceManagerService
 
 331      * For each mounted device a mountpoint is created and this listener is called. Mountpoint was created or existing.
 
 332      * Managed device is now fully connected to node/mountpoint.
 
 334      * @param nNodeId id of the mountpoint
 
 335      * @param netconfNode mountpoint contents
 
 337     private void enterConnectedState(NodeId nNodeId, NetconfNode netconfNode) {
 
 339         String mountPointNodeName = nNodeId.getValue();
 
 340         LOG.info("Access connected state for mountpoint {}", mountPointNodeName);
 
 342         boolean preConditionMissing = false;
 
 343         if (mountPointService == null) {
 
 344             preConditionMissing = true;
 
 345             LOG.warn("No mountservice available.");
 
 347         if (!initializationSuccessful) {
 
 348             preConditionMissing = true;
 
 349             LOG.warn("Devicemanager initialization still pending.");
 
 351         if (preConditionMissing) {
 
 355         boolean isNetconfNodeMaster = isNetconfNodeMaster(netconfNode);
 
 356         LOG.info("isNetconfNodeMaster indication {} for mountpoint {}", isNetconfNodeMaster, mountPointNodeName);
 
 357         if (isNetconfNodeMaster) {
 
 359             InstanceIdentifier<Node> instanceIdentifier =
 
 360                     NETCONF_TOPO_IID.child(Node.class, new NodeKey(new NodeId(mountPointNodeName)));
 
 362             Optional<MountPoint> optionalMountPoint = null;
 
 364             while (!(optionalMountPoint = mountPointService.getMountPoint(instanceIdentifier)).isPresent()
 
 366                 LOG.info("Event listener waiting for mount point for Netconf device :: Name : {}", mountPointNodeName);
 
 371             if (!optionalMountPoint.isPresent()) {
 
 372                 LOG.warn("Event listener timeout while waiting for mount point for Netconf device :: Name : {} ",
 
 375                 // Mountpoint is present for sure
 
 376                 MountPoint mountPoint = optionalMountPoint.get();
 
 377                 // BindingDOMDataBrokerAdapter.BUILDER_FACTORY;
 
 378                 LOG.info("Mountpoint with id: {}", mountPoint.getIdentifier());
 
 380                 Optional<DataBroker> optionalNetconfNodeDatabroker = mountPoint.getService(DataBroker.class);
 
 382                 if (!optionalNetconfNodeDatabroker.isPresent()) {
 
 383                     LOG.info("Slave mountpoint {} without databroker", mountPointNodeName);
 
 385                     LOG.info("Master mountpoint {}", mountPointNodeName);
 
 386                     DataBroker netconfNodeDataBroker = optionalNetconfNodeDatabroker.get();
 
 387                     NetconfAccessor acessor = new NetconfAccessorImpl(nNodeId, netconfNode, netconfNodeDataBroker,
 
 388                             mountPoint, TRANSACTIONUTILS);
 
 390                      * --> Call Listers for onConnect() Indication
 
 393                     netconfNodeConnectListenerList.forEach(item -> {
 
 395                             item.onEnterConnected(acessor);
 
 396                         } catch (Exception e) {
 
 397                             LOG.info("Exception during onEnterConnected listener call", e);
 
 401                     LOG.info("Connect indication forwarded for {}", mountPointNodeName);
 
 408      * Leave the connected status to a non connected or removed status for master mountpoint
 
 410      * @param action that occurred
 
 411      * @param nNodeId id of the mountpoint
 
 412      * @param netconfNode mountpoint contents or not available on remove
 
 414     private void leaveConnectedState(NodeId nNodeId, Optional<NetconfNode> optionalNetconfNode) {
 
 415         String mountPointNodeName = nNodeId.getValue();
 
 416         LOG.info("netconfNode id {}", mountPointNodeName);
 
 418         InstanceIdentifier<Node> instanceIdentifier =
 
 419                 NETCONF_TOPO_IID.child(Node.class, new NodeKey(new NodeId(mountPointNodeName)));
 
 420         Optional<MountPoint> optionalMountPoint = mountPointService.getMountPoint(instanceIdentifier);
 
 421         if (optionalMountPoint.isPresent()) {
 
 422             Optional<DataBroker> optionalNetconfNodeDatabroker = optionalMountPoint.get().getService(DataBroker.class);
 
 423             if (optionalNetconfNodeDatabroker.isPresent()) {
 
 424                 LOG.info("Master mountpoint {}", mountPointNodeName);
 
 425                 netconfNodeConnectListenerList.forEach(item -> {
 
 428                             item.onLeaveConnected(nNodeId, optionalNetconfNode);
 
 430                             LOG.warn("Unexpeced null item during onleave");
 
 432                     } catch (Exception e) {
 
 433                         LOG.info("Exception during onLeaveConnected listener call", e);
 
 440     // ---- onDataTreeChangedHandler
 
 442     private void onDataTreeChangedHandler(@NonNull Collection<DataTreeModification<Node>> changes) {
 
 443         for (final DataTreeModification<Node> change : changes) {
 
 445             final DataObjectModification<Node> root = change.getRootNode();
 
 446             //if (LOG.isTraceEnabled()) {
 
 447             LOG.info /*trace*/("Handle this modificationType:{} path:{} root:{}", root.getModificationType(),
 
 448                     change.getRootPath(), root);
 
 451             // Catch potential nullpointer exceptions ..
 
 453                 ModificationType modificationTyp = root.getModificationType();
 
 454                 Node node = modificationTyp == ModificationType.DELETE ? root.getDataBefore() : root.getDataAfter();
 
 455                 NodeId nodeId = node != null ? node.getNodeId() : null;
 
 456                 if (nodeId != null) {
 
 457                     if (nodeId.equals(CONTROLLER)) {
 
 458                         // Do not forward any controller related events to devicemanager
 
 459                         LOG.debug("Stop processing for [{}]", nodeId);
 
 461                         if (modificationTyp != null) {
 
 462                             switch (modificationTyp) {
 
 463                                 case SUBTREE_MODIFIED: // Create or modify sub level node
 
 464                                 case WRITE: // Create or modify top level node
 
 465                                     // Treat an overwrite as an update
 
 466                                     // leaveconnected state.before = connected; state.after != connected
 
 467                                     // enterConnected state.after == connected
 
 468                                     // => Here create or update by checking root.getDataBefore() != null
 
 470                                     boolean connectedBefore, connectedAfter, created = false;
 
 471                                     NetconfNode nNodeAfter = getNetconfNode(root.getDataAfter());
 
 472                                     connectedAfter = isConnected(nNodeAfter);
 
 473                                     if (root.getDataBefore() != null) {
 
 475                                         NetconfNode nodeBefore = getNetconfNode(root.getDataBefore());
 
 476                                         connectedBefore = isConnected(nodeBefore);
 
 479                                         connectedBefore = false;
 
 484                                             "L1 NETCONF Node change with id:{} ConnectedBefore:{} connectedAfter {}:cluster status:{} akkaIsCluster:{}",
 
 485                                             nodeId, connectedBefore, connectedAfter,
 
 486                                             getClusteredConnectionStatus(nNodeAfter), isCluster);
 
 489                                         netconfNodeStateListenerList.forEach(item -> {
 
 491                                                 item.onCreated(nodeId, nNodeAfter);
 
 492                                             } catch (Exception e) {
 
 493                                                 LOG.info("Exception during onCreated listener call", e);
 
 497                                     if (!connectedBefore && connectedAfter) {
 
 498                                         enterConnectedState(nodeId, nNodeAfter);
 
 500                                         LOG.debug("State change {} {}", connectedBefore, connectedAfter);
 
 501                                         if (connectedBefore && !connectedAfter) {
 
 502                                             leaveConnectedState(nodeId, Optional.of(nNodeAfter));
 
 504                                         netconfNodeStateListenerList.forEach(item -> {
 
 506                                                 item.onStateChange(nodeId, nNodeAfter);
 
 507                                             } catch (Exception e) {
 
 508                                                 LOG.info("Exception during onStateChange listener call", e);
 
 512                                     // doProcessing(update ? Action.UPDATE : Action.CREATE, nodeId, root);
 
 516                                     // leaveconnected state.before = connected;
 
 517                                     leaveConnectedState(nodeId, Optional.empty());
 
 518                                     netconfNodeStateListenerList.forEach(item -> {
 
 520                                             item.onRemoved(nodeId);
 
 521                                         } catch (Exception e) {
 
 522                                             LOG.info("Exception during onRemoved listener call", e);
 
 525                                     // doProcessing(Action.REMOVE, nodeId, root);
 
 531             } catch (NullPointerException e) {
 
 532                 LOG.info("Data not available at ", e);
 
 537     // ---- subclasses for listeners
 
 540      * Clustered listener function to select the right node from DataObjectModification. Called at all nodes.
 
 542     private class L1 implements ClusteredDataTreeChangeListener<Node> {
 
 544         public void onDataTreeChanged(@NonNull Collection<DataTreeModification<Node>> changes) {
 
 545             LOG.info("L1 TreeChange enter changes:{}", changes.size());
 
 546             new Thread(() -> onDataTreeChangedHandler(changes)).start();
 
 547             LOG.info("L1 TreeChange leave");
 
 552      * Data change, called at leader/master
 
 554     private class L2 implements DataTreeChangeListener<Node> {
 
 557         public void onDataTreeChanged(@NonNull Collection<DataTreeModification<Node>> changes) {
 
 558             LOG.info("L2 TreeChange enter changes:{}", changes.size());
 
 560             LOG.info("L2 TreeChange leave");
 
 564     /* --- private helpers --- */
 
 565     private static @Nullable NetconfNode getNetconfNode(Node node) {
 
 566         return node != null ? node.augmentation(NetconfNode.class) : null;
 
 569     private static boolean isConnected(NetconfNode nNode) {
 
 570         return nNode != null ? ConnectionStatus.Connected.equals(nNode.getConnectionStatus()) : false;
 
 573     private static @Nullable ClusteredConnectionStatus getClusteredConnectionStatus(NetconfNode node) {
 
 574         return node != null ? node.getClusteredConnectionStatus() : null;
 
 577     /* -- LOG related functions -- */
 
 579     /** Analyze configuration **/
 
 580     private static @Nullable AkkaConfig getAkkaConfig() {
 
 581         AkkaConfig akkaConfig;
 
 583             akkaConfig = AkkaConfig.load();
 
 584             LOG.debug("akka.conf loaded: " + akkaConfig.toString());
 
 585         } catch (Exception e1) {
 
 587             LOG.warn("problem loading akka.conf: " + e1.getMessage());
 
 589         if (akkaConfig != null && akkaConfig.isCluster()) {
 
 590             LOG.info("cluster mode detected");
 
 591             if (GeoConfig.fileExists()) {
 
 593                     LOG.debug("try to load geoconfig");
 
 595                 } catch (Exception err) {
 
 596                     LOG.warn("problem loading geoconfig: " + err.getMessage());
 
 599                 LOG.debug("no geoconfig file found");
 
 602             LOG.info("single node mode detected");
 
 607     private boolean isNetconfNodeMaster(NetconfNode nNode) {
 
 608         if (this.isCluster) {
 
 609             LOG.debug("check if me is responsible for node");
 
 610             ClusteredConnectionStatus ccs = nNode.getClusteredConnectionStatus();
 
 611             @SuppressWarnings("null")
 
 613             String masterNodeName =
 
 614                     ccs == null || ccs.getNetconfMasterNode() == null ? "null" : ccs.getNetconfMasterNode();
 
 615             LOG.debug("sdnMasterNode=" + masterNodeName + " and sdnMyNode=" + this.clusterName);
 
 616             if (!masterNodeName.equals(this.clusterName)) {
 
 617                 LOG.debug("netconf change but me is not master for this node");
 
 625     private void sleepMs(int milliseconds) {
 
 627             Thread.sleep(milliseconds);
 
 628         } catch (InterruptedException e) {
 
 629             LOG.debug("Interrupted sleep");
 
 630             // Restore interrupted state...
 
 631             Thread.currentThread().interrupt();