Update portmapping YANG model
[transportpce.git] / networkmodel / src / main / java / org / opendaylight / transportpce / networkmodel / service / NetworkModelServiceImpl.java
1 /*
2  * Copyright © 2016 AT&T and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.transportpce.networkmodel.service;
9
10 import com.google.common.util.concurrent.ListenableFuture;
11 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
12 import java.util.ArrayList;
13 import java.util.HashMap;
14 import java.util.List;
15 import java.util.Map;
16 import java.util.Objects;
17 import java.util.Optional;
18 import java.util.concurrent.ExecutionException;
19 import java.util.concurrent.TimeUnit;
20 import java.util.concurrent.TimeoutException;
21 import java.util.stream.Collectors;
22 import org.eclipse.jdt.annotation.Nullable;
23 import org.opendaylight.mdsal.binding.api.NotificationPublishService;
24 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
25 import org.opendaylight.transportpce.common.NetworkUtils;
26 import org.opendaylight.transportpce.common.mapping.PortMapping;
27 import org.opendaylight.transportpce.common.network.NetworkTransactionService;
28 import org.opendaylight.transportpce.networkmodel.R2RLinkDiscovery;
29 import org.opendaylight.transportpce.networkmodel.dto.TopologyShard;
30 import org.opendaylight.transportpce.networkmodel.util.ClliNetwork;
31 import org.opendaylight.transportpce.networkmodel.util.LinkIdUtil;
32 import org.opendaylight.transportpce.networkmodel.util.OpenRoadmNetwork;
33 import org.opendaylight.transportpce.networkmodel.util.OpenRoadmOtnTopology;
34 import org.opendaylight.transportpce.networkmodel.util.OpenRoadmTopology;
35 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.networkmodel.rev201116.TopologyUpdateResult;
36 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.networkmodel.rev201116.TopologyUpdateResultBuilder;
37 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.networkmodel.rev201116.topology.update.result.OrdTopologyChanges;
38 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.networkmodel.rev201116.topology.update.result.OrdTopologyChangesBuilder;
39 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.networkmodel.rev201116.topology.update.result.OrdTopologyChangesKey;
40 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.portmapping.rev210315.OpenroadmNodeVersion;
41 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.portmapping.rev210315.network.nodes.NodeInfo;
42 import org.opendaylight.yang.gen.v1.http.org.openroadm.common.network.rev200529.Link1Builder;
43 import org.opendaylight.yang.gen.v1.http.org.openroadm.common.network.rev200529.TerminationPoint1Builder;
44 import org.opendaylight.yang.gen.v1.http.org.openroadm.common.state.types.rev191129.State;
45 import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev170206.circuit.pack.Ports;
46 import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev170206.circuit.packs.CircuitPacks;
47 import org.opendaylight.yang.gen.v1.http.org.openroadm.device.types.rev191129.NodeTypes;
48 import org.opendaylight.yang.gen.v1.http.org.openroadm.equipment.states.types.rev191129.AdminStates;
49 import org.opendaylight.yang.gen.v1.http.org.openroadm.otn.network.topology.rev200529.Link1;
50 import org.opendaylight.yang.gen.v1.http.org.openroadm.otn.network.topology.rev200529.TerminationPoint1;
51 import org.opendaylight.yang.gen.v1.http.org.transportpce.d._interface.ord.topology.types.rev201116.TopologyNotificationTypes;
52 import org.opendaylight.yang.gen.v1.http.transportpce.topology.rev201019.OtnLinkType;
53 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226.NetworkId;
54 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226.Networks;
55 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226.NodeId;
56 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226.networks.Network;
57 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226.networks.NetworkKey;
58 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226.networks.network.Node;
59 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226.networks.network.NodeBuilder;
60 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226.networks.network.NodeKey;
61 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev180226.LinkId;
62 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev180226.Network1;
63 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev180226.Node1;
64 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev180226.Node1Builder;
65 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev180226.TpId;
66 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev180226.networks.network.Link;
67 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev180226.networks.network.LinkBuilder;
68 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev180226.networks.network.LinkKey;
69 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev180226.networks.network.node.TerminationPoint;
70 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev180226.networks.network.node.TerminationPointBuilder;
71 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev180226.networks.network.node.TerminationPointKey;
72 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev180226.networks.network.node.termination.point.SupportingTerminationPoint;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNodeConnectionStatus;
74 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
75 import org.opendaylight.yangtools.yang.common.Uint32;
76 import org.slf4j.Logger;
77 import org.slf4j.LoggerFactory;
78
79 public class NetworkModelServiceImpl implements NetworkModelService {
80
81     private static final Logger LOG = LoggerFactory.getLogger(NetworkModelServiceImpl.class);
82
83     private NetworkTransactionService networkTransactionService;
84     private final R2RLinkDiscovery linkDiscovery;
85     private final PortMapping portMapping;
86     private Map<String, TopologyShard> topologyShardMountedDevice;
87     private Map<String, TopologyShard> otnTopologyShardMountedDevice;
88     // Maps that include topology component changed with its new operational state <id, state>
89     private Map<String, State> linksChanged;
90     private Map<String, State> terminationPointsChanged;
91     // Variables for creating and sending topology update notification
92     private final NotificationPublishService notificationPublishService;
93     private Map<OrdTopologyChangesKey, OrdTopologyChanges> topologyChanges;
94     private TopologyUpdateResult notification = null;
95
96     public NetworkModelServiceImpl(final NetworkTransactionService networkTransactionService,
97             final R2RLinkDiscovery linkDiscovery, PortMapping portMapping,
98             final NotificationPublishService notificationPublishService) {
99
100         this.networkTransactionService = networkTransactionService;
101         this.linkDiscovery = linkDiscovery;
102         this.portMapping = portMapping;
103         this.topologyShardMountedDevice = new HashMap<String, TopologyShard>();
104         this.otnTopologyShardMountedDevice = new HashMap<String, TopologyShard>();
105         this.linksChanged = new HashMap<String, State>();
106         this.terminationPointsChanged = new HashMap<String, State>();
107         this.notificationPublishService = notificationPublishService;
108         this.topologyChanges = new HashMap<OrdTopologyChangesKey, OrdTopologyChanges>();
109     }
110
111     public void init() {
112         LOG.info("init ...");
113     }
114
115     public void close() {
116     }
117
118     @Override
119     public void createOpenRoadmNode(String nodeId, String openRoadmVersion) {
120         try {
121             LOG.info("createOpenROADMNode: {} ", nodeId);
122
123             if (!portMapping.createMappingData(nodeId, openRoadmVersion)) {
124                 LOG.warn("Could not generate port mapping for {} skipping network model creation", nodeId);
125                 return;
126             }
127             NodeInfo nodeInfo = portMapping.getNode(nodeId).getNodeInfo();
128             // node creation in clli-network
129             Node clliNode = ClliNetwork.createNode(nodeId, nodeInfo);
130             InstanceIdentifier<Node> iiClliNode = InstanceIdentifier.builder(Networks.class)
131                 .child(Network.class, new NetworkKey(new NetworkId(NetworkUtils.CLLI_NETWORK_ID)))
132                 .child(Node.class, clliNode.key())
133                 .build();
134             LOG.info("creating node in {}", NetworkUtils.CLLI_NETWORK_ID);
135             networkTransactionService.merge(LogicalDatastoreType.CONFIGURATION, iiClliNode, clliNode);
136
137             // node creation in openroadm-network
138             Node openroadmNetworkNode = OpenRoadmNetwork.createNode(nodeId, nodeInfo);
139             InstanceIdentifier<Node> iiopenroadmNetworkNode = InstanceIdentifier.builder(Networks.class)
140                 .child(Network.class, new NetworkKey(new NetworkId(NetworkUtils.UNDERLAY_NETWORK_ID)))
141                 .child(Node.class, openroadmNetworkNode.key())
142                 .build();
143             LOG.info("creating node in {}", NetworkUtils.UNDERLAY_NETWORK_ID);
144             networkTransactionService.merge(LogicalDatastoreType.CONFIGURATION, iiopenroadmNetworkNode,
145                 openroadmNetworkNode);
146
147             // nodes/links creation in openroadm-topology
148             TopologyShard topologyShard = OpenRoadmTopology.createTopologyShard(portMapping.getNode(nodeId));
149             if (topologyShard != null) {
150                 this.topologyShardMountedDevice.put(nodeId, topologyShard);
151                 for (Node openRoadmTopologyNode : topologyShard.getNodes()) {
152                     LOG.info("creating node {} in {}", openRoadmTopologyNode.getNodeId().getValue(),
153                         NetworkUtils.OVERLAY_NETWORK_ID);
154                     InstanceIdentifier<Node> iiOpenRoadmTopologyNode = InstanceIdentifier.builder(Networks.class)
155                         .child(Network.class, new NetworkKey(new NetworkId(NetworkUtils.OVERLAY_NETWORK_ID)))
156                         .child(Node.class, openRoadmTopologyNode.key())
157                         .build();
158                     networkTransactionService.merge(LogicalDatastoreType.CONFIGURATION, iiOpenRoadmTopologyNode,
159                         openRoadmTopologyNode);
160                 }
161                 for (Link openRoadmTopologyLink : topologyShard.getLinks()) {
162                     LOG.info("creating link {} in {}", openRoadmTopologyLink.getLinkId().getValue(),
163                         NetworkUtils.OVERLAY_NETWORK_ID);
164                     InstanceIdentifier<Link> iiOpenRoadmTopologyLink = InstanceIdentifier.builder(Networks.class)
165                         .child(Network.class, new NetworkKey(new NetworkId(NetworkUtils.OVERLAY_NETWORK_ID)))
166                         .augmentation(Network1.class)
167                         .child(Link.class, openRoadmTopologyLink.key())
168                         .build();
169                     networkTransactionService.merge(LogicalDatastoreType.CONFIGURATION, iiOpenRoadmTopologyLink,
170                         openRoadmTopologyLink);
171                 }
172             } else {
173                 LOG.error("Unable to create openroadm-topology shard for node {}!", nodeId);
174             }
175             // nodes/links creation in otn-topology
176             if (nodeInfo.getNodeType().getIntValue() == 2 && (nodeInfo.getOpenroadmVersion().getIntValue() != 1)) {
177                 createOpenRoadmOtnNode(nodeId);
178             }
179             networkTransactionService.commit().get();
180             // neighbour links through LLDP
181             if (nodeInfo.getNodeType().getIntValue() == 1) {
182                 this.linkDiscovery.readLLDP(new NodeId(nodeId), openRoadmVersion);
183             }
184             LOG.info("all nodes and links created");
185         } catch (InterruptedException | ExecutionException e) {
186             LOG.error("ERROR: ", e);
187         }
188     }
189
190     @Override
191     public void setOpenRoadmNodeStatus(String nodeId, NetconfNodeConnectionStatus.ConnectionStatus connectionStatus) {
192         LOG.info("setOpenROADMNodeStatus: {} {}", nodeId, connectionStatus.name());
193         /*
194           TODO: set connection status of the device in model,
195           TODO: so we don't need to keep it in memory (Set<String> currentMountedDevice)
196           TODO: unfortunately there is no connection status OpenROADM in network models
197           TODO: waiting for new model version
198          */
199     }
200
201     /*
202      @see org.opendaylight.transportpce.networkmodel.service.NetworkModelService# deleteOpenROADMnode(java.lang.String)
203      */
204
205     @Override
206     public void deleteOpenRoadmnode(String nodeId) {
207         try {
208             NodeKey nodeIdKey = new NodeKey(new NodeId(nodeId));
209
210             LOG.info("deleting node in {}", NetworkUtils.UNDERLAY_NETWORK_ID);
211             InstanceIdentifier<Node> iiopenroadmNetworkNode = InstanceIdentifier.builder(Networks.class)
212                 .child(Network.class, new NetworkKey(new NetworkId(NetworkUtils.UNDERLAY_NETWORK_ID)))
213                 .child(Node.class, nodeIdKey)
214                 .build();
215             this.networkTransactionService.delete(LogicalDatastoreType.CONFIGURATION, iiopenroadmNetworkNode);
216
217             TopologyShard topologyShard = this.topologyShardMountedDevice.get(nodeId);
218             if (topologyShard != null) {
219                 for (Node openRoadmTopologyNode : topologyShard.getNodes()) {
220                     LOG.info("deleting node {} in {}", openRoadmTopologyNode.getNodeId().getValue(),
221                         NetworkUtils.OVERLAY_NETWORK_ID);
222                     InstanceIdentifier<Node> iiOpenRoadmTopologyNode = InstanceIdentifier.builder(Networks.class)
223                         .child(Network.class, new NetworkKey(new NetworkId(NetworkUtils.OVERLAY_NETWORK_ID)))
224                         .child(Node.class, openRoadmTopologyNode.key())
225                         .build();
226                     this.networkTransactionService.delete(LogicalDatastoreType.CONFIGURATION, iiOpenRoadmTopologyNode);
227                 }
228                 for (Link openRoadmTopologyLink : topologyShard.getLinks()) {
229                     LOG.info("deleting link {} in {}", openRoadmTopologyLink.getLinkId().getValue(),
230                         NetworkUtils.OVERLAY_NETWORK_ID);
231                     InstanceIdentifier<Link> iiOpenRoadmTopologyLink = InstanceIdentifier.builder(Networks.class)
232                         .child(Network.class, new NetworkKey(new NetworkId(NetworkUtils.OVERLAY_NETWORK_ID)))
233                         .augmentation(Network1.class)
234                         .child(Link.class, openRoadmTopologyLink.key())
235                         .build();
236                     this.networkTransactionService.delete(LogicalDatastoreType.CONFIGURATION, iiOpenRoadmTopologyLink);
237                 }
238             } else {
239                 LOG.warn("TopologyShard for node '{}' is not present", nodeId);
240             }
241             @Nullable
242             OpenroadmNodeVersion deviceVersion = this.portMapping.getNode(nodeId).getNodeInfo().getOpenroadmVersion();
243             @Nullable
244             NodeTypes nodeType = this.portMapping.getNode(nodeId).getNodeInfo().getNodeType();
245             if (nodeType.getIntValue() == 2 && deviceVersion.getIntValue() != 1) {
246                 TopologyShard otnTopologyShard = this.otnTopologyShardMountedDevice.get(nodeId);
247                 if (otnTopologyShard != null) {
248                     LOG.info("suppression de otnTopologyShard = {}", otnTopologyShard.toString());
249                     for (Node otnTopologyNode : otnTopologyShard.getNodes()) {
250                         LOG.info("deleting node {} in {}", otnTopologyNode.getNodeId().getValue(),
251                             NetworkUtils.OTN_NETWORK_ID);
252                         InstanceIdentifier<Node> iiotnTopologyNode = InstanceIdentifier.builder(Networks.class)
253                             .child(Network.class, new NetworkKey(new NetworkId(NetworkUtils.OTN_NETWORK_ID)))
254                             .child(Node.class, otnTopologyNode.key())
255                             .build();
256                         this.networkTransactionService.delete(LogicalDatastoreType.CONFIGURATION, iiotnTopologyNode);
257                     }
258                     for (Link otnTopologyLink : otnTopologyShard.getLinks()) {
259                         LOG.info("deleting link {} in {}", otnTopologyLink.getLinkId().getValue(),
260                             NetworkUtils.OTN_NETWORK_ID);
261                         InstanceIdentifier<Link> iiotnTopologyLink = InstanceIdentifier.builder(Networks.class)
262                             .child(Network.class, new NetworkKey(new NetworkId(NetworkUtils.OTN_NETWORK_ID)))
263                             .augmentation(Network1.class)
264                             .child(Link.class, otnTopologyLink.key())
265                             .build();
266                         this.networkTransactionService.delete(LogicalDatastoreType.CONFIGURATION, iiotnTopologyLink);
267                     }
268                 }
269             }
270
271             LOG.info("deleteOpenROADMnode: {} version {}", nodeId, deviceVersion.getName());
272             this.portMapping.deleteMappingData(nodeId);
273
274             this.networkTransactionService.commit().get(1, TimeUnit.SECONDS);
275             LOG.info("all nodes and links deleted ! ");
276         } catch (InterruptedException | ExecutionException | TimeoutException e) {
277             LOG.error("Error when trying to delete node : {}", nodeId, e);
278         }
279     }
280
281     @Override
282     public void updateOpenRoadmNetworkTopology(String nodeId, CircuitPacks changedCpack) {
283         // Clear maps for each NETCONF notification received
284         this.linksChanged.clear();
285         this.terminationPointsChanged.clear();
286         this.topologyChanges.clear();
287         // 1. Get the list links and nodes of the current openroadm network topology
288         List<Link> linkList = null;
289         List<Node> nodesList = null;
290         try {
291             InstanceIdentifier.InstanceIdentifierBuilder<Network1> network1IID =
292                 InstanceIdentifier.builder(Networks.class)
293                     .child(Network.class, new NetworkKey(new NetworkId(NetworkUtils.OVERLAY_NETWORK_ID)))
294                     .augmentation(Network1.class);
295             InstanceIdentifier.InstanceIdentifierBuilder<Network> networkIID =
296                 InstanceIdentifier.builder(Networks.class)
297                     .child(Network.class, new NetworkKey(new NetworkId(NetworkUtils.OVERLAY_NETWORK_ID)));
298             Optional<Network> networkOptional = this.networkTransactionService.read(LogicalDatastoreType.CONFIGURATION,
299                 networkIID.build()).get();
300             Optional<Network1> network1Optional =
301                 this.networkTransactionService.read(LogicalDatastoreType.CONFIGURATION, network1IID.build()).get();
302             if (network1Optional.isPresent()) {
303                 // Links list
304                 linkList = new ArrayList<>(Objects.requireNonNull(network1Optional.get().getLink()).values());
305             }
306             if (networkOptional.isPresent()) {
307                 // Nodes list
308                 nodesList = new ArrayList<>(Objects.requireNonNull(networkOptional.get().getNode()).values());
309             }
310         } catch (InterruptedException e) {
311             LOG.error("Couldn't get list of links in the network. Error={}", e.getMessage());
312             Thread.currentThread().interrupt();
313         } catch (ExecutionException e) {
314             LOG.error("Couldn't get list of links in the network. Error={}", e.getMessage());
315         }
316         /* 2. For simplicity the update is only considered in the case of a WSSDEG circuit pack change where client and
317         line ports (external ports) of a node are included and there is a 1-to-1 port mapping to the nodes TPs. The
318         mapping between ports and TPs internal of a node is a bit different as the is a 1-to-many port mapping */
319         String cpackType = changedCpack.getCircuitPackType();
320         switch (cpackType) {
321             case "ADDROP":
322                 LOG.info("ADDROP circuit pack modified");
323                 setTerminationPointsChangedMap(changedCpack, nodeId);
324                 // setTpStateHashmap(changedCpack);
325                 break;
326             case "WSSDEG":
327                 LOG.info("WSSDEG circuit pack modified");
328                 setTerminationPointsChangedMap(changedCpack, nodeId);
329                 // 3. Update the termination points of the node that sent a NETCONF notification
330                 updateOpenRoadmNetworkTopologyTPs(nodesList, nodeId);
331                 // 4. Update the links of the topology affected by the changes on TPs (if any)
332                 updateOpenRoadmNetworkTopologyLinks(linkList, nodesList);
333                 // Send notification to service handler
334                 sendNotification(TopologyNotificationTypes.OpenroadmTopologyUpdate, this.topologyChanges);
335                 break;
336             case "port":
337                 LOG.info("port circuit pack modified");
338                 break;
339             case "pluggable":
340                 LOG.info("pluggable circuit pack modified");
341                 break;
342             default:
343                 LOG.warn("Circuitp pack of type {} not recognized", cpackType);
344         }
345     }
346
347     @Override
348     public void createOtnLinks(String nodeA, String tpA, String nodeZ, String tpZ, OtnLinkType linkType) {
349         TopologyShard otnTopologyShard;
350         switch (linkType) {
351             case OTU4:
352                 otnTopologyShard = OpenRoadmOtnTopology.createOtnLinks(nodeA, tpA, nodeZ, tpZ, linkType);
353                 break;
354             case ODTU4:
355                 String nodeTopoA = new StringBuilder(nodeA).append("-").append(tpA.split("-")[0]).toString();
356                 String nodeTopoZ = new StringBuilder(nodeZ).append("-").append(tpZ.split("-")[0]).toString();
357                 List<LinkId> linkIdList = new ArrayList<>();
358                 linkIdList.add(LinkIdUtil.buildOtnLinkId(nodeTopoA, tpA, nodeTopoZ, tpZ, "OTU4"));
359                 linkIdList.add(LinkIdUtil.buildOtnLinkId(nodeTopoZ, tpZ, nodeTopoA, tpA, "OTU4"));
360                 List<Link> supportedOtu4links = getOtnLinks(linkIdList);
361                 List<TerminationPoint> tps = getOtnNodeTps(nodeTopoA, tpA, nodeTopoZ, tpZ);
362
363                 otnTopologyShard = OpenRoadmOtnTopology.createOtnLinks(supportedOtu4links, tps);
364                 break;
365             default:
366                 LOG.error("unknown otn link type {}", linkType);
367                 otnTopologyShard = new TopologyShard(null, null);
368         }
369         if (otnTopologyShard.getLinks() != null) {
370             for (Link otnTopologyLink : otnTopologyShard.getLinks()) {
371                 LOG.info("creating and updating otn links {} in {}", otnTopologyLink.getLinkId().getValue(),
372                     NetworkUtils.OVERLAY_NETWORK_ID);
373                 InstanceIdentifier<Link> iiOtnTopologyLink = InstanceIdentifier.builder(Networks.class)
374                     .child(Network.class, new NetworkKey(new NetworkId(NetworkUtils.OTN_NETWORK_ID)))
375                     .augmentation(Network1.class)
376                     .child(Link.class, otnTopologyLink.key())
377                     .build();
378                 networkTransactionService.merge(LogicalDatastoreType.CONFIGURATION, iiOtnTopologyLink, otnTopologyLink);
379             }
380         }
381         if (otnTopologyShard.getTps() != null) {
382             for (TerminationPoint otnTopologyTp : otnTopologyShard.getTps()) {
383                 LOG.info("updating otn nodes TP {} in otn-topology", otnTopologyTp.getTpId().getValue());
384                 List<SupportingTerminationPoint> supportingTerminationPoint =
385                     new ArrayList<>(otnTopologyTp.nonnullSupportingTerminationPoint().values());
386                 InstanceIdentifier<TerminationPoint> iiOtnTopologyTp = InstanceIdentifier.builder(Networks.class)
387                     .child(Network.class, new NetworkKey(new NetworkId(NetworkUtils.OTN_NETWORK_ID)))
388                     .child(Node.class, new NodeKey(supportingTerminationPoint.get(0).getNodeRef()))
389                     .augmentation(Node1.class)
390                     .child(TerminationPoint.class, new TerminationPointKey(otnTopologyTp.getTpId()))
391                     .build();
392                 networkTransactionService.merge(LogicalDatastoreType.CONFIGURATION, iiOtnTopologyTp, otnTopologyTp);
393             }
394         }
395         try {
396             networkTransactionService.commit().get();
397         } catch (InterruptedException | ExecutionException e) {
398             LOG.error("Error adding OTN links in otn-topology", e);
399         }
400         LOG.info("OTN links created");
401     }
402
403     @Override
404     public void deleteOtnLinks(String nodeA, String tpA, String nodeZ, String tpZ, OtnLinkType linkType) {
405         TopologyShard otnTopologyShard;
406         String nodeTopoA = new StringBuilder(nodeA).append("-").append(tpA.split("-")[0]).toString();
407         String nodeTopoZ = new StringBuilder(nodeZ).append("-").append(tpZ.split("-")[0]).toString();
408         List<Link> otu4Links;
409         List<LinkId> linkIdList = new ArrayList<>();
410         switch (linkType) {
411             case OTU4:
412                 linkIdList.add(LinkIdUtil.buildOtnLinkId(nodeTopoA, tpA, nodeTopoZ, tpZ, "OTU4"));
413                 linkIdList.add(LinkIdUtil.buildOtnLinkId(nodeTopoZ, tpZ, nodeTopoA, tpA, "OTU4"));
414                 otu4Links = getOtnLinks(linkIdList);
415                 if (checkLinks(otu4Links)) {
416                     deleteLinks(otu4Links);
417                 } else {
418                     LOG.error("Error deleting OTU4 links");
419                 }
420                 otnTopologyShard = new TopologyShard(null, null);
421                 break;
422             case ODTU4:
423                 linkIdList.add(LinkIdUtil.buildOtnLinkId(nodeTopoA, tpA, nodeTopoZ, tpZ, "ODU4"));
424                 linkIdList.add(LinkIdUtil.buildOtnLinkId(nodeTopoZ, tpZ, nodeTopoA, tpA, "ODU4"));
425                 List<Link> odu4Links = getOtnLinks(linkIdList);
426                 List<TerminationPoint> tps = getOtnNodeTps(nodeTopoA, tpA, nodeTopoZ, tpZ);
427                 if (checkLinks(odu4Links) && checkTerminationPoints(tps)) {
428                     deleteLinks(odu4Links);
429                     linkIdList.clear();
430                     linkIdList.add(LinkIdUtil.buildOtnLinkId(nodeTopoA, tpA, nodeTopoZ, tpZ, "OTU4"));
431                     linkIdList.add(LinkIdUtil.buildOtnLinkId(nodeTopoZ, tpZ, nodeTopoA, tpA, "OTU4"));
432                     otu4Links = getOtnLinks(linkIdList);
433                     otnTopologyShard = OpenRoadmOtnTopology.deleteOtnLinks(otu4Links, tps);
434                 } else {
435                     LOG.error("Error deleting ODU4 links");
436                     otnTopologyShard = new TopologyShard(null, null);
437                 }
438                 break;
439             default:
440                 LOG.error("unknown otn link type {}", linkType);
441                 otnTopologyShard = new TopologyShard(null, null);
442         }
443         if (otnTopologyShard.getLinks() != null) {
444             for (Link otnTopologyLink : otnTopologyShard.getLinks()) {
445                 LOG.info("deleting and updating otn links {} in {}", otnTopologyLink.getLinkId().getValue(),
446                     NetworkUtils.OVERLAY_NETWORK_ID);
447                 InstanceIdentifier<Link> iiOtnTopologyLink = InstanceIdentifier.builder(Networks.class)
448                     .child(Network.class, new NetworkKey(new NetworkId(NetworkUtils.OTN_NETWORK_ID)))
449                     .augmentation(Network1.class)
450                     .child(Link.class, otnTopologyLink.key())
451                     .build();
452                 networkTransactionService.merge(LogicalDatastoreType.CONFIGURATION, iiOtnTopologyLink, otnTopologyLink);
453             }
454         }
455         if (otnTopologyShard.getTps() != null) {
456             for (TerminationPoint otnTopologyTp : otnTopologyShard.getTps()) {
457                 LOG.info("updating otn nodes TP {} in otn-topology", otnTopologyTp.getTpId().getValue());
458                 List<SupportingTerminationPoint> supportingTerminationPoint =
459                     new ArrayList<>(otnTopologyTp.nonnullSupportingTerminationPoint().values());
460                 InstanceIdentifier<TerminationPoint> iiOtnTopologyTp = InstanceIdentifier.builder(Networks.class)
461                     .child(Network.class, new NetworkKey(new NetworkId(NetworkUtils.OTN_NETWORK_ID)))
462                     .child(Node.class, new NodeKey(supportingTerminationPoint.get(0).getNodeRef()))
463                     .augmentation(Node1.class)
464                     .child(TerminationPoint.class, new TerminationPointKey(otnTopologyTp.getTpId()))
465                     .build();
466                 networkTransactionService.put(LogicalDatastoreType.CONFIGURATION, iiOtnTopologyTp, otnTopologyTp);
467             }
468         }
469         try {
470             networkTransactionService.commit().get();
471         } catch (InterruptedException | ExecutionException e) {
472             LOG.error("Error deleting OTN links in otn-topology", e);
473         }
474         LOG.info("OTN links deletion terminated");
475     }
476
477     @Override
478     public void updateOtnLinks(List<String> nodeTps, String serviceRate, Short tribPortNb, Short tribSoltNb,
479             boolean isDeletion) {
480         List<Link> supportedOdu4Links = getSupportingOdu4Links(nodeTps);
481         List<TerminationPoint> tps = getOtnNodeTps(nodeTps);
482         TopologyShard otnTopologyShard;
483         otnTopologyShard = OpenRoadmOtnTopology.updateOtnLinks(supportedOdu4Links, tps, serviceRate, tribPortNb,
484             tribSoltNb, isDeletion);
485         if (otnTopologyShard.getLinks() != null) {
486             for (Link otnTopologyLink : otnTopologyShard.getLinks()) {
487                 LOG.info("creating and updating otn links {} in {}", otnTopologyLink.getLinkId().getValue(),
488                     NetworkUtils.OVERLAY_NETWORK_ID);
489                 InstanceIdentifier<Link> iiOtnTopologyLink = InstanceIdentifier.builder(Networks.class)
490                     .child(Network.class, new NetworkKey(new NetworkId(NetworkUtils.OTN_NETWORK_ID)))
491                     .augmentation(Network1.class)
492                     .child(Link.class, new LinkKey(new LinkId(otnTopologyLink.getLinkId().getValue())))
493                     .build();
494                 networkTransactionService.merge(LogicalDatastoreType.CONFIGURATION, iiOtnTopologyLink, otnTopologyLink);
495             }
496         }
497         if (otnTopologyShard.getTps() != null) {
498             for (TerminationPoint otnTopologyTp : otnTopologyShard.getTps()) {
499                 LOG.info("updating otn nodes TP {} in otn-topology", otnTopologyTp.getTpId().getValue());
500                 List<SupportingTerminationPoint> supportingTerminationPoint =
501                     new ArrayList<>(otnTopologyTp.nonnullSupportingTerminationPoint().values());
502                 InstanceIdentifier<TerminationPoint> iiOtnTopologyTp = InstanceIdentifier.builder(Networks.class)
503                     .child(Network.class, new NetworkKey(new NetworkId(NetworkUtils.OTN_NETWORK_ID)))
504                     .child(Node.class, new NodeKey(supportingTerminationPoint.get(0).getNodeRef()))
505                     .augmentation(Node1.class)
506                     .child(TerminationPoint.class, new TerminationPointKey(new TpId(otnTopologyTp.getTpId()
507                         .getValue())))
508                     .build();
509                 if (isDeletion) {
510                     networkTransactionService.merge(LogicalDatastoreType.CONFIGURATION, iiOtnTopologyTp, otnTopologyTp);
511                 } else {
512                     networkTransactionService.put(LogicalDatastoreType.CONFIGURATION, iiOtnTopologyTp, otnTopologyTp);
513                 }
514             }
515         }
516         try {
517             networkTransactionService.commit().get();
518         } catch (InterruptedException | ExecutionException e) {
519             LOG.error("Error updating OTN links in otn-topology", e);
520         }
521     }
522
523     private List<Link> getOtnLinks(List<LinkId> linkIds) {
524         List<Link> links = new ArrayList<>();
525         for (LinkId linkId : linkIds) {
526             InstanceIdentifier<Link> iiLink = InstanceIdentifier.builder(Networks.class)
527                 .child(Network.class, new NetworkKey(new NetworkId(NetworkUtils.OTN_NETWORK_ID)))
528                 .augmentation(Network1.class)
529                 .child(Link.class, new LinkKey(linkId))
530                 .build();
531             ListenableFuture<Optional<Link>> linkOptLf = networkTransactionService
532                 .read(LogicalDatastoreType.CONFIGURATION, iiLink);
533             if (linkOptLf.isDone()) {
534                 try {
535                     if (linkOptLf.get().isPresent()) {
536                         links.add(linkOptLf.get().get());
537                     }
538                 } catch (InterruptedException | ExecutionException e) {
539                     LOG.error("Error retreiving OTN links from otn-topology", e);
540                 }
541             } else {
542                 LOG.error("Error retreiving link {} from otn-topology", linkId.getValue());
543             }
544         }
545         return links;
546     }
547
548     private boolean checkLinks(List<Link> links) {
549         if (links.isEmpty()) {
550             return false;
551         }
552         for (Link link : links) {
553             if (link.augmentation(Link1.class) != null
554                     && !link.augmentation(Link1.class).getUsedBandwidth().equals(Uint32.valueOf(0))) {
555                 return false;
556             }
557         }
558         return true;
559     }
560
561     private boolean checkTerminationPoints(List<TerminationPoint> tps) {
562         if (tps.isEmpty()) {
563             return false;
564         }
565         for (TerminationPoint tp : tps) {
566             if (tp.augmentation(TerminationPoint1.class) != null && tp.augmentation(TerminationPoint1.class)
567                     .getXpdrTpPortConnectionAttributes().getTsPool() != null && tp.augmentation(TerminationPoint1.class)
568                     .getXpdrTpPortConnectionAttributes().getTsPool().size() != 80) {
569                 return false;
570             }
571         }
572         return true;
573     }
574
575     private List<TerminationPoint> getOtnNodeTps(String nodeTopoA, String tpA, String nodeTopoZ, String tpZ) {
576         List<TerminationPoint> tps = new ArrayList<>();
577         InstanceIdentifier<TerminationPoint> iiTpA = InstanceIdentifier.builder(Networks.class)
578             .child(Network.class, new NetworkKey(new NetworkId(NetworkUtils.OTN_NETWORK_ID)))
579             .child(Node.class, new NodeKey(new NodeId(nodeTopoA)))
580             .augmentation(Node1.class)
581             .child(TerminationPoint.class, new TerminationPointKey(new TpId(tpA)))
582             .build();
583         Optional<TerminationPoint> tpAOpt = Optional.empty();
584         InstanceIdentifier<TerminationPoint> iiTpZ = InstanceIdentifier.builder(Networks.class)
585             .child(Network.class, new NetworkKey(new NetworkId(NetworkUtils.OTN_NETWORK_ID)))
586             .child(Node.class, new NodeKey(new NodeId(nodeTopoZ)))
587             .augmentation(Node1.class)
588             .child(TerminationPoint.class, new TerminationPointKey(new TpId(tpZ)))
589             .build();
590         Optional<TerminationPoint> tpZOpt = Optional.empty();
591
592         if (networkTransactionService.read(LogicalDatastoreType.CONFIGURATION, iiTpA).isDone()
593                 && networkTransactionService.read(LogicalDatastoreType.CONFIGURATION, iiTpZ).isDone()) {
594             try {
595                 tpAOpt = networkTransactionService.read(LogicalDatastoreType.CONFIGURATION, iiTpA).get();
596                 tpZOpt = networkTransactionService.read(LogicalDatastoreType.CONFIGURATION, iiTpZ).get();
597             } catch (InterruptedException | ExecutionException e) {
598                 LOG.error("Error retreiving tp {} of node {} or tp {} from node {} from otn-topology", tpA, nodeTopoA,
599                     tpZ, nodeTopoZ, e);
600             }
601         } else {
602             LOG.error("error getting node termination points from the datastore");
603         }
604
605         if (tpAOpt.isPresent() && tpZOpt.isPresent()) {
606             tps.add(tpAOpt.get());
607             tps.add(tpZOpt.get());
608         }
609         return tps;
610     }
611
612     private List<TerminationPoint> getOtnNodeTps(List<String> nodeTopoTps) {
613         List<TerminationPoint> tps = new ArrayList<>();
614         for (String str : nodeTopoTps) {
615             String nodeId = str.split("--")[0];
616             String tp = str.split("--")[1];
617             InstanceIdentifier<TerminationPoint> iiTp = InstanceIdentifier.builder(Networks.class)
618                 .child(Network.class, new NetworkKey(new NetworkId(NetworkUtils.OTN_NETWORK_ID)))
619                 .child(Node.class, new NodeKey(new NodeId(nodeId)))
620                 .augmentation(Node1.class)
621                 .child(TerminationPoint.class, new TerminationPointKey(new TpId(tp)))
622                 .build();
623             Optional<TerminationPoint> tpOpt;
624             if (networkTransactionService.read(LogicalDatastoreType.CONFIGURATION, iiTp).isDone()) {
625                 try {
626                     tpOpt = networkTransactionService.read(LogicalDatastoreType.CONFIGURATION, iiTp).get();
627                     if (tpOpt.isPresent()) {
628                         tps.add(tpOpt.get());
629                     }
630                 } catch (InterruptedException | ExecutionException e) {
631                     LOG.error("Error retreiving tp {} of node {} from otn-topology", tp, nodeId, e);
632                 }
633             } else {
634                 LOG.error("error getting node termination points from the datastore");
635             }
636         }
637         if (tps.isEmpty()) {
638             LOG.warn("returning null");
639             return null;
640         } else {
641             LOG.info("returning tps = {}", tps.toString());
642             return tps;
643         }
644     }
645
646     private void deleteLinks(List<Link> links) {
647         for (Link otnTopologyLink : links) {
648             LOG.info("deleting link {} from {}", otnTopologyLink.getLinkId().getValue(),
649                 NetworkUtils.OVERLAY_NETWORK_ID);
650             InstanceIdentifier<Link> iiOtnTopologyLink = InstanceIdentifier.builder(Networks.class)
651                 .child(Network.class, new NetworkKey(new NetworkId(NetworkUtils.OTN_NETWORK_ID)))
652                 .augmentation(Network1.class)
653                 .child(Link.class, otnTopologyLink.key())
654                 .build();
655             networkTransactionService.delete(LogicalDatastoreType.CONFIGURATION, iiOtnTopologyLink);
656         }
657         try {
658             networkTransactionService.commit().get();
659         } catch (InterruptedException | ExecutionException e) {
660             LOG.error("Error deleting OTN links from otn-topology", e);
661         }
662     }
663
664     private List<Link> getSupportingOdu4Links(List<String> nodesTopoTps) {
665         InstanceIdentifier<Network1> iiOtnTopologyLinks = InstanceIdentifier.builder(Networks.class)
666             .child(Network.class, new NetworkKey(new NetworkId(NetworkUtils.OTN_NETWORK_ID)))
667             .augmentation(Network1.class)
668             .build();
669         ListenableFuture<Optional<Network1>> netw1Fl = networkTransactionService
670             .read(LogicalDatastoreType.CONFIGURATION, iiOtnTopologyLinks);
671         Optional<Network1> netw1Opt = Optional.empty();
672         if (netw1Fl.isDone()) {
673             try {
674                 netw1Opt = netw1Fl.get();
675             } catch (InterruptedException | ExecutionException e) {
676                 LOG.error("Error retreiving list of links from otn-topology", e);
677             }
678         }
679         List<Link> odu4links = null;
680         if (netw1Opt.isPresent() && netw1Opt.get().getLink() != null) {
681             odu4links = netw1Opt
682                 .get()
683                 .nonnullLink().values()
684                 .stream().filter(lk -> lk.getLinkId().getValue().startsWith("ODU4"))
685                 .collect(Collectors.toList());
686         }
687         List<Link> links = new ArrayList<>();
688         if (odu4links != null) {
689             for (String str : nodesTopoTps) {
690                 String[] nodeAndTp = str.split("--");
691                 if (nodeAndTp.length >= 2) {
692                     String nodeId = nodeAndTp[0];
693                     String tp = nodeAndTp[1];
694                     Link slink = odu4links.stream().filter(lk -> lk.getSource().getSourceNode().getValue()
695                         .equals(nodeId) && lk.getSource().getSourceTp().toString().equals(tp)).findFirst().get();
696                     if (!links.contains(slink)) {
697                         links.add(slink);
698                     }
699                     Link dlink = odu4links.stream().filter(lk -> lk.getDestination().getDestNode().getValue()
700                         .equals(nodeId) && lk.getDestination().getDestTp().toString().equals(tp)).findFirst().get();
701                     if (!links.contains(dlink)) {
702                         links.add(dlink);
703                     }
704                 }
705             }
706             LOG.debug("odu4links = {}", links.toString());
707             return links;
708         } else {
709             return null;
710         }
711     }
712
713     private void createOpenRoadmOtnNode(String nodeId) {
714         TopologyShard otnTopologyShard = OpenRoadmOtnTopology.createTopologyShard(portMapping.getNode(nodeId));
715         if (otnTopologyShard != null) {
716             this.otnTopologyShardMountedDevice.put(nodeId, otnTopologyShard);
717             for (Node otnTopologyNode : otnTopologyShard.getNodes()) {
718                 LOG.info("creating otn node {} in {}", otnTopologyNode.getNodeId().getValue(),
719                     NetworkUtils.OTN_NETWORK_ID);
720                 InstanceIdentifier<Node> iiOtnTopologyNode = InstanceIdentifier.builder(Networks.class)
721                     .child(Network.class, new NetworkKey(new NetworkId(NetworkUtils.OTN_NETWORK_ID)))
722                     .child(Node.class, otnTopologyNode.key())
723                     .build();
724                 networkTransactionService.merge(LogicalDatastoreType.CONFIGURATION, iiOtnTopologyNode, otnTopologyNode);
725             }
726             for (Link otnTopologyLink : otnTopologyShard.getLinks()) {
727                 LOG.info("creating otn link {} in {}", otnTopologyLink.getLinkId().getValue(),
728                     NetworkUtils.OVERLAY_NETWORK_ID);
729                 InstanceIdentifier<Link> iiOtnTopologyLink = InstanceIdentifier.builder(Networks.class)
730                     .child(Network.class, new NetworkKey(new NetworkId(NetworkUtils.OTN_NETWORK_ID)))
731                     .augmentation(Network1.class)
732                     .child(Link.class, otnTopologyLink.key())
733                     .build();
734                 networkTransactionService.merge(LogicalDatastoreType.CONFIGURATION, iiOtnTopologyLink, otnTopologyLink);
735             }
736         } else {
737             LOG.error("Unable to create OTN topology shard for node {}!", nodeId);
738         }
739
740     }
741
742     private void setTerminationPointsChangedMap(CircuitPacks changedCpack, String nodeId) {
743         List<Ports> portsList = new ArrayList<>(Objects.requireNonNull(changedCpack.getPorts()).values());
744         for (Ports port : portsList) {
745             String lcp = port.getLogicalConnectionPoint();
746             if (lcp != null) {
747                 String abstractNodeid = nodeId + "-" + lcp.split("-")[0];
748                 if (!this.terminationPointsChanged.containsKey(abstractNodeid + "-" + lcp)) {
749                     LOG.info("Node id {}, LCP {}", abstractNodeid, lcp);
750                     this.terminationPointsChanged.put(abstractNodeid + "-" + lcp,
751                             State.forValue(port.getOperationalState().getIntValue()));
752                 }
753             }
754         }
755     }
756
757     private void updateOpenRoadmNetworkTopologyTPs(List<Node> nodesList, String nodeId) {
758         /* 1. The nodes in nodesList are abstract nodes (i.e. ROADMA01-DEG1) and we have the id of the node that has
759         a change (i.e. ROADMA01). So we only need to look for the abstract nodes that belong to the physical node. */
760         String abstractNodeId;
761         for (Node node : nodesList) {
762             abstractNodeId = Objects.requireNonNull(node.getNodeId()).getValue();
763             // Checking if the node is operationally inService
764             if (abstractNodeId.contains(nodeId) && node.augmentation(org.opendaylight.yang.gen.v1.http
765                     .org.openroadm.common.network.rev200529.Node1.class)
766                     .getOperationalState().equals(State.InService)) {
767                 /* 2. Check if the state of the termination points from the topology shard are equal to the state of
768                 the termination points in the previously created map. */
769                 List<TerminationPoint> tpList = new ArrayList<>(Objects.requireNonNull(node.augmentation(Node1.class))
770                     .getTerminationPoint().values());
771                 Map<TerminationPointKey, TerminationPoint> updatedTpMap = new HashMap<>();
772                 for (TerminationPoint tp : tpList) {
773                     String tpId = Objects.requireNonNull(tp.getTpId()).getValue();
774                     State tpState = Objects.requireNonNull(tp.augmentation(org.opendaylight.yang.gen.v1.http
775                         .org.openroadm.common.network.rev200529.TerminationPoint1.class)).getOperationalState();
776                     String key = abstractNodeId + "-" + tpId;
777                     if (this.terminationPointsChanged.containsKey(key)
778                             && !this.terminationPointsChanged.get(key).equals(tpState)) {
779                         // The state of a termination point has changed... updating
780                         State newTpOperationalState = null;
781                         AdminStates newTpAdminState = null;
782                         /* 3. If the TP has changed its state, it has to be added to the links Map, as a Link state
783                         is defined by the state of the TPs that model the link. */
784                         switch (this.terminationPointsChanged.get(key)) {
785                             case InService:
786                                 newTpAdminState = AdminStates.InService;
787                                 newTpOperationalState = State.InService;
788                                 // Add TP and state inService to the links Map
789                                 this.linksChanged.put(key, State.InService);
790                                 // Update topology change list for service handler notification
791                                 this.topologyChanges.put(
792                                     new OrdTopologyChangesKey(node.getNodeId().getValue() + "-" + tpId),
793                                     new OrdTopologyChangesBuilder()
794                                         .setId(node.getNodeId().getValue() + "-" + tpId)
795                                         .setState(newTpOperationalState)
796                                         .build());
797                                 break;
798                             case OutOfService:
799                                 newTpAdminState = AdminStates.OutOfService;
800                                 newTpOperationalState = State.OutOfService;
801                                 // Add TP and state outOfService to the links Map
802                                 this.linksChanged.put(key, State.OutOfService);
803                                 // Update topology change list for service handler notification
804                                 this.topologyChanges.put(
805                                     new OrdTopologyChangesKey(node.getNodeId().getValue() + "-" + tpId),
806                                     new OrdTopologyChangesBuilder()
807                                         .setId(node.getNodeId().getValue() + "-" + tpId)
808                                         .setState(newTpOperationalState)
809                                         .build());
810                                 break;
811                             case Degraded:
812                                 LOG.warn("Operational state Degraded not handled");
813                                 break;
814                             default:
815                                 LOG.warn("Unrecognized state!");
816                         }
817                         // 4. Add modified TP to the updated List.
818                         TerminationPoint updTp = new TerminationPointBuilder().withKey(tp.key())
819                             .setTpId(tp.getTpId())
820                             .addAugmentation(new TerminationPoint1Builder()
821                                 .setAdministrativeState(newTpAdminState)
822                                 .setOperationalState(newTpOperationalState)
823                                 .build())
824                             .build();
825                         updatedTpMap.put(tp.key(), updTp);
826                     }
827                     // 5. Update the list of termination points of the corresponding node and merge to the datastore.
828                     if (!updatedTpMap.isEmpty()) {
829                         Node updNode = new NodeBuilder().setNodeId(node.getNodeId()).addAugmentation(new Node1Builder()
830                             .setTerminationPoint(updatedTpMap).build()).build();
831                         InstanceIdentifier<Node> iiOpenRoadmTopologyNode = InstanceIdentifier.builder(
832                             Networks.class).child(Network.class, new NetworkKey(
833                                     new NetworkId(NetworkUtils.OVERLAY_NETWORK_ID))).child(Node.class, node.key())
834                             .build();
835                         networkTransactionService.merge(LogicalDatastoreType.CONFIGURATION, iiOpenRoadmTopologyNode,
836                             updNode);
837                         try {
838                             networkTransactionService.commit().get();
839                         } catch (InterruptedException e) {
840                             LOG.error("Couldnt commit change to openroadm topology.", e);
841                             Thread.currentThread().interrupt();
842                         } catch (ExecutionException e) {
843                             LOG.error("Couldnt commit change to openroadm topology.", e);
844                         }
845                     }
846                 }
847             }
848         }
849     }
850
851     private void updateOpenRoadmNetworkTopologyLinks(List<Link> linkList, List<Node> nodesList) {
852         for (Link link : linkList) {
853             String srcTp = link.getSource().getSourceTp().toString();
854             String dstTp = link.getDestination().getDestTp().toString();
855             String srcNode = link.getSource().getSourceNode().getValue();
856             String dstNode = link.getDestination().getDestNode().getValue();
857             State linkState = link.augmentation(org.opendaylight.yang.gen.v1.http
858                 .org.openroadm.common.network.rev200529.Link1.class).getOperationalState();
859             String srcKey = srcNode + "-" + srcTp;
860             String dstKey = dstNode + "-" + dstTp;
861             /* 1. Check the current state of the source and dest tps of the link. If these tps exist on the links Map
862             and the states are different, then we need to update the link state accordingly.
863             There are several cases depending on the current link state:
864                 - TPs were both inService and one of them (or both) is (are) now outOfService --> link to outOfService
865                 - TPs were both outOfService and both of them are now inService --> link to inService
866             However, if only one TP exists on the Link map, we will need to check the state of the other end in order to
867             make a decision: i.e. we cannot assume that if a TP has changed from outOfService to inService the link will
868             become inService, as this can only happen if both TPs are inService, therefore we need to check the other
869             end. */
870             switch (linkState) {
871                 case InService:
872                     if (this.linksChanged.containsKey(srcKey) && this.linksChanged.containsKey(dstKey)) {
873                         // Both TPs of the link have been updated. If one of them is outOfService --> link outOfService
874                         if (State.OutOfService.equals(this.linksChanged.get(srcKey)) || State.OutOfService.equals(this
875                                 .linksChanged.get(dstKey))) {
876                             updateLinkStates(link, State.OutOfService, AdminStates.OutOfService);
877                         }
878                     } else if (this.linksChanged.containsKey(srcKey) && State.OutOfService.equals(this.linksChanged
879                             .get(srcKey))) {
880                         // Source TP has been changed to outOfService --> link outOfService
881                         updateLinkStates(link, State.OutOfService, AdminStates.OutOfService);
882                     } else if (this.linksChanged.containsKey(dstKey) && State.OutOfService.equals(this.linksChanged
883                             .get(dstKey))) {
884                         // Destination TP has been changed to outOfService --> link outOfService
885                         updateLinkStates(link, State.OutOfService, AdminStates.OutOfService);
886                     }
887                     break;
888                 case OutOfService:
889                     if (this.linksChanged.containsKey(srcKey) && this.linksChanged.containsKey(dstKey)) {
890                         // Both TPs of the link have been updated. If both of them are inService --> link inService
891                         if (State.InService.equals(this.linksChanged.get(srcKey)) || State.InService.equals(this
892                                 .linksChanged.get(dstKey))) {
893                             updateLinkStates(link, State.InService, AdminStates.InService);
894                         }
895                     } else if (this.linksChanged.containsKey(srcKey) && State.InService.equals(this.linksChanged
896                             .get(srcKey))) {
897                         // Source TP has been changed to inService --> check the second TP and update link to inService
898                         // only if both TPs are inService
899                         if (tpInService(dstNode, dstTp, nodesList)) {
900                             updateLinkStates(link, State.InService, AdminStates.InService);
901                         }
902                     } else if (this.linksChanged.containsKey(dstKey) && State.InService.equals(this.linksChanged
903                             .get(dstKey))) {
904                         // Destination TP has been changed to to inService --> check the second TP and update link to
905                         // inService only if both TPs are inService
906                         if (tpInService(srcNode, srcTp, nodesList)) {
907                             updateLinkStates(link, State.InService, AdminStates.InService);
908                         }
909                     }
910                     break;
911                 case Degraded:
912                     LOG.warn("Link state degraded not handled");
913                     break;
914                 default:
915                     LOG.warn("Unrecognized state!");
916             }
917         }
918     }
919
920     private boolean tpInService(String nodeId, String tpId, List<Node> nodesList) {
921         // Check the node with dstNode id and check the state of the TP with id dstTP id
922         for (Node node : nodesList) {
923             if (Objects.requireNonNull(node.getNodeId()).getValue().equals(nodeId)) {
924                 List<TerminationPoint> tpList = new ArrayList<>(Objects.requireNonNull(Objects.requireNonNull(node
925                     .augmentation(Node1.class)).getTerminationPoint()).values());
926                 for (TerminationPoint tp : tpList) {
927                     if (Objects.requireNonNull(tp.getTpId()).getValue().equals(tpId)) {
928                         if (State.InService.equals(tp.augmentation(org.opendaylight.yang.gen.v1.http
929                                 .org.openroadm.common.network.rev200529.TerminationPoint1.class)
930                                 .getOperationalState())) {
931                             // The second TP is also inService
932                             return true;
933                         }
934                         break;
935                     }
936                 }
937                 break;
938             }
939         }
940         return false;
941     }
942
943     private void updateLinkStates(Link link, State state, AdminStates adminStates) {
944         // TODO: add change to list of changes
945         // Update topology change list
946         this.topologyChanges.put(new OrdTopologyChangesKey(link.getLinkId().getValue()),
947                 new OrdTopologyChangesBuilder().setId(link.getLinkId().getValue()).setState(state).build());
948         org.opendaylight.yang.gen.v1.http.org.openroadm.common.network.rev200529.Link1 link1 = new Link1Builder()
949             .setOperationalState(state).setAdministrativeState(adminStates).build();
950         Link updLink = new LinkBuilder().withKey(link.key()).addAugmentation(link1).build();
951         InstanceIdentifier.InstanceIdentifierBuilder<Link> linkIID = InstanceIdentifier.builder(Networks.class)
952             .child(Network.class, new NetworkKey(new NetworkId(NetworkUtils.OVERLAY_NETWORK_ID)))
953             .augmentation(Network1.class).child(Link.class, link.key());
954         networkTransactionService.merge(LogicalDatastoreType.CONFIGURATION, linkIID.build(), updLink);
955         try {
956             networkTransactionService.commit().get();
957         } catch (InterruptedException e) {
958             LOG.error("Couldnt commit changed to openroadm topology. Error={}", e.getMessage());
959             Thread.currentThread().interrupt();
960         } catch (ExecutionException e) {
961             LOG.error("Couldnt commit changed to openroadm topology. Error={}", e.getMessage());
962         }
963     }
964
965     @SuppressFBWarnings(
966             value = "UPM_UNCALLED_PRIVATE_METHOD",
967             justification = "false positive, this method is used by public updateOpenRoadmNetworkTopology")
968     private void sendNotification(TopologyNotificationTypes notificationType,
969                                   Map<OrdTopologyChangesKey, OrdTopologyChanges> topologyChangesMap) {
970         if (topologyChangesMap.isEmpty()) {
971             LOG.warn("Empty Topology Change map. No updates in topology");
972             return;
973         }
974         TopologyUpdateResultBuilder topologyUpdateResultBuilder = new TopologyUpdateResultBuilder()
975                 .setNotificationType(notificationType).setOrdTopologyChanges(topologyChangesMap);
976         this.notification = topologyUpdateResultBuilder.build();
977         try {
978             notificationPublishService.putNotification(this.notification);
979         } catch (InterruptedException e) {
980             LOG.error("Notification offer rejected. Error={}", e.getMessage());
981         }
982     }
983 }