Merge "Reformat sdnr netconfnode-state-service to ONAP code style"
[ccsdk/features.git] / sdnr / wt / netconfnode-state-service / provider / src / main / java / org / onap / ccsdk / features / sdnr / wt / netconfnodestateservice / impl / NetconfNodeStateServiceImpl.java
1 /*
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
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
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
15  * the License.
16  * ============LICENSE_END==========================================================================
17  */
18 package org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.impl;
19
20 import java.util.Collection;
21 import java.util.List;
22 import java.util.Optional;
23 import java.util.concurrent.CopyOnWriteArrayList;
24
25 import javax.annotation.Nullable;
26
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;
72
73 public class NetconfNodeStateServiceImpl implements NetconfNodeStateService, RpcApigetStateCallback, AutoCloseable {
74
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";
79
80
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())));
85
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())))
90                     .child(Node.class);
91
92     private static final DataTreeIdentifier<Node> NETCONF_NODE_TOPO_TREE_ID =
93             DataTreeIdentifier.create(LogicalDatastoreType.OPERATIONAL, NETCONF_NODE_TOPO_IID);
94
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();
98
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;
108
109     // -- Parameter
110     private ListenerRegistration<L1> listenerL1;
111     private ListenerRegistration<L2> listenerL2;
112     @SuppressWarnings("unused")
113     private ClusterSingletonServiceRegistration cssRegistration;
114
115     private NetconfnodeStateServiceRpcApiImpl rpcApiService;
116
117     /** Indication if init() function called and fully executed **/
118     private Boolean initializationSuccessful;
119
120     /** List of all registered listeners **/
121     private final List<NetconfNodeConnectListener> netconfNodeConnectListenerList;
122
123     /** List of all registered listeners **/
124     private final List<NetconfNodeStateListener> netconfNodeStateListenerList;
125
126     /** List of all registered listeners **/
127     private final List<VesNotificationListener> vesNotificationListenerList;
128
129     /** Indicates if running in cluster configuration **/
130     private boolean isCluster;
131
132     /** Indicates the name of the cluster **/
133     private String clusterName;
134
135     /** Blueprint **/
136     public NetconfNodeStateServiceImpl() {
137         LOG.info("Creating provider for {}", APPLICATION_NAME);
138
139         this.dataBroker = null;
140         this.mountPointService = null;
141         this.rpcProviderRegistry = null;
142         this.notificationPublishService = null;
143         this.clusterSingletonServiceProvider = null;
144
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<>();
151     }
152
153     public void setDataBroker(DataBroker dataBroker) {
154         this.dataBroker = dataBroker;
155     }
156
157     public void setRpcProviderRegistry(RpcProviderService rpcProviderRegistry) {
158         this.rpcProviderRegistry = rpcProviderRegistry;
159     }
160
161     public void setNotificationPublishService(NotificationPublishService notificationPublishService) {
162         this.notificationPublishService = notificationPublishService;
163     }
164
165     public void setMountPointService(MountPointService mountPointService) {
166         this.mountPointService = mountPointService;
167     }
168
169     public void setClusterSingletonService(ClusterSingletonServiceProvider clusterSingletonService) {
170         this.clusterSingletonServiceProvider = clusterSingletonService;
171     }
172
173     public void setEntityDataProvider(IEntityDataProvider iEntityDataProvider) {
174         this.iEntityDataProvider = iEntityDataProvider;
175     }
176
177     /** Blueprint initialization **/
178     public void init() {
179
180         LOG.info("Session Initiated start {}", APPLICATION_NAME);
181
182         // Start RPC Service
183         this.rpcApiService = new NetconfnodeStateServiceRpcApiImpl(rpcProviderRegistry, vesNotificationListenerList);
184         // Get configuration
185         // ConfigurationFileRepresentation config = new ConfigurationFileRepresentation(CONFIGURATIONFILE);
186         // Akka setup
187         AkkaConfig akkaConfig = getAkkaConfig();
188         this.isCluster = akkaConfig == null ? false : akkaConfig.isCluster();
189         this.clusterName = akkaConfig == null ? "" : akkaConfig.getClusterConfig().getClusterSeedNodeName("abc");
190
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()));
195
196         // RPC Service for specific services
197         this.rpcApiService.setStatusCallback(this);
198
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);
203
204         listenerL1 = dataBroker.registerDataTreeChangeListener(NETCONF_NODE_TOPO_TREE_ID, new L1());
205         listenerL2 = dataBroker.registerDataTreeChangeListener(NETCONF_NODE_TOPO_TREE_ID, new L2());
206
207         this.initializationSuccessful = true;
208
209         LOG.info("Session Initiated end. Initialization done {}", initializationSuccessful);
210
211     }
212
213     /** Blueprint destroy-method method */
214     public void destroy() {
215         close();
216     }
217
218     /**
219      * Getter
220      * 
221      * @return NetconfnodeStateServiceRpcApiImpl
222      */
223     public NetconfnodeStateServiceRpcApiImpl getNetconfnodeStateServiceRpcApiImpl() {
224         return rpcApiService;
225     }
226
227     @Override
228     public GetStatusOutputBuilder getStatus(GetStatusInput input) {
229         return new GetStatusOutputBuilder();
230     }
231
232     @Override
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);
237
238         return new ListenerRegistration<L>() {
239             @Override
240             public @NonNull L getInstance() {
241                 return netconfNodeConnectListener;
242             }
243
244             @Override
245             public void close() {
246                 LOG.info("Remove connect listener {}", netconfNodeConnectListener);
247                 netconfNodeConnectListenerList.remove(netconfNodeConnectListener);
248             }
249         };
250     }
251
252     @Override
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);
257
258         return new ListenerRegistration<L>() {
259             @Override
260             public @NonNull L getInstance() {
261                 return netconfNodeStateListener;
262             }
263
264             @Override
265             public void close() {
266                 LOG.info("Remove state listener {}", netconfNodeStateListener);
267                 netconfNodeStateListenerList.remove(netconfNodeStateListener);
268             }
269         };
270     }
271
272     @Override
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);
277
278         return new ListenerRegistration<L>() {
279             @Override
280             public @NonNull L getInstance() {
281                 return vesNotificationListener;
282             }
283
284             @Override
285             public void close() {
286                 LOG.info("Remove Ves notification listener {}", vesNotificationListener);
287                 vesNotificationListenerList.remove(vesNotificationListener);
288             }
289         };
290     }
291
292     @Override
293     public void close() {
294         LOG.info("Closing start ...");
295         try {
296             close(rpcApiService, listenerL1, listenerL2);
297         } catch (Exception e) {
298             LOG.debug("Closing", e);
299         }
300         LOG.info("Closing done");
301     }
302
303     /**
304      * Used to close all Services, that should support AutoCloseable Pattern
305      *
306      * @param toClose
307      * @throws Exception
308      */
309     private void close(AutoCloseable... toCloseList) throws Exception {
310         for (AutoCloseable element : toCloseList) {
311             if (element != null) {
312                 element.close();
313             }
314         }
315     }
316
317     /**
318      * Indication if init() of this bundle successfully done.
319      * 
320      * @return true if init() was successful. False if not done or not successful.
321      */
322     public boolean isInitializationSuccessful() {
323         return this.initializationSuccessful;
324     }
325
326     /*-------------------------------------------------------------------------------------------
327      * Functions for interface DeviceManagerService
328      */
329
330     /**
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.
333      * 
334      * @param nNodeId id of the mountpoint
335      * @param netconfNode mountpoint contents
336      */
337     private void enterConnectedState(NodeId nNodeId, NetconfNode netconfNode) {
338
339         String mountPointNodeName = nNodeId.getValue();
340         LOG.info("Access connected state for mountpoint {}", mountPointNodeName);
341
342         boolean preConditionMissing = false;
343         if (mountPointService == null) {
344             preConditionMissing = true;
345             LOG.warn("No mountservice available.");
346         }
347         if (!initializationSuccessful) {
348             preConditionMissing = true;
349             LOG.warn("Devicemanager initialization still pending.");
350         }
351         if (preConditionMissing) {
352             return;
353         }
354
355         boolean isNetconfNodeMaster = isNetconfNodeMaster(netconfNode);
356         LOG.info("isNetconfNodeMaster indication {} for mountpoint {}", isNetconfNodeMaster, mountPointNodeName);
357         if (isNetconfNodeMaster) {
358
359             InstanceIdentifier<Node> instanceIdentifier =
360                     NETCONF_TOPO_IID.child(Node.class, new NodeKey(new NodeId(mountPointNodeName)));
361
362             Optional<MountPoint> optionalMountPoint = null;
363             int timeout = 10000;
364             while (!(optionalMountPoint = mountPointService.getMountPoint(instanceIdentifier)).isPresent()
365                     && timeout > 0) {
366                 LOG.info("Event listener waiting for mount point for Netconf device :: Name : {}", mountPointNodeName);
367                 sleepMs(1000);
368                 timeout -= 1000;
369             }
370
371             if (!optionalMountPoint.isPresent()) {
372                 LOG.warn("Event listener timeout while waiting for mount point for Netconf device :: Name : {} ",
373                         mountPointNodeName);
374             } else {
375                 // Mountpoint is present for sure
376                 MountPoint mountPoint = optionalMountPoint.get();
377                 // BindingDOMDataBrokerAdapter.BUILDER_FACTORY;
378                 LOG.info("Mountpoint with id: {}", mountPoint.getIdentifier());
379
380                 Optional<DataBroker> optionalNetconfNodeDatabroker = mountPoint.getService(DataBroker.class);
381
382                 if (!optionalNetconfNodeDatabroker.isPresent()) {
383                     LOG.info("Slave mountpoint {} without databroker", mountPointNodeName);
384                 } else {
385                     LOG.info("Master mountpoint {}", mountPointNodeName);
386                     DataBroker netconfNodeDataBroker = optionalNetconfNodeDatabroker.get();
387                     NetconfAccessor acessor = new NetconfAccessorImpl(nNodeId, netconfNode, netconfNodeDataBroker,
388                             mountPoint, TRANSACTIONUTILS);
389                     /*
390                      * --> Call Listers for onConnect() Indication
391                        for (all)
392                      */
393                     netconfNodeConnectListenerList.forEach(item -> {
394                         try {
395                             item.onEnterConnected(acessor);
396                         } catch (Exception e) {
397                             LOG.info("Exception during onEnterConnected listener call", e);
398                         }
399                     });
400
401                     LOG.info("Connect indication forwarded for {}", mountPointNodeName);
402                 }
403             }
404         }
405     }
406
407     /**
408      * Leave the connected status to a non connected or removed status for master mountpoint
409      * 
410      * @param action that occurred
411      * @param nNodeId id of the mountpoint
412      * @param netconfNode mountpoint contents or not available on remove
413      */
414     private void leaveConnectedState(NodeId nNodeId, Optional<NetconfNode> optionalNetconfNode) {
415         String mountPointNodeName = nNodeId.getValue();
416         LOG.info("netconfNode id {}", mountPointNodeName);
417
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 -> {
426                     try {
427                         if (item != null) {
428                             item.onLeaveConnected(nNodeId, optionalNetconfNode);
429                         } else {
430                             LOG.warn("Unexpeced null item during onleave");
431                         }
432                     } catch (Exception e) {
433                         LOG.info("Exception during onLeaveConnected listener call", e);
434                     }
435                 });
436             }
437         }
438     }
439
440     // ---- onDataTreeChangedHandler
441
442     private void onDataTreeChangedHandler(@NonNull Collection<DataTreeModification<Node>> changes) {
443         for (final DataTreeModification<Node> change : changes) {
444
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);
449             //}
450
451             // Catch potential nullpointer exceptions ..
452             try {
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);
460                     } else {
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
469
470                                     boolean connectedBefore, connectedAfter, created = false;
471                                     NetconfNode nNodeAfter = getNetconfNode(root.getDataAfter());
472                                     connectedAfter = isConnected(nNodeAfter);
473                                     if (root.getDataBefore() != null) {
474                                         // It is an update
475                                         NetconfNode nodeBefore = getNetconfNode(root.getDataBefore());
476                                         connectedBefore = isConnected(nodeBefore);
477                                     } else {
478                                         // It is a create
479                                         connectedBefore = false;
480                                         created = true;
481                                     }
482
483                                     LOG.info(
484                                             "L1 NETCONF Node change with id:{} ConnectedBefore:{} connectedAfter {}:cluster status:{} akkaIsCluster:{}",
485                                             nodeId, connectedBefore, connectedAfter,
486                                             getClusteredConnectionStatus(nNodeAfter), isCluster);
487
488                                     if (created) {
489                                         netconfNodeStateListenerList.forEach(item -> {
490                                             try {
491                                                 item.onCreated(nodeId, nNodeAfter);
492                                             } catch (Exception e) {
493                                                 LOG.info("Exception during onCreated listener call", e);
494                                             }
495                                         });
496                                     }
497                                     if (!connectedBefore && connectedAfter) {
498                                         enterConnectedState(nodeId, nNodeAfter);
499                                     } else {
500                                         LOG.debug("State change {} {}", connectedBefore, connectedAfter);
501                                         if (connectedBefore && !connectedAfter) {
502                                             leaveConnectedState(nodeId, Optional.of(nNodeAfter));
503                                         }
504                                         netconfNodeStateListenerList.forEach(item -> {
505                                             try {
506                                                 item.onStateChange(nodeId, nNodeAfter);
507                                             } catch (Exception e) {
508                                                 LOG.info("Exception during onStateChange listener call", e);
509                                             }
510                                         });
511                                     }
512                                     // doProcessing(update ? Action.UPDATE : Action.CREATE, nodeId, root);
513                                     break;
514                                 case DELETE:
515                                     // Node removed
516                                     // leaveconnected state.before = connected;
517                                     leaveConnectedState(nodeId, Optional.empty());
518                                     netconfNodeStateListenerList.forEach(item -> {
519                                         try {
520                                             item.onRemoved(nodeId);
521                                         } catch (Exception e) {
522                                             LOG.info("Exception during onRemoved listener call", e);
523                                         }
524                                     });
525                                     // doProcessing(Action.REMOVE, nodeId, root);
526                                     break;
527                             }
528                         }
529                     }
530                 }
531             } catch (NullPointerException e) {
532                 LOG.info("Data not available at ", e);
533             }
534         } //for
535     }
536
537     // ---- subclasses for listeners
538
539     /**
540      * Clustered listener function to select the right node from DataObjectModification. Called at all nodes.
541      */
542     private class L1 implements ClusteredDataTreeChangeListener<Node> {
543         @Override
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");
548         }
549     }
550
551     /**
552      * Data change, called at leader/master
553      */
554     private class L2 implements DataTreeChangeListener<Node> {
555
556         @Override
557         public void onDataTreeChanged(@NonNull Collection<DataTreeModification<Node>> changes) {
558             LOG.info("L2 TreeChange enter changes:{}", changes.size());
559             // Do nothing
560             LOG.info("L2 TreeChange leave");
561         }
562     }
563
564     /* --- private helpers --- */
565     private static @Nullable NetconfNode getNetconfNode(Node node) {
566         return node != null ? node.augmentation(NetconfNode.class) : null;
567     }
568
569     private static boolean isConnected(NetconfNode nNode) {
570         return nNode != null ? ConnectionStatus.Connected.equals(nNode.getConnectionStatus()) : false;
571     }
572
573     private static @Nullable ClusteredConnectionStatus getClusteredConnectionStatus(NetconfNode node) {
574         return node != null ? node.getClusteredConnectionStatus() : null;
575     }
576
577     /* -- LOG related functions -- */
578
579     /** Analyze configuration **/
580     private static @Nullable AkkaConfig getAkkaConfig() {
581         AkkaConfig akkaConfig;
582         try {
583             akkaConfig = AkkaConfig.load();
584             LOG.debug("akka.conf loaded: " + akkaConfig.toString());
585         } catch (Exception e1) {
586             akkaConfig = null;
587             LOG.warn("problem loading akka.conf: " + e1.getMessage());
588         }
589         if (akkaConfig != null && akkaConfig.isCluster()) {
590             LOG.info("cluster mode detected");
591             if (GeoConfig.fileExists()) {
592                 try {
593                     LOG.debug("try to load geoconfig");
594                     GeoConfig.load();
595                 } catch (Exception err) {
596                     LOG.warn("problem loading geoconfig: " + err.getMessage());
597                 }
598             } else {
599                 LOG.debug("no geoconfig file found");
600             }
601         } else {
602             LOG.info("single node mode detected");
603         }
604         return akkaConfig;
605     }
606
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")
612             @NonNull
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");
618                 return false;
619             }
620         }
621         return true;
622     }
623
624
625     private void sleepMs(int milliseconds) {
626         try {
627             Thread.sleep(milliseconds);
628         } catch (InterruptedException e) {
629             LOG.debug("Interrupted sleep");
630             // Restore interrupted state...
631             Thread.currentThread().interrupt();
632         }
633     }
634
635
636 }