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.devicemanager.eventdatahandler;
 
  20 import java.util.Optional;
 
  21 import java.util.concurrent.ExecutionException;
 
  22 import java.util.concurrent.ExecutorService;
 
  23 import java.util.concurrent.Executors;
 
  24 import java.util.concurrent.TimeUnit;
 
  25 import org.eclipse.jdt.annotation.NonNull;
 
  26 import org.onap.ccsdk.features.sdnr.wt.dataprovider.model.DataProvider;
 
  27 import org.onap.ccsdk.features.sdnr.wt.dataprovider.model.NetconfTimeStamp;
 
  28 import org.onap.ccsdk.features.sdnr.wt.dataprovider.model.types.NetconfTimeStampImpl;
 
  29 import org.onap.ccsdk.features.sdnr.wt.devicemanager.dcaeconnector.impl.DcaeForwarderInternal;
 
  30 import org.onap.ccsdk.features.sdnr.wt.devicemanager.impl.util.InternalDateAndTime;
 
  31 import org.onap.ccsdk.features.sdnr.wt.devicemanager.impl.util.InternalSeverity;
 
  32 import org.onap.ccsdk.features.sdnr.wt.devicemanager.impl.util.NetworkElementConnectionEntitiyUtil;
 
  33 import org.onap.ccsdk.features.sdnr.wt.devicemanager.impl.xml.ProblemNotificationXml;
 
  34 import org.onap.ccsdk.features.sdnr.wt.devicemanager.impl.xml.WebSocketServiceClientInternal;
 
  35 import org.onap.ccsdk.features.sdnr.wt.devicemanager.service.EventHandlingService;
 
  36 import org.opendaylight.mdsal.binding.api.DataBroker;
 
  37 import org.opendaylight.mdsal.binding.api.ReadTransaction;
 
  38 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
 
  39 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.DateAndTime;
 
  40 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNode;
 
  41 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNodeConnectionStatus.ConnectionStatus;
 
  42 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.network.topology.topology.topology.types.TopologyNetconf;
 
  43 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev201110.ConnectionLogStatus;
 
  44 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev201110.Connectionlog;
 
  45 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev201110.ConnectionlogBuilder;
 
  46 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev201110.EventlogBuilder;
 
  47 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev201110.NetworkElementConnectionEntity;
 
  48 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev201110.NetworkElementDeviceType;
 
  49 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev201110.SourceType;
 
  50 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.devicemanager.rev190109.AttributeValueChangedNotification;
 
  51 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.devicemanager.rev190109.AttributeValueChangedNotificationBuilder;
 
  52 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.devicemanager.rev190109.ObjectCreationNotification;
 
  53 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.devicemanager.rev190109.ObjectCreationNotificationBuilder;
 
  54 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.devicemanager.rev190109.ObjectDeletionNotification;
 
  55 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.devicemanager.rev190109.ObjectDeletionNotificationBuilder;
 
  56 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.devicemanager.rev190109.ProblemNotification;
 
  57 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.devicemanager.rev190109.ProblemNotificationBuilder;
 
  58 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
 
  59 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
 
  60 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
 
  61 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
 
  62 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
 
  63 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
 
  64 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey;
 
  65 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 
  66 import org.slf4j.Logger;
 
  67 import org.slf4j.LoggerFactory;
 
  70  * Responsible class for documenting changes in the ODL itself. The occurence of such an event is documented in the
 
  71  * database and to clients. Specific example here is the registration or deregistration of a netconf device. This
 
  72  * service has an own eventcounter to apply to the ONF Coremodel netconf behaviour.
 
  74  * Important: Websocket notification must be the last action.
 
  79 @SuppressWarnings("deprecation")
 
  80 public class ODLEventListenerHandler implements EventHandlingService, AutoCloseable {
 
  82     private static final Logger LOG = LoggerFactory.getLogger(ODLEventListenerHandler.class);
 
  84     private static final NetconfTimeStamp NETCONFTIME_CONVERTER = NetconfTimeStampImpl.getConverter();
 
  87      * if update NE failed delay before retrying to write data into database
 
  89     private static final long DBWRITE_RETRY_DELAY_MS = 3000;
 
  91     private final String ownKeyName;
 
  92     private final WebSocketServiceClientInternal webSocketService;
 
  93     private final DataProvider databaseService;
 
  94     private final DcaeForwarderInternal aotsDcaeForwarder;
 
  95     private final DataBroker dataBroker;
 
  96     private final ExecutorService executor = Executors.newFixedThreadPool(5);
 
  97     private int eventNumber;
 
 100     /*---------------------------------------------------------------
 
 105      * Create a Service to document events to clients and within a database
 
 107      * @param ownKeyName The name of this service, that is used in the database as identification key.
 
 108      * @param webSocketService service to direct messages to clients
 
 109      * @param databaseService service to write to the database
 
 110      * @param dcaeForwarder to deliver problems to external service
 
 112     public ODLEventListenerHandler(String ownKeyName, WebSocketServiceClientInternal webSocketService,
 
 113             DataProvider databaseService, DcaeForwarderInternal dcaeForwarder, DataBroker dataBroker) {
 
 116         this.ownKeyName = ownKeyName;
 
 117         this.webSocketService = webSocketService;
 
 119         this.databaseService = databaseService;
 
 120         this.aotsDcaeForwarder = dcaeForwarder;
 
 121         this.dataBroker = dataBroker;
 
 123         this.eventNumber = 0;
 
 126     /*---------------------------------------------------------------
 
 127      * Handling of ODL Controller events
 
 131      * (NonConnected) A registration after creation of a mountpoint occured
 
 133      * @param registrationName of device (mountpoint name)
 
 134      * @param nNode with mountpoint data
 
 137     public void registration(NodeId nodeId, NetconfNode nNode) {
 
 139         DateAndTime ts = NETCONFTIME_CONVERTER.getTimeStamp();
 
 140         ObjectCreationNotification notification = new ObjectCreationNotificationBuilder()
 
 141                 .setObjectIdRef(nodeId.getValue()).setCounter(popEvntNumber()).setTimeStamp(ts).build();
 
 142         Connectionlog log = new ConnectionlogBuilder().setNodeId(nodeId.getValue())
 
 143                 .setStatus(ConnectionLogStatus.Mounted).setTimestamp(ts).build();
 
 145         NetworkElementConnectionEntity e = NetworkElementConnectionEntitiyUtil.getNetworkConnection(nodeId.getValue(),
 
 146                 nNode, getNnodeConfig(nodeId));
 
 147         LOG.debug("registration networkelement-connection for {} with status {}", nodeId.getValue(), e.getStatus());
 
 149         // Write first to prevent missing entries
 
 150         databaseService.updateNetworkConnection22(e, nodeId.getValue());
 
 151         databaseService.writeConnectionLog(log);
 
 152         webSocketService.sendViaWebsockets(new NodeId(ownKeyName), notification, ObjectCreationNotification.QNAME,
 
 153                 NetconfTimeStampImpl.getConverter().getTimeStamp());
 
 156     private Optional<NetconfNode> getNnodeConfig(NodeId nodeId) {
 
 157         if (this.dataBroker != null) {
 
 159             InstanceIdentifier<NetconfNode> iif = InstanceIdentifier.create(NetworkTopology.class)
 
 160                     .child(Topology.class, new TopologyKey(new TopologyId(TopologyNetconf.QNAME.getLocalName())))
 
 161                     .child(Node.class, new NodeKey(nodeId)).augmentation(NetconfNode.class);
 
 163             //Implicit close of try with resource is not handled correctly by underlying opendaylight NETCONF service
 
 165             ReadTransaction readTransaction = this.dataBroker.newReadOnlyTransaction();
 
 167                 return readTransaction.read(LogicalDatastoreType.CONFIGURATION, iif).get();
 
 168             } catch (InterruptedException e) {
 
 169                 LOG.warn("InterruptedException occurred - problem requesting netconfnode again:", e);
 
 170                 Thread.currentThread().interrupt();
 
 171             } catch (ExecutionException e) {
 
 172                 LOG.warn("ExecutionException occurred - problem requesting netconfnode again:", e);
 
 175         return Optional.empty();
 
 179      * (Connected) mountpoint state moves to connected
 
 181      * @param mountpointNodeName uuid that is nodeId or mountpointId
 
 182      * @param deviceType according to assessement
 
 185     public void connectIndication(NodeId nNodeId, NetworkElementDeviceType deviceType) {
 
 187         // Write first to prevent missing entries
 
 188         LOG.debug("updating networkelement-connection devicetype for {} with {}", nNodeId.getValue(), deviceType);
 
 189         NetworkElementConnectionEntity e =
 
 190                 NetworkElementConnectionEntitiyUtil.getNetworkConnectionDeviceTpe(deviceType);
 
 191         //if updating db entry for ne connection fails retry later on (due elasticsearch max script executions error)
 
 192         if (!databaseService.updateNetworkConnectionDeviceType(e, nNodeId.getValue())) {
 
 193             this.updateNeConnectionRetryWithDelay(e, nNodeId.getValue());
 
 195         DateAndTime ts = NETCONFTIME_CONVERTER.getTimeStamp();
 
 196         AttributeValueChangedNotification notification = new AttributeValueChangedNotificationBuilder()
 
 197                 .setCounter(popEvntNumber()).setTimeStamp(ts).setObjectIdRef(nNodeId.getValue())
 
 198                 .setAttributeName("deviceType").setNewValue(deviceType.getName()).build();
 
 199         webSocketService.sendViaWebsockets(new NodeId(ownKeyName), notification,
 
 200                 AttributeValueChangedNotification.QNAME, ts);
 
 204      * (NonConnected) mountpoint state changed.
 
 206      * @param mountpointNodeName nodeid
 
 207      * @param netconfNode node
 
 209     public void onStateChangeIndication(NodeId nodeId, NetconfNode netconfNode) {
 
 210         LOG.debug("mountpoint state changed indication for {}", nodeId.getValue());
 
 211         ConnectionStatus csts = netconfNode.getConnectionStatus();
 
 212         this.updateRegistration(nodeId, ConnectionStatus.class.getSimpleName(), csts != null ? csts.getName() : "null",
 
 218      * (NonConnected) A deregistration after removal of a mountpoint occured.
 
 220      * @param registrationName Name of the event that is used as key in the database.
 
 222     @SuppressWarnings("null")
 
 224     public void deRegistration(NodeId nodeId) {
 
 226         DateAndTime ts = NETCONFTIME_CONVERTER.getTimeStamp();
 
 227         ObjectDeletionNotification notification = new ObjectDeletionNotificationBuilder().setCounter(popEvntNumber())
 
 228                 .setTimeStamp(ts).setObjectIdRef(nodeId.getValue()).build();
 
 229         Connectionlog log = new ConnectionlogBuilder().setNodeId(nodeId.getValue())
 
 230                 .setStatus(ConnectionLogStatus.Unmounted).setTimestamp(ts).build();
 
 231         // Write first to prevent missing entries
 
 232         databaseService.removeNetworkConnection(nodeId.getValue());
 
 233         databaseService.writeConnectionLog(log);
 
 234         webSocketService.sendViaWebsockets(new NodeId(ownKeyName), notification,
 
 235                 ObjectDeletionNotification.QNAME, ts);
 
 240      * Mountpoint state changed .. from connected -> connecting or unable-to-connect or vis-e-versa.
 
 242      * @param registrationName Name of the event that is used as key in the database.
 
 245     public void updateRegistration(NodeId nodeId, String attribute, String attributeNewValue, NetconfNode nNode) {
 
 246         DateAndTime ts = NETCONFTIME_CONVERTER.getTimeStamp();
 
 247         AttributeValueChangedNotification notification = new AttributeValueChangedNotificationBuilder()
 
 248                 .setCounter(popEvntNumber()).setTimeStamp(ts).setObjectIdRef(nodeId.getValue())
 
 249                 .setAttributeName(attribute).setNewValue(attributeNewValue).build();
 
 250         Connectionlog log = new ConnectionlogBuilder().setNodeId(nodeId.getValue())
 
 251                 .setStatus(getStatus(attributeNewValue)).setTimestamp(ts).build();
 
 252         NetworkElementConnectionEntity e = NetworkElementConnectionEntitiyUtil.getNetworkConnection(nodeId.getValue(),
 
 253                 nNode, getNnodeConfig(nodeId));
 
 254         LOG.debug("updating networkelement-connection for {} with status {}", nodeId.getValue(), e.getStatus());
 
 256         //if updating db entry for ne connection fails retry later on (due elasticsearch max script executions error)
 
 257         if (!databaseService.updateNetworkConnection22(e, nodeId.getValue())) {
 
 258             this.updateNeConnectionRetryWithDelay(nNode, nodeId.getValue());
 
 260         databaseService.writeConnectionLog(log);
 
 261         webSocketService.sendViaWebsockets(new NodeId(ownKeyName), notification,
 
 262                 AttributeValueChangedNotification.QNAME, ts);
 
 266     private void updateNeConnectionRetryWithDelay(NetconfNode nNode, String registrationName) {
 
 267         LOG.debug("try to rewrite networkelement-connection in {} for node {}", DBWRITE_RETRY_DELAY_MS,
 
 269         executor.execute(new DelayedThread(DBWRITE_RETRY_DELAY_MS) {
 
 273                 databaseService.updateNetworkConnection22(
 
 274                         NetworkElementConnectionEntitiyUtil.getNetworkConnection(registrationName, nNode),
 
 280     private void updateNeConnectionRetryWithDelay(NetworkElementConnectionEntity e, String registrationName) {
 
 281         LOG.debug("try to rewrite networkelement-connection in {} for node {}", DBWRITE_RETRY_DELAY_MS,
 
 283         executor.execute(new DelayedThread(DBWRITE_RETRY_DELAY_MS) {
 
 287                 databaseService.updateNetworkConnection22(e, registrationName);
 
 293      * At a mountpoint a problem situation is indicated
 
 295      * @param registrationName indicating object within SDN controller, normally the mountpointName
 
 296      * @param problemName that changed
 
 297      * @param problemSeverity of the problem according to NETCONF/YANG
 
 300     public void onProblemNotification(String registrationName, String problemName, InternalSeverity problemSeverity) {
 
 301         LOG.debug("Got event of {} {} {}", registrationName, problemName, problemSeverity);
 
 304         ProblemNotificationXml notificationXml =
 
 305                 new ProblemNotificationXml(ownKeyName, registrationName, problemName, problemSeverity,
 
 306                         // popEvntNumberAsString(), InternalDateAndTime.TESTPATTERN );
 
 307                         popEvntNumber(), InternalDateAndTime.valueOf(NETCONFTIME_CONVERTER.getTimeStamp()));
 
 308         DateAndTime ts = NETCONFTIME_CONVERTER.getTimeStamp();
 
 309         ProblemNotification notification =
 
 310                 new ProblemNotificationBuilder().setObjectIdRef(registrationName).setCounter(popEvntNumber())
 
 311                         .setProblem(problemName).setSeverity(InternalSeverity.toYang(problemSeverity)).build();
 
 312         databaseService.writeFaultLog(notificationXml.getFaultlog(SourceType.Controller));
 
 313         databaseService.updateFaultCurrent(notificationXml.getFaultcurrent());
 
 315         aotsDcaeForwarder.sendProblemNotificationUsingMaintenanceFilter(new NodeId(ownKeyName), notificationXml);
 
 317         webSocketService.sendViaWebsockets(new NodeId(ownKeyName), notification, ProblemNotification.QNAME, ts);
 
 321     public void writeEventLog(String objectId, String msg, String value) {
 
 323         LOG.debug("Got startComplete");
 
 324         EventlogBuilder eventlogBuilder = new EventlogBuilder();
 
 325         eventlogBuilder.setNodeId(ownKeyName).setTimestamp(new DateAndTime(NETCONFTIME_CONVERTER.getTimeStamp()))
 
 326                 .setObjectId(objectId).setAttributeName(msg).setNewValue(value).setCounter(popEvntNumber())
 
 327                 .setSourceType(SourceType.Controller);
 
 328         databaseService.writeEventLog(eventlogBuilder.build());
 
 332     /*---------------------------------------------
 
 333      * Handling of ODL Controller events
 
 337      * Called on exit to remove everything for a node from the current list.
 
 339      * @param nodeName to remove all problems for
 
 340      * @return Number of deleted objects
 
 342     public int removeAllCurrentProblemsOfNode(String nodeName) {
 
 343         return databaseService.clearFaultsCurrentOfNodeWithObjectId(ownKeyName, nodeName);
 
 346     /*---------------------------------------------------------------
 
 351      * @return the ownKeyName
 
 353     public String getOwnKeyName() {
 
 358     public void close() throws Exception {
 
 360         executor.awaitTermination(DBWRITE_RETRY_DELAY_MS * 3, TimeUnit.SECONDS);
 
 363     /*---------------------------------------------------------------
 
 366     private Integer popEvntNumber() {
 
 367         return eventNumber++;
 
 370     private static ConnectionLogStatus getStatus(String newValue) {
 
 372         if (newValue.equals(ConnectionStatus.Connected.getName())) {
 
 373             return ConnectionLogStatus.Connected;
 
 375         } else if (newValue.equals(ConnectionStatus.Connecting.getName())) {
 
 376             return ConnectionLogStatus.Connecting;
 
 378         } else if (newValue.equals(ConnectionStatus.UnableToConnect.getName())) {
 
 379             return ConnectionLogStatus.UnableToConnect;
 
 382         return ConnectionLogStatus.Undefined;
 
 385     private class DelayedThread extends Thread {
 
 386         private final long delay;
 
 388         public DelayedThread(long delayms) {
 
 389             this.delay = delayms;
 
 395                 Thread.sleep(this.delay);
 
 396             } catch (InterruptedException e) {
 
 397                 Thread.currentThread().interrupt();