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