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