PCE modification in order to prepare flexgrid
[transportpce.git] / pce / src / main / java / org / opendaylight / transportpce / pce / networkanalyzer / PceCalculation.java
1 /*
2  * Copyright © 2017 AT&T, Inc. 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
9 package org.opendaylight.transportpce.pce.networkanalyzer;
10
11 import java.util.ArrayList;
12 import java.util.HashMap;
13 import java.util.HashSet;
14 import java.util.List;
15 import java.util.Map;
16 import java.util.Optional;
17 import java.util.Set;
18 import java.util.concurrent.ExecutionException;
19 import java.util.stream.Collectors;
20 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
21 import org.opendaylight.transportpce.common.NetworkUtils;
22 import org.opendaylight.transportpce.common.ResponseCodes;
23 import org.opendaylight.transportpce.common.mapping.MappingUtils;
24 import org.opendaylight.transportpce.common.mapping.MappingUtilsImpl;
25 import org.opendaylight.transportpce.common.network.NetworkTransactionService;
26 import org.opendaylight.transportpce.pce.constraints.PceConstraints;
27 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev200128.PathComputationRequestInput;
28 import org.opendaylight.yang.gen.v1.http.org.openroadm.common.network.rev200529.Node1;
29 import org.opendaylight.yang.gen.v1.http.org.openroadm.network.types.rev200529.OpenroadmLinkType;
30 import org.opendaylight.yang.gen.v1.http.org.openroadm.network.types.rev200529.OpenroadmNodeType;
31 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226.NetworkId;
32 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226.Networks;
33 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226.NodeId;
34 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226.networks.Network;
35 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226.networks.NetworkKey;
36 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226.networks.network.Node;
37 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev180226.LinkId;
38 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev180226.Network1;
39 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev180226.networks.network.Link;
40 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
41 //import org.opendaylight.yangtools.yang.common.Decimal64;
42 import org.slf4j.Logger;
43 import org.slf4j.LoggerFactory;
44
45 public class PceCalculation {
46     /* Logging. */
47     private static final Logger LOG = LoggerFactory.getLogger(PceCalculation.class);
48     private NetworkTransactionService networkTransactionService = null;
49
50     ///////////// data parsed from Input/////////////////
51     private PathComputationRequestInput input;
52     private String anodeId = "";
53     private String znodeId = "";
54     private String serviceFormatA = "";
55     private String serviceFormatZ = "";
56     private String serviceType = "";
57     private Long serviceRate = 0L;
58
59     private PceConstraints pceHardConstraints;
60
61     ///////////// Intermediate data/////////////////
62     private List<PceLink> addLinks = new ArrayList<>();
63     private List<PceLink> dropLinks = new ArrayList<>();
64     private HashSet<NodeId> azSrgs = new HashSet<>();
65
66     private PceNode aendPceNode = null;
67     private PceNode zendPceNode = null;
68
69     private List<Link> allLinks = null;
70     private List<Node> allNodes = null;
71
72     // this List serves graph calculation
73     private Map<NodeId, PceNode> allPceNodes = new HashMap<>();
74     // this List serves calculation of ZtoA path description
75     // TODO maybe better solution is possible
76     private Map<LinkId, PceLink> allPceLinks = new HashMap<>();
77     private Set<LinkId> linksToExclude = new HashSet<>();
78     private PceResult returnStructure;
79
80     private enum ConstraintTypes {
81         NONE, HARD_EXCLUDE, HARD_INCLUDE, HARD_DIVERSITY, SOFT_EXCLUDE, SOFT_INCLUDE, SOFT_DIVERSITY;
82     }
83
84     private MappingUtils mappingUtils;
85
86     public PceCalculation(PathComputationRequestInput input, NetworkTransactionService networkTransactionService,
87             PceConstraints pceHardConstraints, PceConstraints pceSoftConstraints, PceResult rc) {
88         this.input = input;
89         this.networkTransactionService = networkTransactionService;
90         this.returnStructure = rc;
91
92         this.pceHardConstraints = pceHardConstraints;
93         this.mappingUtils = new MappingUtilsImpl(networkTransactionService.getDataBroker());
94         parseInput();
95     }
96
97     public void retrievePceNetwork() {
98
99         LOG.info("In PceCalculation retrieveNetwork: ");
100
101         if (!readMdSal()) {
102             returnStructure.setRC(ResponseCodes.RESPONSE_FAILED);
103             return;
104         }
105         MapUtils.mapDiversityConstraints(allNodes, allLinks, pceHardConstraints);
106
107         if (!analyzeNw()) {
108             returnStructure.setRC(ResponseCodes.RESPONSE_FAILED);
109             return;
110         }
111         printNodesInfo(allPceNodes);
112
113         returnStructure.setRC(ResponseCodes.RESPONSE_OK);
114         return;
115     }
116
117     private boolean parseInput() {
118         if (input.getServiceAEnd().getServiceFormat() == null || input.getServiceZEnd().getServiceFormat() == null
119             || input.getServiceAEnd().getServiceRate() == null) {
120             LOG.error("Service Format and Service Rate are required for a path calculation");
121             return false;
122         }
123         serviceFormatA = input.getServiceAEnd().getServiceFormat().getName();
124         serviceFormatZ = input.getServiceZEnd().getServiceFormat().getName();
125         serviceRate = input.getServiceAEnd().getServiceRate().toJava();
126
127         LOG.info("parseInput: A and Z :[{}] and [{}]", anodeId, znodeId);
128         if (!(serviceFormatA.equals(serviceFormatZ))) {
129             LOG.info("parseInput: different service format for A and Z not handled, will use service format from Aend");
130         } else if (serviceRate == 100L) {
131             switch (serviceFormatA) {
132                 case "Ethernet":
133                 case "OC":
134                     serviceType = "100GE";
135                     break;
136                 case "OTU":
137                     serviceType = "OTU4";
138                     break;
139                 case "ODU":
140                     serviceType = "ODU4";
141                     break;
142                 default:
143                     LOG.debug("parseInput: unsupported service type: Format {} Rate 100L", serviceFormatA);
144                     break;
145             }
146             //switch(serviceRate) may seem a better option at first glance.
147             //But switching on Long or long is not directly possible in Java.
148             //And casting to int bumps the limit here.
149             //Passing by ENUM or String are possible alternatives.
150             //Maybe HashMap and similar options should also be considered here.
151         } else if ("Ethernet".equals(serviceFormatA)) {
152         //only rate 100L is currently supported except in Ethernet
153             if (serviceRate == 10L) {
154                 serviceType = "10GE";
155             } else if (serviceRate == 1L) {
156                 serviceType = "1GE";
157             } else {
158                 LOG.debug("parseInput: unsupported service type: Format Ethernet Rate {}", serviceRate);
159             }
160         } else {
161             LOG.debug("parseInput: unsupported service type: Format {} Rate {}",
162                 serviceFormatA, serviceRate);
163         }
164         if ("ODU4".equals(serviceType) || "10GE".equals(serviceType)  || "1GE".equals(serviceType)) {
165             anodeId = input.getServiceAEnd().getTxDirection().getPort().getPortDeviceName();
166             znodeId = input.getServiceZEnd().getTxDirection().getPort().getPortDeviceName();
167         } else {
168             anodeId = input.getServiceAEnd().getNodeId();
169             znodeId = input.getServiceZEnd().getNodeId();
170         }
171
172         returnStructure.setRate(input.getServiceAEnd().getServiceRate().toJava());
173         returnStructure.setServiceFormat(input.getServiceAEnd().getServiceFormat());
174         return true;
175     }
176
177     private boolean readMdSal() {
178         InstanceIdentifier<Network> nwInstanceIdentifier = null;
179         Network nw = null;
180         if (("OC".equals(serviceFormatA)) || ("OTU".equals(serviceFormatA)) || (("Ethernet".equals(serviceFormatA))
181             && (serviceRate == 100L))) {
182
183             LOG.info("readMdSal: network {}", NetworkUtils.OVERLAY_NETWORK_ID);
184             nwInstanceIdentifier = InstanceIdentifier.builder(Networks.class)
185                 .child(Network.class, new NetworkKey(new NetworkId(NetworkUtils.OVERLAY_NETWORK_ID))).build();
186         } else if ("ODU".equals(serviceFormatA) || ("Ethernet".equals(serviceFormatA) && serviceRate == 10L)
187             || ("Ethernet".equals(serviceFormatA) && serviceRate == 1L)) {
188             LOG.info("readMdSal: network {}", NetworkUtils.OTN_NETWORK_ID);
189             nwInstanceIdentifier = InstanceIdentifier.builder(Networks.class)
190                 .child(Network.class, new NetworkKey(new NetworkId(NetworkUtils.OTN_NETWORK_ID))).build();
191         } else {
192             LOG.info("readMdSal: service-rate {} / service-format not handled {}", serviceRate, serviceFormatA);
193             return false;
194         }
195
196         try {
197             Optional<Network> nwOptional =
198                 networkTransactionService.read(LogicalDatastoreType.CONFIGURATION, nwInstanceIdentifier).get();
199             if (nwOptional.isPresent()) {
200                 nw = nwOptional.get();
201                 LOG.debug("readMdSal: network nodes: nwOptional.isPresent = true {}", nw);
202             }
203         } catch (InterruptedException | ExecutionException e) {
204             LOG.error("readMdSal: Error reading topology {}", nwInstanceIdentifier);
205             networkTransactionService.close();
206             returnStructure.setRC(ResponseCodes.RESPONSE_FAILED);
207             throw new RuntimeException(
208                 "readMdSal: Error reading from operational store, topology : " + nwInstanceIdentifier + " :" + e);
209         }
210         networkTransactionService.close();
211
212         if (nw == null) {
213             LOG.error("readMdSal: network is null: {}", nwInstanceIdentifier);
214             return false;
215         }
216         allNodes = nw.nonnullNode().values().stream().sorted((n1, n2)
217             -> n1.getNodeId().getValue().compareTo(n2.getNodeId().getValue())).collect(Collectors.toList());
218         Network1 nw1 = nw.augmentation(Network1.class);
219         if (nw1 != null) {
220             allLinks = nw1.nonnullLink().values().stream().sorted((l1, l2)
221                 -> l1.getSource().getSourceTp().toString().compareTo(l2.getSource().getSourceTp().toString()))
222                     .collect(Collectors.toList());
223         } else {
224             LOG.warn("no otn links in otn-topology");
225         }
226         if (allNodes == null || allNodes.isEmpty()) {
227             LOG.error("readMdSal: no nodes ");
228             return false;
229         }
230         LOG.info("readMdSal: network nodes: {} nodes added", allNodes.size());
231         LOG.debug("readMdSal: network nodes: {} nodes added", allNodes);
232
233         if (allLinks == null || allLinks.isEmpty()) {
234             LOG.error("readMdSal: no links ");
235             return false;
236         }
237         LOG.info("readMdSal: network links: {} links added", allLinks.size());
238         LOG.debug("readMdSal: network links: {} links added", allLinks);
239
240         return true;
241     }
242
243     private boolean analyzeNw() {
244
245         LOG.debug("analyzeNw: allNodes size {}, allLinks size {}", allNodes.size(), allLinks.size());
246
247         if (("100GE".equals(serviceType)) || ("OTU4".equals(serviceType))) {
248             // 100GE service and OTU4 service are handled at the openroadm-topology layer
249             for (Node node : allNodes) {
250                 validateNode(node);
251             }
252
253             LOG.debug("analyzeNw: allPceNodes size {}", allPceNodes.size());
254
255             if (aendPceNode == null || zendPceNode == null) {
256                 LOG.error("analyzeNw: Error in reading nodes: A or Z do not present in the network");
257                 return false;
258             }
259             for (Link link : allLinks) {
260                 validateLink(link);
261             }
262             // debug prints
263             LOG.debug("analyzeNw: addLinks size {}, dropLinks size {}", addLinks.size(), dropLinks.size());
264             // debug prints
265             LOG.debug("analyzeNw: azSrgs size = {}", azSrgs.size());
266             for (NodeId srg : azSrgs) {
267                 LOG.debug("analyzeNw: A/Z Srgs SRG = {}", srg.getValue());
268             }
269             // debug prints
270             for (PceLink link : addLinks) {
271                 filteraddLinks(link);
272             }
273             for (PceLink link : dropLinks) {
274                 filterdropLinks(link);
275             }
276
277         } else {
278             // ODU4, 10GE/ODU2e or 1GE/ODU0 services are handled at openroadm-otn layer
279
280             for (Node node : allNodes) {
281                 validateOtnNode(node);
282             }
283
284             LOG.info("analyzeNw: allPceNodes {}", allPceNodes);
285
286             if (aendPceNode == null || zendPceNode == null) {
287                 LOG.error("analyzeNw: Error in reading nodes: A or Z do not present in the network");
288                 return false;
289             }
290             for (Link link : allLinks) {
291                 validateLink(link);
292             }
293         }
294
295         LOG.info("analyzeNw: allPceNodes size {}, allPceLinks size {}", allPceNodes.size(), allPceLinks.size());
296
297         if ((allPceNodes.size() == 0) || (allPceLinks.size() == 0)) {
298             return false;
299         }
300
301         LOG.debug("analyzeNw: allPceNodes {}", allPceNodes);
302         LOG.debug("analyzeNw: allPceLinks {}", allPceLinks);
303
304         return true;
305     }
306
307     private boolean filteraddLinks(PceLink pcelink) {
308
309         NodeId nodeId = pcelink.getSourceId();
310
311         if (azSrgs.contains(nodeId)) {
312             allPceLinks.put(pcelink.getLinkId(), pcelink);
313             allPceNodes.get(nodeId).addOutgoingLink(pcelink);
314             LOG.debug("analyzeNw: Add_LINK added to source and to allPceLinks {}", pcelink.getLinkId());
315             return true;
316         }
317
318         // remove the SRG from PceNodes, as it is not directly connected to A/Z
319         allPceNodes.remove(nodeId);
320         LOG.debug("analyzeNw: SRG removed {}", nodeId.getValue());
321
322         return false;
323     }
324
325     private boolean filterdropLinks(PceLink pcelink) {
326
327         NodeId nodeId = pcelink.getDestId();
328
329         if (azSrgs.contains(nodeId)) {
330             allPceLinks.put(pcelink.getLinkId(), pcelink);
331             allPceNodes.get(nodeId).addOutgoingLink(pcelink);
332             LOG.debug("analyzeNw: Drop_LINK added to dest and to allPceLinks {}", pcelink.getLinkId());
333             return true;
334         }
335
336         // remove the SRG from PceNodes, as it is not directly connected to A/Z
337         allPceNodes.remove(pcelink.getDestId());
338         LOG.debug("analyzeNw: SRG removed {}", nodeId.getValue());
339
340         return false;
341     }
342
343     private boolean validateLink(Link link) {
344         LOG.info("validateLink: link {} ", link);
345
346         NodeId sourceId = link.getSource().getSourceNode();
347         NodeId destId = link.getDestination().getDestNode();
348         PceNode source = allPceNodes.get(sourceId);
349         PceNode dest = allPceNodes.get(destId);
350
351         if (source == null) {
352             LOG.debug("validateLink: Link is ignored due source node is rejected by node validation - {}",
353                 link.getSource().getSourceNode().getValue());
354             return false;
355         }
356         if (dest == null) {
357             LOG.debug("validateLink: Link is ignored due dest node is rejected by node validation - {}",
358                 link.getDestination().getDestNode().getValue());
359             return false;
360         }
361
362         if (("100GE".equals(serviceType)) || ("OTU4".equals(serviceType))) {
363             // 100GE or OTU4 services are handled at WDM Layer
364             PceLink pcelink = new PceLink(link, source, dest);
365             if (!pcelink.isValid()) {
366                 dropOppositeLink(link);
367                 LOG.error(" validateLink: Link is ignored due errors in network data or in opposite link");
368                 return false;
369             }
370             LinkId linkId = pcelink.getLinkId();
371             if (validateLinkConstraints(pcelink).equals(ConstraintTypes.HARD_EXCLUDE)) {
372                 dropOppositeLink(link);
373                 LOG.debug("validateLink: constraints : link is ignored == {}", linkId.getValue());
374                 return false;
375             }
376             switch (pcelink.getlinkType()) {
377                 case ROADMTOROADM:
378                 case EXPRESSLINK:
379                     allPceLinks.put(linkId, pcelink);
380                     source.addOutgoingLink(pcelink);
381                     LOG.debug("validateLink: {}-LINK added to allPceLinks {}",
382                         pcelink.getlinkType(), pcelink);
383                     break;
384                 case ADDLINK:
385                     pcelink.setClient(source.getRdmSrgClient(pcelink.getSourceTP().toString()));
386                     addLinks.add(pcelink);
387                     LOG.debug("validateLink: ADD-LINK saved  {}", pcelink);
388                     break;
389                 case DROPLINK:
390                     pcelink.setClient(dest.getRdmSrgClient(pcelink.getDestTP().toString()));
391                     dropLinks.add(pcelink);
392                     LOG.debug("validateLink: DROP-LINK saved  {}", pcelink);
393                     break;
394                 case XPONDERINPUT:
395                     // store separately all SRG links directly
396                     azSrgs.add(sourceId);
397                     // connected to A/Z
398                     if (!dest.checkTP(pcelink.getDestTP().toString())) {
399                         LOG.debug(
400                             "validateLink: XPONDER-INPUT is rejected as NW port is busy - {} ", pcelink);
401                         return false;
402                     }
403                     if (dest.getXpdrClient(pcelink.getDestTP().toString()) != null) {
404                         pcelink.setClient(dest.getXpdrClient(pcelink.getDestTP().toString()));
405                     }
406                     allPceLinks.put(linkId, pcelink);
407                     source.addOutgoingLink(pcelink);
408                     LOG.debug("validateLink: XPONDER-INPUT link added to allPceLinks {}", pcelink);
409                     break;
410                 // does it mean XPONDER==>>SRG ?
411                 case XPONDEROUTPUT:
412                     // store separately all SRG links directly
413                     azSrgs.add(destId);
414                     // connected to A/Z
415                     if (!source.checkTP(pcelink.getSourceTP().toString())) {
416                         LOG.debug(
417                             "validateLink: XPONDER-OUTPUT is rejected as NW port is busy - {} ", pcelink);
418                         return false;
419                     }
420                     if (source.getXpdrClient(pcelink.getSourceTP().toString()) != null) {
421                         pcelink.setClient(source.getXpdrClient(pcelink.getSourceTP().toString()));
422                     }
423                     allPceLinks.put(linkId, pcelink);
424                     source.addOutgoingLink(pcelink);
425                     LOG.debug("validateLink: XPONDER-OUTPUT link added to allPceLinks {}", pcelink);
426                     break;
427                 default:
428                     LOG.warn("validateLink: link type is not supported {}", pcelink);
429             }
430             return true;
431
432         } else if (("ODU4".equals(serviceType)) || ("10GE".equals(serviceType)) || ("1GE".equals(serviceType))) {
433             // ODU4, 1GE and 10GE services relying on ODU2, ODU2e or ODU0 services are handled at OTN layer
434             PceLink pceOtnLink = new PceLink(link, source, dest);
435
436             if (!pceOtnLink.isOtnValid(link, serviceType)) {
437                 dropOppositeLink(link);
438                 LOG.error(" validateLink: Link is ignored due errors in network data or in opposite link");
439                 return false;
440             }
441
442             LinkId linkId = pceOtnLink.getLinkId();
443             if (validateLinkConstraints(pceOtnLink).equals(ConstraintTypes.HARD_EXCLUDE)) {
444                 dropOppositeLink(link);
445                 LOG.debug("validateLink: constraints : link is ignored == {}", linkId.getValue());
446                 return false;
447             }
448
449             switch (pceOtnLink.getlinkType()) {
450                 case OTNLINK:
451                     if (dest.getXpdrClient(pceOtnLink.getDestTP().toString()) != null) {
452                         pceOtnLink.setClient(dest.getXpdrClient(pceOtnLink.getDestTP().toString()));
453                     }
454
455                     allPceLinks.put(linkId, pceOtnLink);
456                     source.addOutgoingLink(pceOtnLink);
457                     LOG.info("validateLink: OTN-LINK added to allPceLinks {}", pceOtnLink);
458                     break;
459                 default:
460                     LOG.warn("validateLink: link type is not supported {}", pceOtnLink);
461             }
462             return true;
463
464         } else {
465             LOG.error(" validateLink: Unmanaged service type {}", serviceType);
466             return false;
467         }
468
469     }
470
471     private boolean validateNode(Node node) {
472         LOG.debug("validateNode: node {} ", node);
473         // PceNode will be used in Graph algorithm
474         Node1 node1 = node.augmentation(Node1.class);
475         if (node1 == null) {
476             LOG.error("getNodeType: no Node1 (type) Augmentation for node: [{}]. Node is ignored", node.getNodeId());
477             return false;
478         }
479         OpenroadmNodeType nodeType = node1.getNodeType();
480         String deviceNodeId = MapUtils.getSupNetworkNode(node);
481         // Should never happen but because of existing topology test files
482         // we have to manage this case
483         if (deviceNodeId == null || deviceNodeId.isBlank()) {
484             deviceNodeId = node.getNodeId().getValue();
485         }
486         LOG.info("Device node id {} for {}", deviceNodeId, node);
487         PceOpticalNode pceNode = new PceOpticalNode(node, nodeType, mappingUtils.getOpenRoadmVersion(deviceNodeId));
488         pceNode.validateAZxponder(anodeId, znodeId, input.getServiceAEnd().getServiceFormat());
489         pceNode.initWLlist();
490
491         if (!pceNode.isValid()) {
492             LOG.warn(" validateNode: Node is ignored");
493             return false;
494         }
495         if (validateNodeConstraints(pceNode).equals(ConstraintTypes.HARD_EXCLUDE)) {
496             return false;
497         }
498         if (endPceNode(nodeType, pceNode.getNodeId(), pceNode) && this.aendPceNode == null
499             && isAZendPceNode(this.serviceFormatA, pceNode, anodeId, "A")) {
500             this.aendPceNode = pceNode;
501         }
502         if (endPceNode(nodeType, pceNode.getNodeId(), pceNode) && this.zendPceNode == null
503             && isAZendPceNode(this.serviceFormatZ, pceNode, znodeId, "Z")) {
504             this.zendPceNode = pceNode;
505         }
506
507         allPceNodes.put(pceNode.getNodeId(), pceNode);
508         LOG.debug("validateNode: node is saved {}", pceNode.getNodeId().getValue());
509         return true;
510     }
511
512     private boolean isAZendPceNode(String serviceFormat, PceOpticalNode pceNode, String azNodeId, String azEndPoint) {
513         switch (serviceFormat) {
514             case "Ethernet":
515             case "OC":
516                 if (pceNode.getSupNetworkNodeId().equals(azNodeId)) {
517                     return true;
518                 }
519                 return false;
520             case "OTU":
521                 if ("A".equals(azEndPoint) && pceNode.getNodeId().getValue()
522                     .equals(this.input.getServiceAEnd().getRxDirection().getPort().getPortDeviceName())) {
523                     return true;
524                 }
525                 if ("Z".equals(azEndPoint) && pceNode.getNodeId().getValue()
526                     .equals(this.input.getServiceZEnd().getRxDirection().getPort().getPortDeviceName())) {
527                     return true;
528                 }
529                 return false;
530             default:
531                 LOG.debug("Unsupported service Format {} for node {}", serviceFormat, pceNode.getNodeId().getValue());
532                 return false;
533         }
534     }
535
536     private boolean validateOtnNode(Node node) {
537         LOG.info("validateOtnNode: {} ", node.getNodeId().getValue());
538         // PceOtnNode will be used in Graph algorithm
539         if (node.augmentation(Node1.class) != null) {
540             OpenroadmNodeType nodeType = node.augmentation(Node1.class).getNodeType();
541
542             PceOtnNode pceOtnNode = new PceOtnNode(node, nodeType, node.getNodeId(), "otn", serviceType);
543             pceOtnNode.validateXponder(anodeId, znodeId);
544
545             if (!pceOtnNode.isValid()) {
546                 LOG.warn(" validateOtnNode: Node {} is ignored", node.getNodeId().getValue());
547                 return false;
548             }
549             if (validateNodeConstraints(pceOtnNode).equals(ConstraintTypes.HARD_EXCLUDE)) {
550                 return false;
551             }
552             if (pceOtnNode.getNodeId().getValue().equals(anodeId) && this.aendPceNode == null) {
553                 this.aendPceNode = pceOtnNode;
554             }
555             if (pceOtnNode.getNodeId().getValue().equals(znodeId) && this.zendPceNode == null) {
556                 this.zendPceNode = pceOtnNode;
557             }
558             allPceNodes.put(pceOtnNode.getNodeId(), pceOtnNode);
559             LOG.info("validateOtnNode: node {} is saved", node.getNodeId().getValue());
560             return true;
561         } else {
562             LOG.error("ValidateOtnNode: no node-type augmentation. Node {} is ignored", node.getNodeId().getValue());
563             return false;
564         }
565
566 //        if (mode == "AZ") {
567 //            pceOtnNode.validateAZxponder(anodeId, znodeId);
568 //        } else if (mode == "intermediate") {
569 //            pceOtnNode.validateIntermediateSwitch();
570 //        } else {
571 //            LOG.error("validateOtnNode: unproper mode passed to the method : {} not supported", mode);
572 //            return null;
573 //        }
574     }
575
576     private ConstraintTypes validateNodeConstraints(PceNode pcenode) {
577         if (pceHardConstraints.getExcludeSupNodes().isEmpty() && pceHardConstraints.getExcludeCLLI().isEmpty()) {
578             return ConstraintTypes.NONE;
579         }
580         if (pceHardConstraints.getExcludeSupNodes().contains(pcenode.getSupNetworkNodeId())) {
581             LOG.info("validateNodeConstraints: {}", pcenode.getNodeId().getValue());
582             return ConstraintTypes.HARD_EXCLUDE;
583         }
584         if (pceHardConstraints.getExcludeCLLI().contains(pcenode.getSupClliNodeId())) {
585             LOG.info("validateNodeConstraints: {}", pcenode.getNodeId().getValue());
586             return ConstraintTypes.HARD_EXCLUDE;
587         }
588         return ConstraintTypes.NONE;
589     }
590
591     private ConstraintTypes validateLinkConstraints(PceLink link) {
592         if (pceHardConstraints.getExcludeSRLG().isEmpty()) {
593             return ConstraintTypes.NONE;
594         }
595
596         // for now SRLG is the only constraint for link
597         if (link.getlinkType() != OpenroadmLinkType.ROADMTOROADM) {
598             return ConstraintTypes.NONE;
599         }
600
601         List<Long> constraints = new ArrayList<>(pceHardConstraints.getExcludeSRLG());
602         constraints.retainAll(link.getsrlgList());
603         if (!constraints.isEmpty()) {
604             LOG.info("validateLinkConstraints: {}", link.getLinkId().getValue());
605             return ConstraintTypes.HARD_EXCLUDE;
606         }
607
608         return ConstraintTypes.NONE;
609     }
610
611     private void dropOppositeLink(Link link) {
612         LinkId opplink = MapUtils.extractOppositeLink(link);
613
614         if (allPceLinks.containsKey(opplink)) {
615             allPceLinks.remove(opplink);
616         } else {
617             linksToExclude.add(opplink);
618         }
619     }
620
621     private Boolean endPceNode(OpenroadmNodeType openroadmNodeType, NodeId nodeId, PceOpticalNode pceNode) {
622         switch (openroadmNodeType) {
623             case SRG:
624                 pceNode.initSrgTps();
625                 this.azSrgs.add(nodeId);
626                 break;
627             case XPONDER:
628                 pceNode.initXndrTps(input.getServiceAEnd().getServiceFormat());
629                 break;
630             default:
631                 LOG.warn("endPceNode: Node {} is not SRG or XPONDER !", nodeId);
632                 return false;
633         }
634
635         if (!pceNode.isValid()) {
636             LOG.error("validateNode : there are no availaible wavelengths in node {}", pceNode.getNodeId().getValue());
637             return false;
638         }
639         return true;
640     }
641
642     public PceNode getaendPceNode() {
643         return aendPceNode;
644     }
645
646     public PceNode getzendPceNode() {
647         return zendPceNode;
648     }
649
650     public Map<NodeId, PceNode> getAllPceNodes() {
651         return this.allPceNodes;
652     }
653
654     public Map<LinkId, PceLink> getAllPceLinks() {
655         return this.allPceLinks;
656     }
657
658     public String getServiceType() {
659         return serviceType;
660     }
661
662     public PceResult getReturnStructure() {
663         return returnStructure;
664     }
665
666     private static void printNodesInfo(Map<NodeId, PceNode> allPceNodes) {
667         allPceNodes.forEach(((nodeId, pceNode) -> {
668             LOG.info("In printNodes in node {} : outgoing links {} ", pceNode.getNodeId().getValue(),
669                     pceNode.getOutgoingLinks());
670         }));
671     }
672 }