Merge "YANG Model update for A1 Adapter"
[ccsdk/features.git] / sdnr / wt / devicemanager / provider / src / main / java / org / onap / ccsdk / features / sdnr / wt / devicemanager / impl / DeviceManagerImpl.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.devicemanager.impl;
19
20 import java.util.List;
21 import java.util.Optional;
22 import java.util.concurrent.ConcurrentHashMap;
23 import java.util.concurrent.CopyOnWriteArrayList;
24 import org.eclipse.jdt.annotation.NonNull;
25 import org.eclipse.jdt.annotation.Nullable;
26 import org.onap.ccsdk.features.sdnr.wt.common.configuration.ConfigurationFileRepresentation;
27 import org.onap.ccsdk.features.sdnr.wt.common.database.HtDatabaseClient;
28 import org.onap.ccsdk.features.sdnr.wt.database.config.EsConfig;
29 import org.onap.ccsdk.features.sdnr.wt.dataprovider.model.DataProvider;
30 import org.onap.ccsdk.features.sdnr.wt.dataprovider.model.IEntityDataProvider;
31 import org.onap.ccsdk.features.sdnr.wt.devicemanager.DeviceManagerService;
32 import org.onap.ccsdk.features.sdnr.wt.devicemanager.DeviceManagerServiceProvider;
33 import org.onap.ccsdk.features.sdnr.wt.devicemanager.DeviceMonitoredNe;
34 import org.onap.ccsdk.features.sdnr.wt.devicemanager.FactoryRegistration;
35 import org.onap.ccsdk.features.sdnr.wt.devicemanager.NetconfNetworkElementService;
36 import org.onap.ccsdk.features.sdnr.wt.devicemanager.NetworkElement;
37 import org.onap.ccsdk.features.sdnr.wt.devicemanager.NetworkElementFactory;
38 import org.onap.ccsdk.features.sdnr.wt.devicemanager.UnkownDevicemanagerServiceException;
39 import org.onap.ccsdk.features.sdnr.wt.devicemanager.aaiconnector.impl.AaiProviderClient;
40 import org.onap.ccsdk.features.sdnr.wt.devicemanager.archiveservice.ArchiveCleanService;
41 import org.onap.ccsdk.features.sdnr.wt.devicemanager.base.onfcore.ONFCoreNetworkElementFactory;
42 import org.onap.ccsdk.features.sdnr.wt.devicemanager.base.onfcore.ONFCoreNetworkElementRepresentation;
43 import org.onap.ccsdk.features.sdnr.wt.devicemanager.dcaeconnector.impl.DcaeForwarderInternal;
44 import org.onap.ccsdk.features.sdnr.wt.devicemanager.dcaeconnector.impl.DcaeForwarderImpl;
45 import org.onap.ccsdk.features.sdnr.wt.devicemanager.dcaeconnector.impl.DcaeProviderClient;
46 import org.onap.ccsdk.features.sdnr.wt.devicemanager.devicemonitor.impl.DeviceMonitor;
47 import org.onap.ccsdk.features.sdnr.wt.devicemanager.devicemonitor.impl.DeviceMonitorImpl;
48 import org.onap.ccsdk.features.sdnr.wt.devicemanager.housekeeping.ConnectionStatusHousekeepingService;
49 import org.onap.ccsdk.features.sdnr.wt.devicemanager.housekeeping.ResyncNetworkElementHouskeepingService;
50 import org.onap.ccsdk.features.sdnr.wt.devicemanager.impl.conf.odlAkka.AkkaConfig;
51 import org.onap.ccsdk.features.sdnr.wt.devicemanager.impl.conf.odlGeo.GeoConfig;
52 import org.onap.ccsdk.features.sdnr.wt.devicemanager.impl.handler.ODLEventListenerHandler;
53 import org.onap.ccsdk.features.sdnr.wt.devicemanager.impl.handler.RpcPushNotificationsHandler;
54 import org.onap.ccsdk.features.sdnr.wt.devicemanager.impl.listener.NetconfChangeListener;
55 import org.onap.ccsdk.features.sdnr.wt.devicemanager.impl.util.GenericTransactionUtils;
56 import org.onap.ccsdk.features.sdnr.wt.devicemanager.impl.xml.WebSocketServiceClientInternal;
57 import org.onap.ccsdk.features.sdnr.wt.devicemanager.impl.xml.WebSocketServiceClientDummyImpl;
58 import org.onap.ccsdk.features.sdnr.wt.devicemanager.impl.xml.WebSocketServiceClientImpl2;
59 import org.onap.ccsdk.features.sdnr.wt.devicemanager.maintenance.impl.MaintenanceServiceImpl;
60 import org.onap.ccsdk.features.sdnr.wt.devicemanager.performancemanager.impl.PerformanceManagerImpl;
61 import org.onap.ccsdk.features.sdnr.wt.devicemanager.performancemanager.impl.database.service.MicrowaveHistoricalPerformanceWriterService;
62 import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.INetconfAcessor;
63 import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.NetconfAccessor;
64 import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.NetconfNodeStateService;
65 import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.TransactionUtils;
66 import org.opendaylight.mdsal.binding.api.DataBroker;
67 import org.opendaylight.mdsal.binding.api.MountPoint;
68 import org.opendaylight.mdsal.binding.api.MountPointService;
69 import org.opendaylight.mdsal.binding.api.NotificationPublishService;
70 import org.opendaylight.mdsal.binding.api.RpcProviderService;
71 import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceProvider;
72 import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceRegistration;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNode;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNodeConnectionStatus.ConnectionStatus;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.connection.status.ClusteredConnectionStatus;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.network.topology.topology.topology.types.TopologyNetconf;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.websocketmanager.rev150105.WebsocketmanagerService;
78 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
79 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
80 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
81 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
82 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
83 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
84 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey;
85 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
86 import org.slf4j.Logger;
87 import org.slf4j.LoggerFactory;
88
89 /**
90  * Devicemanager
91  * - Handles startup and closedown of network element handlers for netconf session
92  * - Provide common services for network element specific components
93  */
94 public class DeviceManagerImpl implements NetconfNetworkElementService, DeviceManagerServiceProvider, NetconfNodeService, AutoCloseable {
95
96     private static final Logger LOG = LoggerFactory.getLogger(DeviceManagerImpl.class);
97     private static final String APPLICATION_NAME = "DeviceManager";
98     private static final String MYDBKEYNAMEBASE = "SDN-Controller";
99     private static final String CONFIGURATIONFILE = "etc/devicemanager.properties";
100     public static final long DATABASE_TIMEOUT_MS = 120*1000L;
101
102
103     // http://sendateodl:8181/restconf/operational/network-topology:network-topology/topology/topology-netconf
104     private static final InstanceIdentifier<Topology> NETCONF_TOPO_IID =
105             InstanceIdentifier.create(NetworkTopology.class).child(Topology.class,
106                     new TopologyKey(new TopologyId(TopologyNetconf.QNAME.getLocalName())));
107     @SuppressWarnings("unused")
108     private static final String STARTUPLOG_FILENAME = "etc/devicemanager.startup.log";
109     // private static final String STARTUPLOG_FILENAME2 = "data/cache/devicemanager.startup.log";
110
111     // MDSAL Services
112     private DataBroker dataBroker;
113     private MountPointService mountPointService;
114     private RpcProviderService rpcProviderRegistry;
115     @SuppressWarnings("unused")
116     private NotificationPublishService notificationPublishService;
117     private ClusterSingletonServiceProvider clusterSingletonServiceProvider;
118     private WebsocketmanagerService websocketmanagerService;
119     private IEntityDataProvider iEntityDataProvider;
120
121     // Devicemanager common services for network element handler
122     private @Nullable WebSocketServiceClientInternal webSocketService;
123     private ODLEventListenerHandler odlEventListenerHandler;
124     private NetconfChangeListener netconfChangeListener;
125     private DeviceManagerApiServiceImpl rpcApiService;
126     private PerformanceManagerImpl performanceManager;
127     private DcaeProviderClient dcaeProviderClient;
128     private AaiProviderClient aaiProviderClient;
129     private DcaeForwarderInternal aotsDcaeForwarder;
130     private DeviceMonitor deviceMonitor;
131     private MaintenanceServiceImpl maintenanceService;
132     private DevicemanagerNotificationDelayService notificationDelayService;
133     private ResyncNetworkElementHouskeepingService resyncNetworkElementHouskeepingService;
134     private ArchiveCleanService archiveCleanService;
135     private ConnectionStatusHousekeepingService housekeepingService;
136     private NetconfNodeStateService netconfNodeStateService;
137     private DataProvider dataProvider;
138     private HtDatabaseClient htDatabaseClient;
139     // Handler
140     private RpcPushNotificationsHandler rpcPushNotificationsHandler;
141     private DeviceManagerNetconfConnectHandler forTest;
142     private final TransactionUtils transactionUtils;
143     // Attributes
144     private final Object networkelementLock;
145     private final ConcurrentHashMap<String, NetworkElement> networkElementRepresentations;
146     private final List<MyNetworkElementFactory<? extends NetworkElementFactory>> factoryList;
147     private AkkaConfig akkaConfig;
148     private ClusterSingletonServiceRegistration cssRegistration;
149     private ClusterSingletonServiceRegistration cssRegistration2;
150     private Boolean devicemanagerInitializationOk;
151
152     // Blueprint 1
153     public DeviceManagerImpl() {
154         LOG.info("Creating provider for {}", APPLICATION_NAME);
155         this.devicemanagerInitializationOk = false;
156         this.factoryList = new CopyOnWriteArrayList<>();
157         this.networkelementLock = new Object();
158         this.networkElementRepresentations = new ConcurrentHashMap<>();
159         this.transactionUtils = new GenericTransactionUtils();
160
161         this.dataBroker = null;
162         this.mountPointService = null;
163         this.rpcProviderRegistry = null;
164         this.notificationPublishService = null;
165         this.clusterSingletonServiceProvider = null;
166         this.websocketmanagerService = null;
167         this.iEntityDataProvider = null;
168
169         this.webSocketService = null;
170     }
171
172     public void setDataBroker(DataBroker dataBroker) {
173         this.dataBroker = dataBroker;
174     }
175
176     public void setRpcProviderRegistry(RpcProviderService rpcProviderRegistry) {
177         this.rpcProviderRegistry = rpcProviderRegistry;
178     }
179
180     public void setNotificationPublishService(NotificationPublishService notificationPublishService) {
181         this.notificationPublishService = notificationPublishService;
182     }
183
184     public void setMountPointService(MountPointService mountPointService) {
185         this.mountPointService = mountPointService;
186     }
187     public void setClusterSingletonService(ClusterSingletonServiceProvider clusterSingletonService) {
188         this.clusterSingletonServiceProvider = clusterSingletonService;
189     }
190     public void setNetconfNodeStateService(NetconfNodeStateService netconfNodeStateService) {
191         this.netconfNodeStateService = netconfNodeStateService;
192     }
193     public void setWebsocketmanagerService(WebsocketmanagerService websocketmanagerService) {
194         this.websocketmanagerService = websocketmanagerService;
195     }
196     public void setEntityDataProvider(IEntityDataProvider iEntityDataProvider) {
197         this.iEntityDataProvider = iEntityDataProvider;
198     }
199
200     public void init() throws Exception {
201
202         LOG.info("Session Initiated start {}", APPLICATION_NAME);
203         this.iEntityDataProvider.setReadyStatus(false);
204
205         // Register network element factories and related init functions
206         registerMyNetworkElementFactory(new ONFCoreNetworkElementFactory(), (a,b,c) -> initONFCoremodel(a,b,(ONFCoreNetworkElementRepresentation)c));
207         //registerMyNetworkElementFactory(new ORanNetworkElementFactory(), (a,b,c) -> initORan(a,b,(ONFCoreNetworkElementRepresentation)c));
208         //registerMyNetworkElementFactory(new NtsNetworkElementFactory(), (a,b,c) -> initNts(a,b,(ONFCoreNetworkElementRepresentation)c));
209         //registerMyNetworkElementFactory(new GRanNetworkElementFactory(), (a,b,c) -> initGRan(a,b,(ONFCoreNetworkElementRepresentation)c));
210
211         this.dataProvider = iEntityDataProvider.getDataProvider();        // Get configuration
212
213         ConfigurationFileRepresentation config = new ConfigurationFileRepresentation(CONFIGURATIONFILE);
214
215         this.akkaConfig = loadClusterConfiguration();
216         this.notificationDelayService = new DevicemanagerNotificationDelayService(config);
217
218         EsConfig dbConfig = new EsConfig(config);
219         LOG.debug("esConfig=" + dbConfig.toString());
220         // Start database
221         // TODO Remove this database client
222         this.htDatabaseClient = new HtDatabaseClient(dbConfig.getHosts());
223         this.htDatabaseClient.waitForYellowStatus(DATABASE_TIMEOUT_MS);
224
225         // start service for device maintenance service
226         this.maintenanceService = new MaintenanceServiceImpl(htDatabaseClient);
227
228         // Websockets
229         try {
230             this.webSocketService = new WebSocketServiceClientImpl2(websocketmanagerService);
231         } catch (Exception e) {
232             LOG.error("Can not start websocket service. Loading mock class.", e);
233             this.webSocketService = new WebSocketServiceClientDummyImpl();
234         }
235         // DCAE
236         this.dcaeProviderClient = new DcaeProviderClient(config, dbConfig.getCluster(), this);
237
238         this.aaiProviderClient = new AaiProviderClient(config, this);
239         // EM
240         String myDbKeyNameExtended = MYDBKEYNAMEBASE + "-" + dbConfig.getCluster();
241
242         this.aotsDcaeForwarder = new DcaeForwarderImpl(null, dcaeProviderClient, maintenanceService);
243         this.rpcPushNotificationsHandler = new RpcPushNotificationsHandler(webSocketService,
244                 dataProvider, aotsDcaeForwarder);
245         this.odlEventListenerHandler = new ODLEventListenerHandler(myDbKeyNameExtended, webSocketService,
246                 dataProvider, aotsDcaeForwarder);
247         this.archiveCleanService = new ArchiveCleanService(config, dataProvider);
248         this.housekeepingService = new ConnectionStatusHousekeepingService(this.dataBroker,
249                 dataProvider);
250         this.cssRegistration = this.clusterSingletonServiceProvider
251                 .registerClusterSingletonService(this.archiveCleanService);
252         this.cssRegistration2 = this.clusterSingletonServiceProvider
253                 .registerClusterSingletonService(this.housekeepingService);
254         // PM
255         this.performanceManager = new PerformanceManagerImpl(60, new MicrowaveHistoricalPerformanceWriterService(htDatabaseClient), config);
256
257         // DM
258         // DeviceMonitor has to be available before netconfSubscriptionManager is
259         // configured
260         LOG.debug("start DeviceMonitor Service");
261         this.deviceMonitor = new DeviceMonitorImpl(dataBroker, odlEventListenerHandler, config);
262
263         // ResyncNetworkElementHouskeepingService
264         this.resyncNetworkElementHouskeepingService = new ResyncNetworkElementHouskeepingService(
265                 this, mountPointService, odlEventListenerHandler,
266                 dataProvider, deviceMonitor);
267
268         // RPC Service for specific services
269         // Start RPC Service
270         LOG.debug("start rpc service");
271         this.rpcApiService = new DeviceManagerApiServiceImpl(rpcProviderRegistry, maintenanceService,
272                 resyncNetworkElementHouskeepingService, rpcPushNotificationsHandler);
273
274         // netconfSubscriptionManager should be the last one because this is a callback
275         // service
276         LOG.debug("start NetconfSubscriptionManager Service");
277         // this.netconfSubscriptionManager = new
278         // NetconfSubscriptionManagerOfDeviceManager(this, dataBroker);
279         // this.netconfSubscriptionManager.register();
280         this.netconfChangeListener = new NetconfChangeListener(this, dataBroker);
281         this.netconfChangeListener.register();
282
283         this.forTest = new DeviceManagerNetconfConnectHandler(netconfNodeStateService);
284
285         writeToEventLog(APPLICATION_NAME, "startup", "done");
286         this.devicemanagerInitializationOk = true;
287
288         LOG.info("Session Initiated end. Initialization done {}", devicemanagerInitializationOk);
289         this.iEntityDataProvider.setReadyStatus(true);
290
291     }
292
293     @Override
294     public void close() {
295         LOG.info("DeviceManagerImpl closing ...");
296         close(performanceManager);
297         close(dcaeProviderClient);
298         close(aaiProviderClient);
299         close(deviceMonitor);
300         close(htDatabaseClient);
301         close(netconfChangeListener);
302         close(maintenanceService);
303         close(rpcApiService);
304         close(notificationDelayService);
305         close(archiveCleanService);
306         close(housekeepingService);
307         close(forTest);
308         close(cssRegistration, cssRegistration2);
309         LOG.info("DeviceManagerImpl closing done");
310     }
311
312     @Override
313     public @NonNull <L extends NetworkElementFactory> FactoryRegistration<L> registerNetworkElementFactory(@NonNull L factory) {
314         LOG.info("Factory registration {}", factory.getClass().getName());
315         MyNetworkElementFactory<L> myFactory = new MyNetworkElementFactory<>(factory, (a,b,c) -> initDefault(a,b,c));
316         factoryList.add(myFactory);
317         return new FactoryRegistration<L>() {
318
319             @Override
320             public @NonNull L getInstance() {
321                 return myFactory.getFactory();
322             }
323
324             @Override
325             public void close() {
326                 factoryList.remove(myFactory);
327             }
328
329         };
330     }
331
332     private <L extends NetworkElementFactory> void registerMyNetworkElementFactory(@NonNull L factory,
333             Register<String, MountPoint, NetworkElement> init) {
334         factoryList.add(new MyNetworkElementFactory<>(factory, init));
335     }
336
337
338     @Override
339     public @NonNull DataProvider getDataProvider() {
340         return this.dataProvider;
341     }
342
343     /**
344      * Used to close all Services, that should support AutoCloseable Pattern
345      * @param toClose
346      */
347     private void close(AutoCloseable... toCloseList) {
348         for (AutoCloseable element : toCloseList) {
349             if (element != null) {
350                 try {
351                     element.close();
352                 } catch (Exception e) {
353                     LOG.warn("Problem during close {}", e);
354                 }
355             }
356         }
357     }
358
359     /*-------------------------------------------------------------------------------------------
360      * Functions for interface DeviceManagerService
361      */
362
363     /**
364      * For each mounted device a mountpoint is created and this listener is called.
365      * Mountpoint was created or existing. Managed device is now fully connected to node/mountpoint.
366      * @param action provide action
367      * @param nNodeId id of the mountpoint
368      * @param nNode mountpoint contents
369      */
370     public void startListenerOnNodeForConnectedState(Action action, NodeId nNodeId, NetconfNode nNode) {
371
372         String mountPointNodeName = nNodeId.getValue();
373         LOG.info("Starting Event listener on Netconf for mountpoint {} Action {}", mountPointNodeName, action);
374
375         boolean preConditionMissing = false;
376         if (mountPointService == null) {
377             preConditionMissing = true;
378             LOG.warn("No mountservice available.");
379         }
380         if (!devicemanagerInitializationOk) {
381             preConditionMissing = true;
382             LOG.warn("Devicemanager initialization still pending.");
383         }
384         if (preConditionMissing) {
385             return;
386         }
387
388         if (!isNetconfNodeMaster(nNode)) {
389             // Change Devicemonitor-status to connected ... for non master mountpoints.
390             deviceMonitor.deviceConnectSlaveIndication(mountPointNodeName);
391         } else {
392
393             InstanceIdentifier<Node> instanceIdentifier = NETCONF_TOPO_IID.child(Node.class,
394                     new NodeKey(nNodeId));
395
396             Optional<MountPoint> optionalMountPoint = waitForMountpoint(instanceIdentifier, mountPointNodeName);
397
398
399             if (!optionalMountPoint.isPresent()) {
400                 LOG.warn("Event listener timeout while waiting for mount point for Netconf device :: Name : {} ",
401                         mountPointNodeName);
402             } else {
403                 // Mountpoint is present for sure
404                 MountPoint mountPoint = optionalMountPoint.get();
405                 // BindingDOMDataBrokerAdapter.BUILDER_FACTORY;
406                 LOG.info("Mountpoint with id: {} class {} toString {}", mountPoint.getIdentifier(),
407                         mountPoint.getClass().getName(), mountPoint);
408
409                 Optional<DataBroker> optionalNetconfNodeDatabroker = mountPoint.getService(DataBroker.class);
410                 if (!optionalNetconfNodeDatabroker.isPresent()) {
411                     LOG.info("Slave mountpoint {} without databroker", mountPointNodeName);
412                 } else {
413
414                     // It is master for mountpoint and all data are available.
415                     // Make sure that specific mountPointNodeName is handled only once.
416                     // be aware that startListenerOnNodeForConnectedState could be called multiple
417                     // times for same mountPointNodeName.
418                     // networkElementRepresentations contains handled NEs at master node.
419
420                     synchronized (networkelementLock) {
421                         if (networkElementRepresentations.containsKey(mountPointNodeName)) {
422                             LOG.warn("Mountpoint {} already registered. Leave startup procedure.", mountPointNodeName);
423                             return;
424                         }
425                     }
426                     // update db with connect status
427                     sendUpdateNotification(mountPointNodeName, nNode.getConnectionStatus(), nNode);
428
429                     DataBroker netconfNodeDataBroker = optionalNetconfNodeDatabroker.get();
430                     LOG.info("Master mountpoint {}", mountPointNodeName);
431                     INetconfAcessor acessor = new NetconfAccessor(nNodeId, nNode, netconfNodeDataBroker, mountPoint, transactionUtils);
432
433                     for (MyNetworkElementFactory<? extends NetworkElementFactory> f : factoryList) {
434                         Optional<NetworkElement> optionalNe = f.getFactory().create(acessor, this);
435                         if (optionalNe.isPresent()) {
436                             f.getInit().register(mountPointNodeName, mountPoint, optionalNe.get());
437                             break; //Use the first provided
438                         }
439                     }
440                 }
441             }
442         }
443     }
444
445     @SuppressWarnings("unchecked")
446     @Override
447     public @NonNull <L extends DeviceManagerService> L getService(Class<L> serviceInterface) throws UnkownDevicemanagerServiceException {
448         if (serviceInterface.isInstance(webSocketService)) {
449             return (L) this.webSocketService;
450         } else if (serviceInterface.isInstance(aotsDcaeForwarder)) {
451             return (L) this.aotsDcaeForwarder;
452         } else if (serviceInterface.isInstance(notificationDelayService)) {
453             return (L) notificationDelayService;
454         }
455         throw new UnkownDevicemanagerServiceException("Unknown service ",serviceInterface);
456     }
457
458     // Deviceinitialization
459
460     @FunctionalInterface
461     interface Register<X, Y, Z> {
462         public void register(X mountPointNodeName, Y mountPoint, Z ne);
463     }
464
465     private class MyNetworkElementFactory<L extends NetworkElementFactory> {
466
467         private final Register<String, MountPoint, NetworkElement> init;
468         private final @NonNull L factory;
469
470         @SuppressWarnings("null")
471         public MyNetworkElementFactory(@NonNull L factory, Register<String, MountPoint, NetworkElement> init) {
472             super();
473             if (init == null || factory == null) {
474                 throw new IllegalArgumentException("Null not allowed here.");
475             }
476             this.init = init;
477             this.factory = factory;
478         }
479         public Register<String, MountPoint, NetworkElement> getInit() {
480             return init;
481         }
482         public @NonNull L getFactory() {
483             return factory;
484         }
485     }
486
487     /**
488      * Execute register command, for network element
489      * @param mountPointNodeName  of new network element
490      * @param mountPoint of new network element
491      * @param inNe that needs to register
492      */
493     private void initDefault(String mountPointNodeName, MountPoint mountPoint, NetworkElement inNe) {
494         // sendUpdateNotification(mountPointNodeName, nNode.getConnectionStatus(), nNode);
495
496         // TODO
497         putToNetworkElementRepresentations(mountPointNodeName, inNe);
498         deviceMonitor.deviceConnectMasterIndication(mountPointNodeName, inNe);
499
500         inNe.register();
501     }
502
503     private void initONFCoremodel(String mountPointNodeName, MountPoint mountPoint,
504             ONFCoreNetworkElementRepresentation ne) {
505         putToNetworkElementRepresentations(mountPointNodeName, ne);
506         // create automatic empty maintenance entry into db before reading and listening
507         // for problems
508         maintenanceService.createIfNotExists(mountPointNodeName);
509
510         // Setup microwaveEventListener for notification service
511         // MicrowaveEventListener microwaveEventListener = new
512         // MicrowaveEventListener(mountPointNodeName, websocketmanagerService,
513         // xmlMapper, databaseClientEvents);
514
515         ne.doRegisterEventListener(mountPoint);
516
517         // Register netconf stream
518         NetconfNotification.registerNotificationStream(mountPointNodeName, mountPoint, "NETCONF");
519
520         // -- Read data from NE
521         ne.initialReadFromNetworkElement();
522
523         if (aaiProviderClient != null) {
524             aaiProviderClient.onDeviceRegistered(mountPointNodeName);
525         }
526         // -- Register NE to performance manager
527         if (performanceManager != null) {
528             performanceManager.registration(mountPointNodeName, ne);
529         }
530
531         deviceMonitor.deviceConnectMasterIndication(mountPointNodeName, (DeviceMonitoredNe)ne);
532
533         LOG.info("Starting Event listener finished. Added Netconf device {}", mountPointNodeName);
534     }
535
536     private void initORan(String mountPointNodeName, MountPoint mountPoint, ONFCoreNetworkElementRepresentation neORan) {
537         // sendUpdateNotification(mountPointNodeName, nNode.getConnectionStatus(), nNode);
538         putToNetworkElementRepresentations(mountPointNodeName, neORan);
539
540         maintenanceService.createIfNotExists(mountPointNodeName);
541
542         deviceMonitor.deviceConnectMasterIndication(mountPointNodeName, (DeviceMonitoredNe)neORan);
543
544         // -- Read data from NE
545         neORan.initialReadFromNetworkElement();
546         neORan.doRegisterEventListener(mountPoint);
547         NetconfNotification.registerNotificationStream(mountPointNodeName, mountPoint, "NETCONF");
548     }
549
550     private void initNts(String mountPointNodeName, MountPoint mountPoint, ONFCoreNetworkElementRepresentation neNts) {
551         // sendUpdateNotification(mountPointNodeName, nNode.getConnectionStatus(), nNode);
552         putToNetworkElementRepresentations(mountPointNodeName, neNts);
553         deviceMonitor.deviceConnectMasterIndication(mountPointNodeName, (DeviceMonitoredNe)neNts);
554
555         // -- Read data from NE
556         neNts.initialReadFromNetworkElement();
557     }
558     private void initGRan(String mountPointNodeName, MountPoint mountPoint, ONFCoreNetworkElementRepresentation neGRan) {
559         // sendUpdateNotification(mountPointNodeName, nNode.getConnectionStatus(), nNode);
560         putToNetworkElementRepresentations(mountPointNodeName, neGRan);
561         deviceMonitor.deviceConnectMasterIndication(mountPointNodeName, (DeviceMonitoredNe)neGRan);
562
563         // -- Read data from NE
564         neGRan.initialReadFromNetworkElement();
565     }
566     /**
567      * @param instanceIdentifier
568      * @param mountPointNodeName
569      * @return
570      */
571     private Optional<MountPoint> waitForMountpoint(InstanceIdentifier<Node> instanceIdentifier,
572             String mountPointNodeName) {
573         Optional<MountPoint> optionalMountPoint = null;
574         int timeout = 10000;
575         while (!(optionalMountPoint = mountPointService.getMountPoint(instanceIdentifier)).isPresent()
576                 && timeout > 0) {
577             LOG.info("Event listener waiting for mount point for Netconf device :: Name : {}", mountPointNodeName);
578             sleepMs(1000);
579             timeout -= 1000;
580         }
581         return optionalMountPoint;
582     }
583
584     private void putToNetworkElementRepresentations(String mountPointNodeName, NetworkElement ne) {
585         NetworkElement result;
586         synchronized (networkelementLock) {
587             result = networkElementRepresentations.put(mountPointNodeName, ne);
588         }
589         if (result != null) {
590             LOG.warn("NE list was not empty as expected, but contained {} ", result.getNodeId());
591         } else {
592             odlEventListenerHandler.connectIndication(mountPointNodeName, ne.getDeviceType());
593         }
594     }
595
596     /**
597      * Mountpoint created or existing. Managed device is actually disconnected from node/ mountpoint.
598      * Origin state: Connecting, Connected
599      * Target state: are UnableToConnect or Connecting
600      * @param action create or update
601      * @param nNodeId id of the mountpoint
602      * @param nNode mountpoint contents
603      */
604     public void enterNonConnectedState(Action action, NodeId nNodeId, NetconfNode nNode) {
605         String mountPointNodeName = nNodeId.getValue();
606         ConnectionStatus csts = nNode.getConnectionStatus();
607         if (isNetconfNodeMaster(nNode)) {
608             sendUpdateNotification(mountPointNodeName, csts,nNode);
609         }
610
611         // Handling if mountpoint exist. connected -> connecting/UnableToConnect
612         stopListenerOnNodeForConnectedState(mountPointNodeName);
613
614         deviceMonitor.deviceDisconnectIndication(mountPointNodeName);
615
616     }
617
618     /**
619      * Mountpoint removed indication.
620      * @param nNodeId id of the mountpoint
621      */
622     public void removeMountpointState(NodeId nNodeId) {
623         String mountPointNodeName = nNodeId.getValue();
624         LOG.info("mountpointNodeRemoved {}", nNodeId.getValue());
625
626         stopListenerOnNodeForConnectedState(mountPointNodeName);
627         deviceMonitor.removeMountpointIndication(mountPointNodeName);
628         if (odlEventListenerHandler != null) {
629             odlEventListenerHandler.deRegistration(mountPointNodeName);
630         }
631     }
632
633     /**
634      * Do all tasks necessary to move from mountpoint state connected -> connecting
635      * @param mountPointNodeName provided
636      * @param ne representing the device connected to mountpoint
637      */
638     private void stopListenerOnNodeForConnectedState( String mountPointNodeName) {
639         NetworkElement ne = networkElementRepresentations.remove(mountPointNodeName);
640         if (ne != null) {
641             this.maintenanceService.deleteIfNotRequired(mountPointNodeName);
642             ne.deregister();
643             if (performanceManager != null) {
644                 performanceManager.deRegistration(mountPointNodeName);
645             }
646             if (aaiProviderClient != null) {
647                 aaiProviderClient.onDeviceUnregistered(mountPointNodeName);
648             }
649         }
650     }
651
652     private void sendUpdateNotification(String mountPointNodeName, ConnectionStatus csts, NetconfNode nNode) {
653         LOG.info("update ConnectedState for device :: Name : {} ConnectionStatus {}", mountPointNodeName, csts);
654         if (odlEventListenerHandler != null) {
655             odlEventListenerHandler.updateRegistration(mountPointNodeName, ConnectionStatus.class.getSimpleName(),
656                     csts != null ? csts.getName() : "null", nNode);
657         }
658     }
659
660     /**
661      * Handle netconf/mountpoint changes
662      */
663     @Override
664     public void netconfNodeChangeHandler(Action action, NodeId nodeId, NetconfNode nNode) {
665
666         @Nullable ConnectionStatus csts = nNode.getConnectionStatus();
667         @Nullable ClusteredConnectionStatus ccsts = nNode.getClusteredConnectionStatus();
668         String nodeIdString = nodeId.getValue();
669
670         LOG.debug("NETCONF Node processing with id {} action {} status {} cluster status {}", nodeId,
671                     action, csts, ccsts);
672
673         boolean isCluster = akkaConfig == null && akkaConfig.isCluster();
674         if (isCluster && ccsts == null) {
675             LOG.debug("NETCONF Node {} {} does not provide cluster status. Stop execution.", nodeIdString, action);
676         } else {
677             switch (action) {
678                 case REMOVE:
679                     removeMountpointState(nodeId); // Stop Monitor
680                     break;
681                 case CREATE:
682                     if (odlEventListenerHandler != null) {
683                         odlEventListenerHandler.registration(nodeIdString,nNode);
684                     }
685                     createOrUpdateMountpointState(action, csts, nodeId, nNode);
686                     break;
687                 case UPDATE:
688                     createOrUpdateMountpointState(action, csts, nodeId, nNode);
689                     break;
690             }
691         }
692     }
693
694     private void createOrUpdateMountpointState(Action action, @Nullable ConnectionStatus csts, NodeId nodeId, NetconfNode nNode) {
695         if (csts != null) {
696             switch (csts) {
697                 case Connected: {
698                     startListenerOnNodeForConnectedState(action, nodeId, nNode);
699                     break;
700                 }
701                 case UnableToConnect:
702                 case Connecting: {
703                     enterNonConnectedState(action, nodeId, nNode);
704                     break;
705                 }
706             }
707         } else {
708             LOG.debug("NETCONF Node handled with null status for action", action);
709         }
710     }
711
712     /*-------------------------------------------------------------------------------------------
713      * Functions
714      */
715
716     public ArchiveCleanService getArchiveCleanService() {
717         return this.archiveCleanService;
718     }
719
720     public DataProvider getDatabaseClientEvents() {
721         return dataProvider;
722     }
723
724     @Override
725     public DeviceManagerServiceProvider getServiceProvider() {
726         return this;
727     }
728
729     /**
730      * Indication if init() of devicemanager successfully done.
731      * @return true if init() was sucessfull. False if not done or not successfull.
732      */
733     public boolean isDevicemanagerInitializationOk() {
734         return this.devicemanagerInitializationOk;
735     }
736
737     /**
738      * Get NE object. Used by DCAE Service
739      * @param mountpoint mount point name
740      * @return null or NE specific data
741      */
742     public @Nullable NetworkElement getNeByMountpoint(String mountpoint) {
743
744         return networkElementRepresentations.get(mountpoint);
745
746     }
747
748     @Override
749     public void writeToEventLog(String objectId, String msg, String value) {
750         this.odlEventListenerHandler.writeEventLog(objectId, msg, value);
751     }
752
753     /*---------------------------------------------------------------------
754      * Private funtions
755      */
756
757
758     /* -- LOG related functions -- */
759
760
761     private boolean isInClusterMode() {
762         return this.akkaConfig == null ? false : this.akkaConfig.isCluster();
763     }
764
765     private String getClusterNetconfNodeName() {
766         return this.akkaConfig == null ? "" : this.akkaConfig.getClusterConfig().getClusterSeedNodeName("abc");
767     }
768
769     private boolean isNetconfNodeMaster(NetconfNode nNode) {
770         if (isInClusterMode()) {
771             LOG.debug("check if me is responsible for node");
772             String masterNodeName = null;
773             ClusteredConnectionStatus ccst = nNode.getClusteredConnectionStatus();
774             if (ccst != null) {
775                 masterNodeName = ccst.getNetconfMasterNode();
776             }
777             if (masterNodeName == null) {
778                 masterNodeName = "null";
779             }
780
781             String myNodeName = getClusterNetconfNodeName();
782             LOG.debug("sdnMasterNode=" + masterNodeName + " and sdnMyNode=" + myNodeName);
783             if (!masterNodeName.equals(myNodeName)) {
784                 LOG.debug("netconf change but me is not master for this node");
785                 return false;
786             }
787         }
788         return true;
789     }
790
791     private static AkkaConfig loadClusterConfiguration() {
792         AkkaConfig akkaConfigRes;
793         try {
794             akkaConfigRes = AkkaConfig.load();
795             LOG.debug("akka.conf loaded: " + akkaConfigRes.toString());
796         } catch (Exception e1) {
797             akkaConfigRes = null;
798             LOG.warn("problem loading akka.conf: " + e1.getMessage());
799         }
800         @SuppressWarnings("unused")
801         GeoConfig geoConfig = null;
802         if (akkaConfigRes != null && akkaConfigRes.isCluster()) {
803             LOG.info("cluster mode detected");
804             if (GeoConfig.fileExists()) {
805                 try {
806                     LOG.debug("try to load geoconfig");
807                     geoConfig = GeoConfig.load();
808                 } catch (Exception err) {
809                     LOG.warn("problem loading geoconfig: " + err.getMessage());
810                 }
811             } else {
812                 LOG.debug("no geoconfig file found");
813             }
814         } else {
815             LOG.info("single node mode detected");
816         }
817         return akkaConfigRes;
818     }
819
820     private void sleepMs(int milliseconds) {
821         try {
822             Thread.sleep(milliseconds);
823         } catch (InterruptedException e) {
824             LOG.debug("Interrupted sleep");
825             // Restore interrupted state...
826             Thread.currentThread().interrupt();
827         }
828     }
829 }