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