2 * Copyright © 2017 Orange, Inc. and others. All rights reserved.
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
9 package org.opendaylight.transportpce.stubpce.topology;
11 import com.google.common.collect.Lists;
13 import java.util.ArrayList;
14 import java.util.List;
15 import java.util.ListIterator;
16 import java.util.SortedSet;
17 import java.util.TreeSet;
19 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.stubpce.rev170426.path.description.list.PathDescriptionsBuilder;
20 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev170426.path.description.AToZDirection;
21 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev170426.path.description.AToZDirectionBuilder;
22 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev170426.path.description.ZToADirection;
23 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev170426.path.description.ZToADirectionBuilder;
24 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev170426.path.description.atoz.direction.AToZ;
25 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev170426.path.description.atoz.direction.AToZBuilder;
26 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev170426.path.description.atoz.direction.AToZKey;
27 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev170426.path.description.ztoa.direction.ZToA;
28 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev170426.path.description.ztoa.direction.ZToABuilder;
29 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev170426.path.description.ztoa.direction.ZToAKey;
30 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev170426.pce.resource.Resource;
31 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev170426.pce.resource.ResourceBuilder;
32 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev170426.pce.resource.resource.resource.Link;
33 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev170426.pce.resource.resource.resource.LinkBuilder;
34 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev170426.pce.resource.resource.resource.link.LinkIdentifierBuilder;
35 import org.slf4j.Logger;
36 import org.slf4j.LoggerFactory;
40 * Class to build Path between
43 * @author <a href="mailto:martial.coulibaly@gfi.com">Martial Coulibaly</a> on
46 public class SuperNodePath {
48 private static final Logger LOG = LoggerFactory.getLogger(SuperNodePath.class);
49 /** List of NodeLinkNode. */
50 private List<NodeLinkNode> paths;
51 /** Supernode topology. */
52 private Network network;
55 * SuperNodePath constructor.
57 * @param network Supernode topology
59 public SuperNodePath(Network network) {
60 setPaths(new ArrayList<NodeLinkNode>());
61 this.network = network;
65 * test if Supernode is an
66 * extremity of path to build.
68 * @param end extremity node Id
69 * @param supernodes Supernodes list to build path
70 * @return true if link extremity, false else
72 private Boolean endNode(String end, List<String> supernodes) {
73 Boolean result = false;
74 if (end != null && end.compareTo(" ") != 0) {
75 for (String node : supernodes) {
76 if (node.compareTo(end) == 0) {
89 * @param nodeId supernode id to get
90 * @return SuperNode supernode gets
92 public SuperNode getSuperNode(String nodeId) {
93 SuperNode result = null;
94 if (network != null) {
95 for (SuperNode tmp : network.getSuperNodes()) {
96 if (tmp.getSuperNodeId().compareTo(nodeId) == 0) {
109 * @param aend begin extremity
110 * @param zend end extremity
111 * @param links Roadm to Roadm links
112 * @param direct determine if link is direct or not
113 * @return String list of links name
115 private List<String> findLinks(String aend, String zend, List<String> links, boolean direct) {
116 List<String> result = new ArrayList<String>();
117 if (links.size() > 0) {
118 aend = aend.replace("Node", "ROADM");
119 zend = zend.replace("Node", "ROADM");
120 String atozlink = null;
121 String ztoalink = null;
122 for (String tmp : links) {
123 if (tmp.contains(aend)
124 && tmp.contains(zend)) {
125 LOG.info("direct path found for : {} / {}", aend, zend);
126 if (tmp.startsWith(aend)) {
129 if (tmp.startsWith(zend)) {
132 if (atozlink != null && ztoalink != null) {
133 result.add(atozlink.concat("/").concat(ztoalink));
140 LOG.info("no roadm-to-roadm links !");
146 *find next Supernode hop.
148 * @param link roadm to roadm link
149 * @param aend begin supernode
150 * @param node list of supernode id
151 * @return String supernodeId next hop
153 private String findHop(String link, String aend, List<String> node) {
154 String result = null;
155 aend = aend.replace("Node", "ROADM");
156 for (String tmp : node) {
157 tmp = tmp.replace("Node", "ROADM");
158 if (tmp.compareTo(aend) != 0) {
159 if (link.contains(aend) && link.contains(tmp)) {
160 LOG.info("hop : {}", tmp);
169 *get all Supernode in
172 * @return String list of Supernode Id
174 private List<String> getSuperNodeId() {
175 List<String> result = new ArrayList<String>();
176 if (network.getSuperNodes().size() > 0) {
177 for (SuperNode tmp : network.getSuperNodes()) {
178 result.add(tmp.getSuperNodeId());
185 * get all roadm to roadm
188 * @return String list of roadm to roadm links
190 private List<String> getRoadmLinks() {
191 List<String> result = new ArrayList<String>();
192 if (network.getRoadmToroadm().getLinks().size() > 0) {
193 for (String tmp : network.getRoadmToroadm().getLinks()) {
201 * create NodeLinkNode
204 * @param links String list of roadm to roadm links
205 * @param aend beginning Supernode
206 * @param zend ending Supernode
207 * @param direct determine if link is direct or not
209 private void fill(List<String> links,String aend, String zend, boolean direct) {
210 String term = "indirect";
214 if (!links.isEmpty()) {
215 List<String> atoz = new ArrayList<String>();
216 List<String> ztoa = new ArrayList<String>();
217 for (String tmp : links) {
218 String [] split = tmp.split("/");
219 if (split.length == 2) {
224 if (!atoz.isEmpty() && atoz.size() == ztoa.size()) {
225 NodeLinkNode node = new NodeLinkNode(aend, zend, atoz,ztoa,direct);
230 LOG.info("{} links not found !", term);
235 * launch SupernodePath process
236 * to build NodeLinkNode.
238 * @param aend beginning extremity path
239 * @param zend ending extremity path
241 public void run(String aend, String zend) {
242 if (network != null) {
243 List<String> supernodes = getSuperNodeId();
244 List<String> roadmLinks = getRoadmLinks();
245 if (aend != null && zend != null) {
246 int size = supernodes.size();
248 List<String> links = null;
250 if (endNode(aend, supernodes) && endNode(zend, supernodes)) {
251 LOG.info("Getting direct links ...");
252 links = new ArrayList<String>();
253 links = findLinks(aend,zend,roadmLinks,true);
254 fill(links, aend, zend, true);
255 LOG.info("Getting indirect links ..");
256 links = new ArrayList<String>();
257 for (String tmp : roadmLinks) {
258 hop = findHop(tmp, aend, supernodes);
260 if (hop.compareTo(zend.replace("Node", "ROADM")) != 0) {
261 LOG.info("next hop found : {}", hop);
262 links.addAll(findLinks(aend,hop,roadmLinks,false));
263 links.addAll(findLinks(hop,zend,roadmLinks,false));
269 fill(links, aend, zend, false);
271 LOG.info("aend or/and zend not exists !");
275 LOG.info("aend or/and is null !");
278 LOG.info("network is null !!");
284 * in AToZ List containing
287 * @param order beginning order
288 * @param atozDirection AToZdirection List
289 * @return AToZdirection List
291 public List<AToZDirection> modifyOrder(int order, List<AToZDirection> atozDirection) {
292 List<AToZDirection> result = new ArrayList<AToZDirection>();
293 for (AToZDirection tmp : atozDirection) {
294 List<AToZ> atozList = tmp.getAToZ();
295 int size = atozList.size();
297 for (ListIterator<AToZ> it = atozList.listIterator(); it.hasNext();) {
298 AToZ atoz = it.next();
299 org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription
300 .rev170426.pce.resource.resource.Resource res = atoz.getResource().getResource();
301 int tmpkey = order + Integer.parseInt(atoz.getKey().getId());
302 AToZKey atozKey = new AToZKey(Integer.toString(tmpkey));
303 org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface
304 .pathdescription.rev170426.pce.resource.Resource resource = new ResourceBuilder()
305 .setResource(res).build();
306 AToZ hop = new AToZBuilder().setId(atozKey.getId()).setKey(atozKey).setResource(resource).build();
318 * merge two AToZdirection List.
320 * @param cleanInterA first AToZdirection List
321 * @param cleanInterZ second AToZdirection List
322 * @param first boolean to determine if it is the first time merge is done
323 * @return AToZDirection List
325 public List<AToZDirection> merge(List<AToZDirection> cleanInterA, List<AToZDirection> cleanInterZ,
327 List<AToZDirection> result = new ArrayList<AToZDirection>();
328 if (!cleanInterA.isEmpty()) {
329 int order = cleanInterA.get(0).getAToZ().size();
331 List<AToZDirection> modify = modifyOrder(order, cleanInterZ);
332 if (!modify.isEmpty()) {
333 for (AToZDirection tmp : cleanInterA) {
334 List<AToZ> atozList = new ArrayList<AToZ>(tmp.getAToZ());
335 for (AToZDirection add : modify) {
336 ListIterator<AToZ> it = atozList.listIterator();
337 /** on va a la fin de la liste */
338 while (it.hasNext()) {
341 List<AToZ> addList = add.getAToZ();
342 for (AToZ atoz : addList) {
345 AToZDirectionBuilder newDirection = new AToZDirectionBuilder();
346 newDirection.setRate((long) 100).setAToZWavelengthNumber((long) 200).setAToZ(atozList);
347 result.add(newDirection.build());
348 atozList = new ArrayList<AToZ>(tmp.getAToZ());
352 LOG.info("modify List is empty ! ");
355 LOG.info("order is not superior to 0");
358 if (first && !cleanInterZ.isEmpty()) {
359 LOG.info("first merge so result is a copy of second AToZDirection List !");
360 result = new ArrayList<AToZDirection>(cleanInterZ);
362 LOG.info("cleanInterA is empty !");
372 * @param atozLink atoz roadm link
373 * @param ztoaLink ztoa roadm link
374 * @return String list of degree
376 public List<String> getDeg(String atozLink, String ztoaLink) {
377 List<String> result = new ArrayList<String>();
378 if (atozLink != null && ztoaLink != null) {
379 String [] split = atozLink.split("-", 4);
380 if (split.length == 4) {
381 result = Lists.newArrayList(split[1],split[3]);
384 LOG.info("atozlink and/or ztoalink is null !");
391 * (ROADMA-DEG1-ROADMZ-DEG2
393 * ROADMZ-DEG2-ROADMA-DEG1).
395 * @param linkId Link name
396 * @return String link name reversed
398 public String reverseLinkId(String linkId) {
399 StringBuilder builder = new StringBuilder();
400 String [] split = linkId.split("-");
401 int size = split.length;
404 if (linkId.contains("XPDR")) {
405 if (linkId.startsWith("XPDR")) {
406 builder.append(split[1]).append("-")
407 .append(split[2]).append("-")
410 builder.append(split[2]).append("-")
411 .append(split[0]).append("-")
418 builder.append(split[2]).append("-")
419 .append(split[3]).append("-")
420 .append(split[0]).append("-")
427 return builder.toString();
431 * convert AToAdirection to
434 * @param atozDirection AToZdirection to convert
435 * @return ZToAdirection
437 public ZToADirection convertToZtoaDirection(AToZDirection atozDirection) {
438 ZToADirectionBuilder ztoaDirection = new ZToADirectionBuilder();
439 if (atozDirection != null) {
440 List<AToZ> atozList = atozDirection.getAToZ();
441 List<ZToA> ztoaList = new ArrayList<ZToA>();
442 if (!atozList.isEmpty()) {
443 List<AToZ> reverse = Lists.reverse(atozList);
444 /** Building path. */
445 ZToAKey ztoaKey = null;
446 Resource resource = null;
447 org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription
448 .rev170426.pce.resource.resource.Resource resLink = null;
451 for (AToZ atoz : reverse) {
452 ztoaKey = new ZToAKey(Integer.toString(odr));
453 resLink = atoz.getResource().getResource();
454 if (resLink != null) {
455 if (resLink instanceof Link) {
456 Link link = (Link) resLink;
457 String newLinkId = reverseLinkId(link.getLinkIdentifier().getLinkId());
458 if (newLinkId != null) {
459 resource = new ResourceBuilder().setResource(new LinkBuilder()
460 .setLinkIdentifier(new LinkIdentifierBuilder()
461 .setLinkId(newLinkId)
468 resource = new ResourceBuilder().setResource(resLink).build();
471 if (resource != null) {
472 hop = new ZToABuilder()
474 .setResource(resource)
479 LOG.info("resource is null ");
482 if (!ztoaList.isEmpty()) {
483 ztoaDirection.setRate((long) 100).setZToAWavelengthNumber((long) 200).setZToA(ztoaList);
485 LOG.info("ztoaList is empty !");
489 return ztoaDirection.build();
493 *build Pathdescritions ordered List
494 *to be loaded in Pathdescriptions
497 * @param atozDirection AToZdirection List
498 * @param term direct ou indirect
499 * @return PathDescriptionsOrdered List
501 private SortedSet<PathDescriptionsOrdered> buildPathDescription(List<AToZDirection> atozDirection, String term) {
502 SortedSet<PathDescriptionsOrdered> result = new TreeSet<PathDescriptionsOrdered>();
503 PathDescriptionsBuilder pathDescr = new PathDescriptionsBuilder();
504 int size = atozDirection.size();
505 if (!atozDirection.isEmpty()) {
506 LOG.info("result list AToZDirection size : {}", atozDirection.size());
507 List<ZToADirection> ztoadirList = new ArrayList<ZToADirection>();
508 for (AToZDirection atozdir : atozDirection) {
509 ZToADirection ztodir = convertToZtoaDirection(atozdir);
510 if (ztodir != null) {
511 ztoadirList.add(ztodir);
514 if (!ztoadirList.isEmpty() && size == ztoadirList.size()) {
515 LOG.info("building PathDescriptions ...");
517 String pathName = null;
518 for (int indexPath = 0 ; indexPath < size ; indexPath++) {
519 pathName = term.concat(Integer.toString(index));
520 LOG.info("pathName : {}", pathName);
521 pathDescr.setAToZDirection(atozDirection.get(indexPath))
522 .setZToADirection(ztoadirList.get(indexPath)).setPathName(pathName);
523 LOG.info("pathdesciption : {}", pathDescr.build().toString());
524 result.add(new PathDescriptionsOrdered(pathDescr.build(),index));
528 LOG.info("Something wrong happen during atodir conversion...");
532 LOG.info("atozDirection is empty");
538 * gets link extremity.
541 * @return Supernode List of extremities
543 public List<SuperNode> getSuperNodeEndLink(String link) {
544 List<SuperNode> result = new ArrayList<SuperNode>();
546 String [] split = link.split("-");
547 if (split.length == 4) {
548 String aend = split[0].replaceAll("ROADM", "Node");
549 String zend = split[2].replaceAll("ROADM", "Node");
550 if (aend != null && zend != null) {
551 LOG.info("getting super node for : {} and {}", aend, zend);
552 SuperNode aendSp = getSuperNode(aend);
553 SuperNode zendSp = getSuperNode(zend);
554 if (aendSp != null && zendSp != null) {
565 * build all direct paths.
567 * @param aend beginning extremity path
568 * @param zend ending extremity path
569 * @param paths NodeLinkNode list paths
570 * @return PathDescriptionsOrdered List of direct paths
572 public SortedSet<PathDescriptionsOrdered> getDirectPathDesc(String aend, String zend,List<NodeLinkNode> paths) {
573 List<AToZDirection> atozdirectionPaths = new ArrayList<AToZDirection>();
574 SortedSet<PathDescriptionsOrdered> result = new TreeSet<PathDescriptionsOrdered>();
575 SuperNode aendSp = getSuperNode(aend);
576 SuperNode zendSp = getSuperNode(zend);
577 if (!paths.isEmpty()) {
578 for (NodeLinkNode tmp : paths) {
579 if (tmp.getDirect()) {
580 LOG.info("Direct NodeLinkNode : {}", tmp.toString());
581 String atozLink = null;
582 String ztoaLink = null;
583 atozLink = tmp.getAtozLink().get(0);
584 ztoaLink = tmp.getZtoaLink().get(0);
585 if (atozLink != null && ztoaLink != null) {
586 LOG.info("atozlink : {}", atozLink);
587 LOG.info("ztoalink : {}", ztoaLink);
588 InterNodePath interAend = new InterNodePath(aendSp);
589 interAend.buildPath(zend);
590 InterNodePath interZend = new InterNodePath(zendSp);
591 interZend.buildPath(zend);
592 List<String> deg = getDeg(atozLink,ztoaLink);
593 LOG.info("deg : {}", deg.toString());
594 if (deg.size() == 2) {
595 List<AToZDirection> cleanInterA =
596 interAend.replaceOrRemoveAToZDirectionEndLink(deg.get(0),"",atozLink,
597 interAend.getAtoz(),false);
598 List<AToZDirection> cleanInterZ =
599 interZend.replaceOrRemoveAToZDirectionEndLink("TAIL-LINKS",deg.get(1),"",
600 interZend.getAtoz(),true);
601 if (!cleanInterA.isEmpty() && !cleanInterZ.isEmpty()) {
602 atozdirectionPaths.addAll(merge(cleanInterA,cleanInterZ,false));
604 LOG.info("cleanInterA ad/or cleanInterZ is empty !");
607 LOG.info("deg size is not correct, must be 2 ! ");
610 LOG.info("atozlink and / or ztoalink is null");
616 LOG.info("List of direct path is empty !");
618 if (!atozdirectionPaths.isEmpty()) {
619 LOG.info("result size : {}", result.size());
620 result = buildPathDescription(atozdirectionPaths,aend.concat("To").concat(zend).concat("_direct_"));
622 LOG.info("result is empty");
628 * build all indirect paths.
630 * @param aend beginning extremity path
631 * @param zend ending extremity path
632 * @param paths NodeLinkNode list paths
633 * @return PathDescriptionsOrdered List of indirect paths
635 public SortedSet<PathDescriptionsOrdered> getIndirectPathDesc(String aend, String zend,List<NodeLinkNode> paths) {
636 List<AToZDirection> atozdirectionPaths = new ArrayList<AToZDirection>();
637 SortedSet<PathDescriptionsOrdered> result = new TreeSet<PathDescriptionsOrdered>();
638 SuperNode aendSp = getSuperNode(aend);
639 SuperNode zendSp = getSuperNode(zend);
640 if (!paths.isEmpty()) {
641 for (NodeLinkNode tmp : paths) {
642 if (!tmp.getDirect()) {
643 LOG.info("Indirect NodeLinkNode : {}", tmp.toString());
644 int size = tmp.getAtozLink().size();
645 /** must be two for now just one hop. */
646 LOG.info("number of links : {}", size);
647 boolean first = true;
649 List<String> atozLinks = tmp.getAtozLink();
650 List<String> ztoaLinks = tmp.getZtoaLink();
651 if (!atozLinks.isEmpty() && !ztoaLinks.isEmpty()) {
652 LOG.info("atozlink : {}", atozLinks.toString());
653 LOG.info("ztoalink : {}", ztoaLinks.toString());
656 List<SuperNode> hop = getSuperNodeEndLink(atozLinks.get(loop));
657 if (!hop.isEmpty() && hop.size() == 2) {
660 InterNodePath interAend = new InterNodePath(aendSp);
661 interAend.buildPath(zend);
662 LOG.info("interAend : {}", interAend.getAtoz().toString());
663 InterNodePath interZend = new InterNodePath(zendSp);
664 interZend.buildPath(zend);
665 LOG.info("interZend : {}", interZend.getAtoz().toString());
666 List<String> deg1 = getDeg(atozLinks.get(loop),ztoaLinks.get(loop));
667 LOG.info("deg1 : {}", deg1.toString());
668 if (!deg1.isEmpty() && deg1.size() == 2) {
669 List<AToZDirection> cleanInterA = null;
670 List<AToZDirection> cleanInterZ = null;
671 if (zendSp.getSuperNodeId().compareTo(zend) == 0) {
672 cleanInterA = interAend.replaceOrRemoveAToZDirectionEndLink(deg1.get(0),
673 "",atozLinks.get(loop),interAend.getAtoz(),false);
674 LOG.info("next hop is zend");
675 cleanInterZ = interZend.replaceOrRemoveAToZDirectionEndLink("TAIL-LINKS",
676 deg1.get(1),"",interZend.getAtoz(),true);
677 } else if (loop < 1) {
678 cleanInterA = interAend.replaceOrRemoveAToZDirectionEndLink(deg1.get(0),
679 "",atozLinks.get(loop),interAend.getAtoz(),false);
680 cleanInterZ = interZend.getAToZDirectionEndBy(deg1.get(1),
681 interZend.getAtoz(), 1);
683 if (!cleanInterA.isEmpty() && !cleanInterZ.isEmpty()) {
684 atozdirectionPaths = merge(atozdirectionPaths,cleanInterA,first);
685 atozdirectionPaths = merge(atozdirectionPaths, cleanInterZ,false);
688 LOG.info("cleanInterA ad/or cleanInterZ is empty !");
693 LOG.info("Hop list is empty");
699 LOG.info("Link size is not supported , must be two !");
704 LOG.info("List of indirect path is empty !");
706 if (!atozdirectionPaths.isEmpty()) {
707 LOG.info("result size : {}", result.size());
708 result = buildPathDescription(atozdirectionPaths,aend.concat("To").concat(zend).concat("_indirect_"));
710 LOG.info("result is empty");
715 public static void main(String[] args) {
716 Topology topo = new Topology();
718 SuperNodePath path = new SuperNodePath(topo.getNetwork());
719 String aend = "NodeA";
720 String zend = "NodeZ";
721 path.run(aend, zend);
722 path.getDirectPathDesc(aend, zend, path.getPaths());
723 path.getIndirectPathDesc(aend, zend, path.getPaths());
726 public List<NodeLinkNode> getPaths() {
730 public void setPaths(List<NodeLinkNode> paths) {