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();