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