cc534245c1ffd207d3b1981b204572bddbb5ab72
[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.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.binding.api.NotificationPublishService;
23 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
24 import org.opendaylight.transportpce.common.InstanceIdentifiers;
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.transportpce.networkmodel.util.TopologyUtils;
36 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.networkmodel.rev201116.TopologyUpdateResult;
37 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.networkmodel.rev201116.TopologyUpdateResultBuilder;
38 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.networkmodel.rev201116.topology.update.result.TopologyChanges;
39 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.networkmodel.rev201116.topology.update.result.TopologyChangesBuilder;
40 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.networkmodel.rev201116.topology.update.result.TopologyChangesKey;
41 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.portmapping.rev210426.OpenroadmNodeVersion;
42 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.portmapping.rev210426.mapping.Mapping;
43 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.portmapping.rev210426.network.nodes.NodeInfo;
44 import org.opendaylight.yang.gen.v1.http.org.openroadm.device.types.rev191129.NodeTypes;
45 import org.opendaylight.yang.gen.v1.http.org.openroadm.otn.network.topology.rev200529.Link1;
46 import org.opendaylight.yang.gen.v1.http.org.openroadm.otn.network.topology.rev200529.TerminationPoint1;
47 import org.opendaylight.yang.gen.v1.http.transportpce.topology.rev210511.OtnLinkType;
48 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226.NetworkId;
49 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226.Networks;
50 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226.NodeId;
51 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226.networks.Network;
52 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226.networks.NetworkKey;
53 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226.networks.network.Node;
54 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226.networks.network.NodeKey;
55 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev180226.LinkId;
56 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev180226.Network1;
57 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev180226.Node1;
58 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev180226.TpId;
59 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev180226.networks.network.Link;
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.TerminationPointKey;
63 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev180226.networks.network.node.termination.point.SupportingTerminationPoint;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNodeConnectionStatus;
65 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
66 import org.opendaylight.yangtools.yang.common.Uint32;
67 import org.slf4j.Logger;
68 import org.slf4j.LoggerFactory;
69
70 public class NetworkModelServiceImpl implements NetworkModelService {
71
72     private static final Logger LOG = LoggerFactory.getLogger(NetworkModelServiceImpl.class);
73
74     private NetworkTransactionService networkTransactionService;
75     private final R2RLinkDiscovery linkDiscovery;
76     private final PortMapping portMapping;
77     private Map<String, TopologyShard> topologyShardMountedDevice;
78     private Map<String, TopologyShard> otnTopologyShardMountedDevice;
79     // Variables for creating and sending topology update notification
80     private final NotificationPublishService notificationPublishService;
81     private Map<TopologyChangesKey, TopologyChanges> topologyChanges;
82     private TopologyUpdateResult notification = null;
83
84     public NetworkModelServiceImpl(final NetworkTransactionService networkTransactionService,
85             final R2RLinkDiscovery linkDiscovery, PortMapping portMapping,
86             final NotificationPublishService notificationPublishService) {
87
88         this.networkTransactionService = networkTransactionService;
89         this.linkDiscovery = linkDiscovery;
90         this.portMapping = portMapping;
91         this.topologyShardMountedDevice = new HashMap<String, TopologyShard>();
92         this.otnTopologyShardMountedDevice = new HashMap<String, TopologyShard>();
93         this.notificationPublishService = notificationPublishService;
94         this.topologyChanges = new HashMap<TopologyChangesKey, TopologyChanges>();
95     }
96
97     public void init() {
98         LOG.info("init ...");
99     }
100
101     public void close() {
102     }
103
104     @Override
105     public void createOpenRoadmNode(String nodeId, String openRoadmVersion) {
106         try {
107             LOG.info("createOpenROADMNode: {} ", nodeId);
108
109             if (!portMapping.createMappingData(nodeId, openRoadmVersion)) {
110                 LOG.warn("Could not generate port mapping for {} skipping network model creation", nodeId);
111                 return;
112             }
113             NodeInfo nodeInfo = portMapping.getNode(nodeId).getNodeInfo();
114             // node creation in clli-network
115             Node clliNode = ClliNetwork.createNode(nodeId, nodeInfo);
116             InstanceIdentifier<Node> iiClliNode = InstanceIdentifier.builder(Networks.class)
117                 .child(Network.class, new NetworkKey(new NetworkId(NetworkUtils.CLLI_NETWORK_ID)))
118                 .child(Node.class, clliNode.key())
119                 .build();
120             LOG.info("creating node in {}", NetworkUtils.CLLI_NETWORK_ID);
121             networkTransactionService.merge(LogicalDatastoreType.CONFIGURATION, iiClliNode, clliNode);
122
123             // node creation in openroadm-network
124             Node openroadmNetworkNode = OpenRoadmNetwork.createNode(nodeId, nodeInfo);
125             InstanceIdentifier<Node> iiopenroadmNetworkNode = InstanceIdentifier.builder(Networks.class)
126                 .child(Network.class, new NetworkKey(new NetworkId(NetworkUtils.UNDERLAY_NETWORK_ID)))
127                 .child(Node.class, openroadmNetworkNode.key())
128                 .build();
129             LOG.info("creating node in {}", NetworkUtils.UNDERLAY_NETWORK_ID);
130             networkTransactionService.merge(LogicalDatastoreType.CONFIGURATION, iiopenroadmNetworkNode,
131                 openroadmNetworkNode);
132
133             // nodes/links creation in openroadm-topology
134             TopologyShard topologyShard = OpenRoadmTopology.createTopologyShard(portMapping.getNode(nodeId));
135             if (topologyShard != null) {
136                 this.topologyShardMountedDevice.put(nodeId, topologyShard);
137                 for (Node openRoadmTopologyNode : topologyShard.getNodes()) {
138                     LOG.info("creating node {} in {}", openRoadmTopologyNode.getNodeId().getValue(),
139                         NetworkUtils.OVERLAY_NETWORK_ID);
140                     InstanceIdentifier<Node> iiOpenRoadmTopologyNode = InstanceIdentifier.builder(Networks.class)
141                         .child(Network.class, new NetworkKey(new NetworkId(NetworkUtils.OVERLAY_NETWORK_ID)))
142                         .child(Node.class, openRoadmTopologyNode.key())
143                         .build();
144                     networkTransactionService.merge(LogicalDatastoreType.CONFIGURATION, iiOpenRoadmTopologyNode,
145                         openRoadmTopologyNode);
146                 }
147                 for (Link openRoadmTopologyLink : topologyShard.getLinks()) {
148                     LOG.info("creating link {} in {}", openRoadmTopologyLink.getLinkId().getValue(),
149                         NetworkUtils.OVERLAY_NETWORK_ID);
150                     InstanceIdentifier<Link> iiOpenRoadmTopologyLink = InstanceIdentifier.builder(Networks.class)
151                         .child(Network.class, new NetworkKey(new NetworkId(NetworkUtils.OVERLAY_NETWORK_ID)))
152                         .augmentation(Network1.class)
153                         .child(Link.class, openRoadmTopologyLink.key())
154                         .build();
155                     networkTransactionService.merge(LogicalDatastoreType.CONFIGURATION, iiOpenRoadmTopologyLink,
156                         openRoadmTopologyLink);
157                 }
158             } else {
159                 LOG.error("Unable to create openroadm-topology shard for node {}!", nodeId);
160             }
161             // nodes/links creation in otn-topology
162             if (nodeInfo.getNodeType().getIntValue() == 2 && (nodeInfo.getOpenroadmVersion().getIntValue() != 1)) {
163                 createOpenRoadmOtnNode(nodeId);
164             }
165             networkTransactionService.commit().get();
166             // neighbour links through LLDP
167             if (nodeInfo.getNodeType().getIntValue() == 1) {
168                 this.linkDiscovery.readLLDP(new NodeId(nodeId), openRoadmVersion);
169             }
170             LOG.info("all nodes and links created");
171         } catch (InterruptedException | ExecutionException e) {
172             LOG.error("ERROR: ", e);
173         }
174     }
175
176     @Override
177     public void setOpenRoadmNodeStatus(String nodeId, NetconfNodeConnectionStatus.ConnectionStatus connectionStatus) {
178         LOG.info("setOpenROADMNodeStatus: {} {}", nodeId, connectionStatus.name());
179         /*
180           TODO: set connection status of the device in model,
181           TODO: so we don't need to keep it in memory (Set<String> currentMountedDevice)
182           TODO: unfortunately there is no connection status OpenROADM in network models
183           TODO: waiting for new model version
184          */
185     }
186
187     /*
188      @see org.opendaylight.transportpce.networkmodel.service.NetworkModelService# deleteOpenROADMnode(java.lang.String)
189      */
190
191     @Override
192     public void deleteOpenRoadmnode(String nodeId) {
193         try {
194             NodeKey nodeIdKey = new NodeKey(new NodeId(nodeId));
195
196             LOG.info("deleting node in {}", NetworkUtils.UNDERLAY_NETWORK_ID);
197             InstanceIdentifier<Node> iiopenroadmNetworkNode = InstanceIdentifier.builder(Networks.class)
198                 .child(Network.class, new NetworkKey(new NetworkId(NetworkUtils.UNDERLAY_NETWORK_ID)))
199                 .child(Node.class, nodeIdKey)
200                 .build();
201             this.networkTransactionService.delete(LogicalDatastoreType.CONFIGURATION, iiopenroadmNetworkNode);
202
203             TopologyShard topologyShard = this.topologyShardMountedDevice.get(nodeId);
204             if (topologyShard != null) {
205                 for (Node openRoadmTopologyNode : topologyShard.getNodes()) {
206                     LOG.info("deleting node {} in {}", openRoadmTopologyNode.getNodeId().getValue(),
207                         NetworkUtils.OVERLAY_NETWORK_ID);
208                     InstanceIdentifier<Node> iiOpenRoadmTopologyNode = InstanceIdentifier.builder(Networks.class)
209                         .child(Network.class, new NetworkKey(new NetworkId(NetworkUtils.OVERLAY_NETWORK_ID)))
210                         .child(Node.class, openRoadmTopologyNode.key())
211                         .build();
212                     this.networkTransactionService.delete(LogicalDatastoreType.CONFIGURATION, iiOpenRoadmTopologyNode);
213                 }
214                 for (Link openRoadmTopologyLink : topologyShard.getLinks()) {
215                     LOG.info("deleting link {} in {}", openRoadmTopologyLink.getLinkId().getValue(),
216                         NetworkUtils.OVERLAY_NETWORK_ID);
217                     InstanceIdentifier<Link> iiOpenRoadmTopologyLink = InstanceIdentifier.builder(Networks.class)
218                         .child(Network.class, new NetworkKey(new NetworkId(NetworkUtils.OVERLAY_NETWORK_ID)))
219                         .augmentation(Network1.class)
220                         .child(Link.class, openRoadmTopologyLink.key())
221                         .build();
222                     this.networkTransactionService.delete(LogicalDatastoreType.CONFIGURATION, iiOpenRoadmTopologyLink);
223                 }
224             } else {
225                 LOG.warn("TopologyShard for node '{}' is not present", nodeId);
226             }
227             @Nullable
228             OpenroadmNodeVersion deviceVersion = this.portMapping.getNode(nodeId).getNodeInfo().getOpenroadmVersion();
229             @Nullable
230             NodeTypes nodeType = this.portMapping.getNode(nodeId).getNodeInfo().getNodeType();
231             if (nodeType.getIntValue() == 2 && deviceVersion.getIntValue() != 1) {
232                 TopologyShard otnTopologyShard = this.otnTopologyShardMountedDevice.get(nodeId);
233                 if (otnTopologyShard != null) {
234                     LOG.info("suppression de otnTopologyShard = {}", otnTopologyShard.toString());
235                     for (Node otnTopologyNode : otnTopologyShard.getNodes()) {
236                         LOG.info("deleting node {} in {}", otnTopologyNode.getNodeId().getValue(),
237                             NetworkUtils.OTN_NETWORK_ID);
238                         InstanceIdentifier<Node> iiotnTopologyNode = InstanceIdentifier.builder(Networks.class)
239                             .child(Network.class, new NetworkKey(new NetworkId(NetworkUtils.OTN_NETWORK_ID)))
240                             .child(Node.class, otnTopologyNode.key())
241                             .build();
242                         this.networkTransactionService.delete(LogicalDatastoreType.CONFIGURATION, iiotnTopologyNode);
243                     }
244                     for (Link otnTopologyLink : otnTopologyShard.getLinks()) {
245                         LOG.info("deleting link {} in {}", otnTopologyLink.getLinkId().getValue(),
246                             NetworkUtils.OTN_NETWORK_ID);
247                         InstanceIdentifier<Link> iiotnTopologyLink = InstanceIdentifier.builder(Networks.class)
248                             .child(Network.class, new NetworkKey(new NetworkId(NetworkUtils.OTN_NETWORK_ID)))
249                             .augmentation(Network1.class)
250                             .child(Link.class, otnTopologyLink.key())
251                             .build();
252                         this.networkTransactionService.delete(LogicalDatastoreType.CONFIGURATION, iiotnTopologyLink);
253                     }
254                 }
255             }
256
257             LOG.info("deleteOpenROADMnode: {} version {}", nodeId, deviceVersion.getName());
258             this.portMapping.deleteMappingData(nodeId);
259
260             this.networkTransactionService.commit().get(1, TimeUnit.SECONDS);
261             LOG.info("all nodes and links deleted ! ");
262         } catch (InterruptedException | ExecutionException | TimeoutException e) {
263             LOG.error("Error when trying to delete node : {}", nodeId, e);
264         }
265     }
266
267     @Override
268     public void updateOpenRoadmTopologies(String nodeId, Mapping mapping) {
269         LOG.info("update OpenRoadm topologies after change update from: {} ", nodeId);
270         this.topologyChanges.clear();
271         Network openroadmTopology = null;
272         Network otnTopology = null;
273         Map<LinkKey, Link> openroadmTopologyLinks = null;
274         Map<LinkKey, Link> otnTopologyLinks = null;
275         try {
276             openroadmTopology = this.networkTransactionService
277                 .read(LogicalDatastoreType.CONFIGURATION, InstanceIdentifiers.OVERLAY_NETWORK_II)
278                 .get().get();
279             if (openroadmTopology.augmentation(Network1.class) != null) {
280                 openroadmTopologyLinks = openroadmTopology.augmentation(Network1.class).getLink();
281             }
282             otnTopology = this.networkTransactionService
283                 .read(LogicalDatastoreType.CONFIGURATION, InstanceIdentifiers.OTN_NETWORK_II)
284                 .get().get();
285             if (otnTopology.augmentation(Network1.class) != null) {
286                 otnTopologyLinks = otnTopology.augmentation(Network1.class).getLink();
287             }
288         } catch (InterruptedException | ExecutionException e) {
289             LOG.error("Error when trying to update node : {}", nodeId, e);
290         }
291         if (openroadmTopology == null || otnTopology == null) {
292             LOG.warn("Error getting topologies from datastore");
293             return;
294         }
295         String abstractNodeid = String.join("-", nodeId, mapping.getLogicalConnectionPoint().split("-")[0]);
296         // nodes/links update in openroadm-topology
297         if (openroadmTopology.getNode() != null) {
298             TopologyShard topologyShard = TopologyUtils.updateTopologyShard(abstractNodeid, mapping,
299                 openroadmTopology.getNode(), openroadmTopologyLinks);
300             if (topologyShard.getLinks() != null) {
301                 for (Link link : topologyShard.getLinks()) {
302                     LOG.info("updating links {} in {}", link.getLinkId().getValue(),
303                         NetworkUtils.OVERLAY_NETWORK_ID);
304                     InstanceIdentifier<Link> iiTopologyLink = InstanceIdentifier.builder(Networks.class)
305                         .child(Network.class, new NetworkKey(new NetworkId(NetworkUtils.OVERLAY_NETWORK_ID)))
306                         .augmentation(Network1.class)
307                         .child(Link.class, link.key())
308                         .build();
309                     networkTransactionService.merge(LogicalDatastoreType.CONFIGURATION, iiTopologyLink, link);
310                 }
311             }
312             if (topologyShard.getTps() != null) {
313                 for (TerminationPoint tp : topologyShard.getTps()) {
314                     LOG.info("updating TP {} in openroadm-topology", tp.getTpId().getValue());
315                     InstanceIdentifier<TerminationPoint> iiTopologyTp = InstanceIdentifier.builder(Networks.class)
316                         .child(Network.class, new NetworkKey(new NetworkId(NetworkUtils.OVERLAY_NETWORK_ID)))
317                         .child(Node.class, new NodeKey(new NodeId(abstractNodeid)))
318                         .augmentation(Node1.class)
319                         .child(TerminationPoint.class, new TerminationPointKey(tp.getTpId()))
320                         .build();
321                     networkTransactionService.merge(LogicalDatastoreType.CONFIGURATION, iiTopologyTp, tp);
322                     TopologyChanges tc = new TopologyChangesBuilder()
323                         .withKey(new TopologyChangesKey(abstractNodeid, tp.getTpId().getValue()))
324                         .setNodeId(abstractNodeid)
325                         .setTpId(tp.getTpId().getValue())
326                         .setState(tp.augmentation(
327                             org.opendaylight.yang.gen.v1.http.org.openroadm.common.network.rev200529.TerminationPoint1
328                                 .class).getOperationalState())
329                         .build();
330                     if (!this.topologyChanges.containsKey(tc.key())) {
331                         this.topologyChanges.put(tc.key(), tc);
332                     }
333                 }
334             }
335         }
336         // nodes/links update in otn-topology
337         if (otnTopology.getNode() != null
338             && otnTopology.getNode().containsKey(new NodeKey(new NodeId(abstractNodeid)))) {
339             TopologyShard otnShard = TopologyUtils.updateTopologyShard(abstractNodeid, mapping,
340                 otnTopology.getNode(), otnTopologyLinks);
341             if (otnShard.getLinks() != null) {
342                 for (Link link : otnShard.getLinks()) {
343                     LOG.info("updating links {} in {}", link.getLinkId().getValue(),
344                         NetworkUtils.OVERLAY_NETWORK_ID);
345                     InstanceIdentifier<Link> iiTopologyLink = InstanceIdentifier.builder(Networks.class)
346                         .child(Network.class, new NetworkKey(new NetworkId(NetworkUtils.OTN_NETWORK_ID)))
347                         .augmentation(Network1.class)
348                         .child(Link.class, link.key())
349                         .build();
350                     networkTransactionService.merge(LogicalDatastoreType.CONFIGURATION, iiTopologyLink, link);
351                 }
352             }
353             if (otnShard.getTps() != null) {
354                 for (TerminationPoint tp : otnShard.getTps()) {
355                     LOG.info("updating TP {} in otn-topology", tp.getTpId().getValue());
356                     InstanceIdentifier<TerminationPoint> iiTopologyTp = InstanceIdentifier.builder(Networks.class)
357                         .child(Network.class, new NetworkKey(new NetworkId(NetworkUtils.OTN_NETWORK_ID)))
358                         .child(Node.class, new NodeKey(new NodeId(abstractNodeid)))
359                         .augmentation(Node1.class)
360                         .child(TerminationPoint.class, new TerminationPointKey(tp.getTpId()))
361                         .build();
362                     networkTransactionService.merge(LogicalDatastoreType.CONFIGURATION, iiTopologyTp, tp);
363                     TopologyChanges tc = new TopologyChangesBuilder()
364                         .withKey(new TopologyChangesKey(abstractNodeid, tp.getTpId().getValue()))
365                         .setNodeId(abstractNodeid)
366                         .setTpId(tp.getTpId().getValue())
367                         .setState(tp.augmentation(
368                             org.opendaylight.yang.gen.v1.http.org.openroadm.common.network.rev200529.TerminationPoint1
369                                 .class).getOperationalState())
370                         .build();
371                     if (!this.topologyChanges.containsKey(tc.key())) {
372                         this.topologyChanges.put(tc.key(), tc);
373                     }
374                 }
375             }
376         }
377         // commit datastore updates
378         try {
379             networkTransactionService.commit().get();
380             sendNotification();
381         } catch (InterruptedException | ExecutionException e) {
382             LOG.error("Error updating openroadm-topology", e);
383         }
384     }
385
386     @Override
387     public void createOtnLinks(String nodeA, String tpA, String nodeZ, String tpZ, OtnLinkType linkType) {
388         TopologyShard otnTopologyShard;
389         switch (linkType) {
390             case OTU4:
391                 otnTopologyShard = OpenRoadmOtnTopology.createOtnLinks(nodeA, tpA, nodeZ, tpZ, linkType);
392                 break;
393             case ODTU4:
394                 String nodeTopoA = new StringBuilder(nodeA).append("-").append(tpA.split("-")[0]).toString();
395                 String nodeTopoZ = new StringBuilder(nodeZ).append("-").append(tpZ.split("-")[0]).toString();
396                 List<LinkId> linkIdList = new ArrayList<>();
397                 linkIdList.add(LinkIdUtil.buildOtnLinkId(nodeTopoA, tpA, nodeTopoZ, tpZ, "OTU4"));
398                 linkIdList.add(LinkIdUtil.buildOtnLinkId(nodeTopoZ, tpZ, nodeTopoA, tpA, "OTU4"));
399                 List<Link> supportedOtu4links = getOtnLinks(linkIdList);
400                 List<TerminationPoint> tps = getOtnNodeTps(nodeTopoA, tpA, nodeTopoZ, tpZ);
401
402                 otnTopologyShard = OpenRoadmOtnTopology.createOtnLinks(supportedOtu4links, tps);
403                 break;
404             default:
405                 LOG.error("unknown otn link type {}", linkType);
406                 otnTopologyShard = new TopologyShard(null, null);
407         }
408         if (otnTopologyShard.getLinks() != null) {
409             for (Link otnTopologyLink : otnTopologyShard.getLinks()) {
410                 LOG.info("creating and updating otn links {} in {}", otnTopologyLink.getLinkId().getValue(),
411                     NetworkUtils.OVERLAY_NETWORK_ID);
412                 InstanceIdentifier<Link> iiOtnTopologyLink = InstanceIdentifier.builder(Networks.class)
413                     .child(Network.class, new NetworkKey(new NetworkId(NetworkUtils.OTN_NETWORK_ID)))
414                     .augmentation(Network1.class)
415                     .child(Link.class, otnTopologyLink.key())
416                     .build();
417                 networkTransactionService.merge(LogicalDatastoreType.CONFIGURATION, iiOtnTopologyLink, otnTopologyLink);
418             }
419         }
420         if (otnTopologyShard.getTps() != null) {
421             for (TerminationPoint otnTopologyTp : otnTopologyShard.getTps()) {
422                 LOG.info("updating otn nodes TP {} in otn-topology", otnTopologyTp.getTpId().getValue());
423                 List<SupportingTerminationPoint> supportingTerminationPoint =
424                     new ArrayList<>(otnTopologyTp.nonnullSupportingTerminationPoint().values());
425                 InstanceIdentifier<TerminationPoint> iiOtnTopologyTp = InstanceIdentifier.builder(Networks.class)
426                     .child(Network.class, new NetworkKey(new NetworkId(NetworkUtils.OTN_NETWORK_ID)))
427                     .child(Node.class, new NodeKey(supportingTerminationPoint.get(0).getNodeRef()))
428                     .augmentation(Node1.class)
429                     .child(TerminationPoint.class, new TerminationPointKey(otnTopologyTp.getTpId()))
430                     .build();
431                 networkTransactionService.merge(LogicalDatastoreType.CONFIGURATION, iiOtnTopologyTp, otnTopologyTp);
432             }
433         }
434         try {
435             networkTransactionService.commit().get();
436         } catch (InterruptedException | ExecutionException e) {
437             LOG.error("Error adding OTN links in otn-topology", e);
438         }
439         LOG.info("OTN links created");
440     }
441
442     @Override
443     public void deleteOtnLinks(String nodeA, String tpA, String nodeZ, String tpZ, OtnLinkType linkType) {
444         TopologyShard otnTopologyShard;
445         String nodeTopoA = new StringBuilder(nodeA).append("-").append(tpA.split("-")[0]).toString();
446         String nodeTopoZ = new StringBuilder(nodeZ).append("-").append(tpZ.split("-")[0]).toString();
447         List<Link> otu4Links;
448         List<LinkId> linkIdList = new ArrayList<>();
449         switch (linkType) {
450             case OTU4:
451                 linkIdList.add(LinkIdUtil.buildOtnLinkId(nodeTopoA, tpA, nodeTopoZ, tpZ, "OTU4"));
452                 linkIdList.add(LinkIdUtil.buildOtnLinkId(nodeTopoZ, tpZ, nodeTopoA, tpA, "OTU4"));
453                 otu4Links = getOtnLinks(linkIdList);
454                 if (checkLinks(otu4Links)) {
455                     deleteLinks(otu4Links);
456                 } else {
457                     LOG.error("Error deleting OTU4 links");
458                 }
459                 otnTopologyShard = new TopologyShard(null, null);
460                 break;
461             case ODTU4:
462                 linkIdList.add(LinkIdUtil.buildOtnLinkId(nodeTopoA, tpA, nodeTopoZ, tpZ, "ODU4"));
463                 linkIdList.add(LinkIdUtil.buildOtnLinkId(nodeTopoZ, tpZ, nodeTopoA, tpA, "ODU4"));
464                 List<Link> odu4Links = getOtnLinks(linkIdList);
465                 List<TerminationPoint> tps = getOtnNodeTps(nodeTopoA, tpA, nodeTopoZ, tpZ);
466                 if (checkLinks(odu4Links) && checkTerminationPoints(tps)) {
467                     deleteLinks(odu4Links);
468                     linkIdList.clear();
469                     linkIdList.add(LinkIdUtil.buildOtnLinkId(nodeTopoA, tpA, nodeTopoZ, tpZ, "OTU4"));
470                     linkIdList.add(LinkIdUtil.buildOtnLinkId(nodeTopoZ, tpZ, nodeTopoA, tpA, "OTU4"));
471                     otu4Links = getOtnLinks(linkIdList);
472                     otnTopologyShard = OpenRoadmOtnTopology.deleteOtnLinks(otu4Links, tps);
473                 } else {
474                     LOG.error("Error deleting ODU4 links");
475                     otnTopologyShard = new TopologyShard(null, null);
476                 }
477                 break;
478             default:
479                 LOG.error("unknown otn link type {}", linkType);
480                 otnTopologyShard = new TopologyShard(null, null);
481         }
482         if (otnTopologyShard.getLinks() != null) {
483             for (Link otnTopologyLink : otnTopologyShard.getLinks()) {
484                 LOG.info("deleting and updating otn links {} in {}", otnTopologyLink.getLinkId().getValue(),
485                     NetworkUtils.OVERLAY_NETWORK_ID);
486                 InstanceIdentifier<Link> iiOtnTopologyLink = InstanceIdentifier.builder(Networks.class)
487                     .child(Network.class, new NetworkKey(new NetworkId(NetworkUtils.OTN_NETWORK_ID)))
488                     .augmentation(Network1.class)
489                     .child(Link.class, otnTopologyLink.key())
490                     .build();
491                 networkTransactionService.merge(LogicalDatastoreType.CONFIGURATION, iiOtnTopologyLink, otnTopologyLink);
492             }
493         }
494         if (otnTopologyShard.getTps() != null) {
495             for (TerminationPoint otnTopologyTp : otnTopologyShard.getTps()) {
496                 LOG.info("updating otn nodes TP {} in otn-topology", otnTopologyTp.getTpId().getValue());
497                 List<SupportingTerminationPoint> supportingTerminationPoint =
498                     new ArrayList<>(otnTopologyTp.nonnullSupportingTerminationPoint().values());
499                 InstanceIdentifier<TerminationPoint> iiOtnTopologyTp = InstanceIdentifier.builder(Networks.class)
500                     .child(Network.class, new NetworkKey(new NetworkId(NetworkUtils.OTN_NETWORK_ID)))
501                     .child(Node.class, new NodeKey(supportingTerminationPoint.get(0).getNodeRef()))
502                     .augmentation(Node1.class)
503                     .child(TerminationPoint.class, new TerminationPointKey(otnTopologyTp.getTpId()))
504                     .build();
505                 networkTransactionService.put(LogicalDatastoreType.CONFIGURATION, iiOtnTopologyTp, otnTopologyTp);
506             }
507         }
508         try {
509             networkTransactionService.commit().get();
510         } catch (InterruptedException | ExecutionException e) {
511             LOG.error("Error deleting OTN links in otn-topology", e);
512         }
513         LOG.info("OTN links deletion terminated");
514     }
515
516     @Override
517     public void updateOtnLinks(List<String> nodeTps, Uint32 serviceRate, Short tribPortNb, Short tribSoltNb,
518             boolean isDeletion) {
519         List<Link> supportedOdu4Links = getSupportingOdu4Links(nodeTps);
520         List<TerminationPoint> tps = getOtnNodeTps(nodeTps);
521         TopologyShard otnTopologyShard;
522         otnTopologyShard = OpenRoadmOtnTopology.updateOtnLinks(supportedOdu4Links, tps, serviceRate, tribPortNb,
523             tribSoltNb, isDeletion);
524         if (otnTopologyShard.getLinks() != null) {
525             for (Link otnTopologyLink : otnTopologyShard.getLinks()) {
526                 LOG.info("creating and updating otn links {} in {}", otnTopologyLink.getLinkId().getValue(),
527                     NetworkUtils.OVERLAY_NETWORK_ID);
528                 InstanceIdentifier<Link> iiOtnTopologyLink = InstanceIdentifier.builder(Networks.class)
529                     .child(Network.class, new NetworkKey(new NetworkId(NetworkUtils.OTN_NETWORK_ID)))
530                     .augmentation(Network1.class)
531                     .child(Link.class, new LinkKey(new LinkId(otnTopologyLink.getLinkId().getValue())))
532                     .build();
533                 networkTransactionService.merge(LogicalDatastoreType.CONFIGURATION, iiOtnTopologyLink, otnTopologyLink);
534             }
535         }
536         if (otnTopologyShard.getTps() != null) {
537             for (TerminationPoint otnTopologyTp : otnTopologyShard.getTps()) {
538                 LOG.info("updating otn nodes TP {} in otn-topology", otnTopologyTp.getTpId().getValue());
539                 List<SupportingTerminationPoint> supportingTerminationPoint =
540                     new ArrayList<>(otnTopologyTp.nonnullSupportingTerminationPoint().values());
541                 InstanceIdentifier<TerminationPoint> iiOtnTopologyTp = InstanceIdentifier.builder(Networks.class)
542                     .child(Network.class, new NetworkKey(new NetworkId(NetworkUtils.OTN_NETWORK_ID)))
543                     .child(Node.class, new NodeKey(supportingTerminationPoint.get(0).getNodeRef()))
544                     .augmentation(Node1.class)
545                     .child(TerminationPoint.class, new TerminationPointKey(new TpId(otnTopologyTp.getTpId()
546                         .getValue())))
547                     .build();
548                 if (isDeletion) {
549                     networkTransactionService.merge(LogicalDatastoreType.CONFIGURATION, iiOtnTopologyTp, otnTopologyTp);
550                 } else {
551                     networkTransactionService.put(LogicalDatastoreType.CONFIGURATION, iiOtnTopologyTp, otnTopologyTp);
552                 }
553             }
554         }
555         try {
556             networkTransactionService.commit().get();
557         } catch (InterruptedException | ExecutionException e) {
558             LOG.error("Error updating OTN links in otn-topology", e);
559         }
560     }
561
562     private List<Link> getOtnLinks(List<LinkId> linkIds) {
563         List<Link> links = new ArrayList<>();
564         for (LinkId linkId : linkIds) {
565             InstanceIdentifier<Link> iiLink = InstanceIdentifier.builder(Networks.class)
566                 .child(Network.class, new NetworkKey(new NetworkId(NetworkUtils.OTN_NETWORK_ID)))
567                 .augmentation(Network1.class)
568                 .child(Link.class, new LinkKey(linkId))
569                 .build();
570             ListenableFuture<Optional<Link>> linkOptLf = networkTransactionService
571                 .read(LogicalDatastoreType.CONFIGURATION, iiLink);
572             if (linkOptLf.isDone()) {
573                 try {
574                     if (linkOptLf.get().isPresent()) {
575                         links.add(linkOptLf.get().get());
576                     }
577                 } catch (InterruptedException | ExecutionException e) {
578                     LOG.error("Error retreiving OTN links from otn-topology", e);
579                 }
580             } else {
581                 LOG.error("Error retreiving link {} from otn-topology", linkId.getValue());
582             }
583         }
584         return links;
585     }
586
587     private boolean checkLinks(List<Link> links) {
588         if (links.isEmpty()) {
589             return false;
590         }
591         for (Link link : links) {
592             if (link.augmentation(Link1.class) != null
593                     && !link.augmentation(Link1.class).getUsedBandwidth().equals(Uint32.valueOf(0))) {
594                 return false;
595             }
596         }
597         return true;
598     }
599
600     private boolean checkTerminationPoints(List<TerminationPoint> tps) {
601         if (tps.isEmpty()) {
602             return false;
603         }
604         for (TerminationPoint tp : tps) {
605             if (tp.augmentation(TerminationPoint1.class) != null && tp.augmentation(TerminationPoint1.class)
606                     .getXpdrTpPortConnectionAttributes().getTsPool() != null && tp.augmentation(TerminationPoint1.class)
607                     .getXpdrTpPortConnectionAttributes().getTsPool().size() != 80) {
608                 return false;
609             }
610         }
611         return true;
612     }
613
614     private List<TerminationPoint> getOtnNodeTps(String nodeTopoA, String tpA, String nodeTopoZ, String tpZ) {
615         List<TerminationPoint> tps = new ArrayList<>();
616         InstanceIdentifier<TerminationPoint> iiTpA = InstanceIdentifier.builder(Networks.class)
617             .child(Network.class, new NetworkKey(new NetworkId(NetworkUtils.OTN_NETWORK_ID)))
618             .child(Node.class, new NodeKey(new NodeId(nodeTopoA)))
619             .augmentation(Node1.class)
620             .child(TerminationPoint.class, new TerminationPointKey(new TpId(tpA)))
621             .build();
622         Optional<TerminationPoint> tpAOpt = Optional.empty();
623         InstanceIdentifier<TerminationPoint> iiTpZ = InstanceIdentifier.builder(Networks.class)
624             .child(Network.class, new NetworkKey(new NetworkId(NetworkUtils.OTN_NETWORK_ID)))
625             .child(Node.class, new NodeKey(new NodeId(nodeTopoZ)))
626             .augmentation(Node1.class)
627             .child(TerminationPoint.class, new TerminationPointKey(new TpId(tpZ)))
628             .build();
629         Optional<TerminationPoint> tpZOpt = Optional.empty();
630
631         if (networkTransactionService.read(LogicalDatastoreType.CONFIGURATION, iiTpA).isDone()
632                 && networkTransactionService.read(LogicalDatastoreType.CONFIGURATION, iiTpZ).isDone()) {
633             try {
634                 tpAOpt = networkTransactionService.read(LogicalDatastoreType.CONFIGURATION, iiTpA).get();
635                 tpZOpt = networkTransactionService.read(LogicalDatastoreType.CONFIGURATION, iiTpZ).get();
636             } catch (InterruptedException | ExecutionException e) {
637                 LOG.error("Error retreiving tp {} of node {} or tp {} from node {} from otn-topology", tpA, nodeTopoA,
638                     tpZ, nodeTopoZ, e);
639             }
640         } else {
641             LOG.error("error getting node termination points from the datastore");
642         }
643
644         if (tpAOpt.isPresent() && tpZOpt.isPresent()) {
645             tps.add(tpAOpt.get());
646             tps.add(tpZOpt.get());
647         }
648         return tps;
649     }
650
651     private List<TerminationPoint> getOtnNodeTps(List<String> nodeTopoTps) {
652         List<TerminationPoint> tps = new ArrayList<>();
653         for (String str : nodeTopoTps) {
654             String nodeId = str.split("--")[0];
655             String tp = str.split("--")[1];
656             InstanceIdentifier<TerminationPoint> iiTp = InstanceIdentifier.builder(Networks.class)
657                 .child(Network.class, new NetworkKey(new NetworkId(NetworkUtils.OTN_NETWORK_ID)))
658                 .child(Node.class, new NodeKey(new NodeId(nodeId)))
659                 .augmentation(Node1.class)
660                 .child(TerminationPoint.class, new TerminationPointKey(new TpId(tp)))
661                 .build();
662             Optional<TerminationPoint> tpOpt;
663             if (networkTransactionService.read(LogicalDatastoreType.CONFIGURATION, iiTp).isDone()) {
664                 try {
665                     tpOpt = networkTransactionService.read(LogicalDatastoreType.CONFIGURATION, iiTp).get();
666                     if (tpOpt.isPresent()) {
667                         tps.add(tpOpt.get());
668                     }
669                 } catch (InterruptedException | ExecutionException e) {
670                     LOG.error("Error retreiving tp {} of node {} from otn-topology", tp, nodeId, e);
671                 }
672             } else {
673                 LOG.error("error getting node termination points from the datastore");
674             }
675         }
676         if (tps.isEmpty()) {
677             LOG.warn("returning null");
678             return null;
679         } else {
680             LOG.info("returning tps = {}", tps.toString());
681             return tps;
682         }
683     }
684
685     private void deleteLinks(List<Link> links) {
686         for (Link otnTopologyLink : links) {
687             LOG.info("deleting link {} from {}", otnTopologyLink.getLinkId().getValue(),
688                 NetworkUtils.OVERLAY_NETWORK_ID);
689             InstanceIdentifier<Link> iiOtnTopologyLink = InstanceIdentifier.builder(Networks.class)
690                 .child(Network.class, new NetworkKey(new NetworkId(NetworkUtils.OTN_NETWORK_ID)))
691                 .augmentation(Network1.class)
692                 .child(Link.class, otnTopologyLink.key())
693                 .build();
694             networkTransactionService.delete(LogicalDatastoreType.CONFIGURATION, iiOtnTopologyLink);
695         }
696         try {
697             networkTransactionService.commit().get();
698         } catch (InterruptedException | ExecutionException e) {
699             LOG.error("Error deleting OTN links from otn-topology", e);
700         }
701     }
702
703     private List<Link> getSupportingOdu4Links(List<String> nodesTopoTps) {
704         InstanceIdentifier<Network1> iiOtnTopologyLinks = InstanceIdentifier.builder(Networks.class)
705             .child(Network.class, new NetworkKey(new NetworkId(NetworkUtils.OTN_NETWORK_ID)))
706             .augmentation(Network1.class)
707             .build();
708         ListenableFuture<Optional<Network1>> netw1Fl = networkTransactionService
709             .read(LogicalDatastoreType.CONFIGURATION, iiOtnTopologyLinks);
710         Optional<Network1> netw1Opt = Optional.empty();
711         if (netw1Fl.isDone()) {
712             try {
713                 netw1Opt = netw1Fl.get();
714             } catch (InterruptedException | ExecutionException e) {
715                 LOG.error("Error retreiving list of links from otn-topology", e);
716             }
717         }
718         List<Link> odu4links = null;
719         if (netw1Opt.isPresent() && netw1Opt.get().getLink() != null) {
720             odu4links = netw1Opt
721                 .get()
722                 .nonnullLink().values()
723                 .stream().filter(lk -> lk.getLinkId().getValue().startsWith("ODU4"))
724                 .collect(Collectors.toList());
725         }
726         List<Link> links = new ArrayList<>();
727         if (odu4links != null) {
728             for (String str : nodesTopoTps) {
729                 String[] nodeAndTp = str.split("--");
730                 if (nodeAndTp.length >= 2) {
731                     String nodeId = nodeAndTp[0];
732                     String tp = nodeAndTp[1];
733                     Link slink = odu4links.stream().filter(lk -> lk.getSource().getSourceNode().getValue()
734                         .equals(nodeId) && lk.getSource().getSourceTp().toString().equals(tp)).findFirst().get();
735                     if (!links.contains(slink)) {
736                         links.add(slink);
737                     }
738                     Link dlink = odu4links.stream().filter(lk -> lk.getDestination().getDestNode().getValue()
739                         .equals(nodeId) && lk.getDestination().getDestTp().toString().equals(tp)).findFirst().get();
740                     if (!links.contains(dlink)) {
741                         links.add(dlink);
742                     }
743                 }
744             }
745             LOG.debug("odu4links = {}", links.toString());
746             return links;
747         } else {
748             return null;
749         }
750     }
751
752     private void createOpenRoadmOtnNode(String nodeId) {
753         TopologyShard otnTopologyShard = OpenRoadmOtnTopology.createTopologyShard(portMapping.getNode(nodeId));
754         if (otnTopologyShard != null) {
755             this.otnTopologyShardMountedDevice.put(nodeId, otnTopologyShard);
756             for (Node otnTopologyNode : otnTopologyShard.getNodes()) {
757                 LOG.info("creating otn node {} in {}", otnTopologyNode.getNodeId().getValue(),
758                     NetworkUtils.OTN_NETWORK_ID);
759                 InstanceIdentifier<Node> iiOtnTopologyNode = InstanceIdentifier.builder(Networks.class)
760                     .child(Network.class, new NetworkKey(new NetworkId(NetworkUtils.OTN_NETWORK_ID)))
761                     .child(Node.class, otnTopologyNode.key())
762                     .build();
763                 networkTransactionService.merge(LogicalDatastoreType.CONFIGURATION, iiOtnTopologyNode, otnTopologyNode);
764             }
765             for (Link otnTopologyLink : otnTopologyShard.getLinks()) {
766                 LOG.info("creating otn link {} in {}", otnTopologyLink.getLinkId().getValue(),
767                     NetworkUtils.OVERLAY_NETWORK_ID);
768                 InstanceIdentifier<Link> iiOtnTopologyLink = InstanceIdentifier.builder(Networks.class)
769                     .child(Network.class, new NetworkKey(new NetworkId(NetworkUtils.OTN_NETWORK_ID)))
770                     .augmentation(Network1.class)
771                     .child(Link.class, otnTopologyLink.key())
772                     .build();
773                 networkTransactionService.merge(LogicalDatastoreType.CONFIGURATION, iiOtnTopologyLink, otnTopologyLink);
774             }
775         } else {
776             LOG.error("Unable to create OTN topology shard for node {}!", nodeId);
777         }
778     }
779
780     @SuppressFBWarnings(
781             value = "UPM_UNCALLED_PRIVATE_METHOD",
782             justification = "false positive, this method is used by public updateOpenRoadmNetworkTopology")
783     private void sendNotification() {
784         if (topologyChanges.isEmpty()) {
785             LOG.warn("Empty Topology Change List. No updates in topology");
786             return;
787         }
788         this.notification = new TopologyUpdateResultBuilder()
789             .setTopologyChanges(topologyChanges)
790             .build();
791         try {
792             notificationPublishService.putNotification(this.notification);
793         } catch (InterruptedException e) {
794             LOG.error("Notification offer rejected. Error={}", e.getMessage());
795         }
796     }
797 }