/* * Copyright © 2017 Orange, Inc. and others. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html */ package org.opendaylight.transportpce.stubpce.topology; import com.google.common.collect.Lists; import java.util.ArrayList; import java.util.List; import java.util.ListIterator; import java.util.SortedSet; import java.util.TreeSet; import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.stubpce.rev170426.path.description.list.PathDescriptionsBuilder; import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev170426.path.description.AToZDirection; import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev170426.path.description.AToZDirectionBuilder; import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev170426.path.description.ZToADirection; import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev170426.path.description.ZToADirectionBuilder; import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev170426.path.description.atoz.direction.AToZ; import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev170426.path.description.atoz.direction.AToZBuilder; import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev170426.path.description.atoz.direction.AToZKey; import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev170426.path.description.ztoa.direction.ZToA; import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev170426.path.description.ztoa.direction.ZToABuilder; import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev170426.path.description.ztoa.direction.ZToAKey; import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev170426.pce.resource.Resource; import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev170426.pce.resource.ResourceBuilder; import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev170426.pce.resource.resource.resource.Link; import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev170426.pce.resource.resource.resource.LinkBuilder; import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev170426.pce.resource.resource.resource.link.LinkIdentifierBuilder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Class to build Path between * two Supernode. * * @author Martial Coulibaly on * behalf of Orange */ public class SuperNodePath { /** Logging. */ private static final Logger LOG = LoggerFactory.getLogger(SuperNodePath.class); /** List of NodeLinkNode. */ private List paths; /** Supernode topology. */ private Network network; /** * SuperNodePath constructor. * * @param network Supernode topology */ public SuperNodePath(Network network) { setPaths(new ArrayList()); this.network = network; } /** * test if Supernode is an * extremity of path to build. * * @param end extremity node Id * @param supernodes Supernodes list to build path * @return true if link extremity, false else */ private Boolean endNode(String end, List supernodes) { Boolean result = false; if ((end != null) && (end.compareTo(" ") != 0)) { for (String node : supernodes) { if (node.compareTo(end) == 0) { result = true; break; } } } return result; } /** * get Supernode * with supernode Id. * * @param nodeId supernode id to get * @return SuperNode supernode gets */ public SuperNode getSuperNode(String nodeId) { SuperNode result = null; if (this.network != null) { for (SuperNode tmp : this.network.getSuperNodes()) { if (tmp.getSuperNodeId().compareTo(nodeId) == 0) { result = tmp; break; } } } return result; } /** *find links between *two Supernodes. * * @param aend begin extremity * @param zend end extremity * @param links Roadm to Roadm links * @param direct determine if link is direct or not * @return String list of links name */ private List findLinks(String aend, String zend, List links, boolean direct) { List result = new ArrayList(); if (links.size() > 0) { aend = aend.replace("Node", "ROADM"); zend = zend.replace("Node", "ROADM"); String atozlink = null; String ztoalink = null; for (String tmp : links) { if (tmp.contains(aend) && tmp.contains(zend)) { LOG.info("direct path found for : {} / {}", aend, zend); if (tmp.startsWith(aend)) { atozlink = tmp; } if (tmp.startsWith(zend)) { ztoalink = tmp; } if ((atozlink != null) && (ztoalink != null)) { result.add(atozlink.concat("/").concat(ztoalink)); atozlink = null; ztoalink = null; } } } } else { LOG.info("no roadm-to-roadm links !"); } return result; } /** *find next Supernode hop. * * @param link roadm to roadm link * @param aend begin supernode * @param node list of supernode id * @return String supernodeId next hop */ private String findHop(String link, String aend, List node) { String result = null; aend = aend.replace("Node", "ROADM"); for (String tmp : node) { tmp = tmp.replace("Node", "ROADM"); if (tmp.compareTo(aend) != 0) { if (link.contains(aend) && link.contains(tmp)) { LOG.info("hop : {}", tmp); result = tmp; } } } return result; } /** *get all Supernode in *topology. * * @return String list of Supernode Id */ private List getSuperNodeId() { List result = new ArrayList(); if (this.network.getSuperNodes().size() > 0) { for (SuperNode tmp : this.network.getSuperNodes()) { result.add(tmp.getSuperNodeId()); } } return result; } /** * get all roadm to roadm * links in topology. * * @return String list of roadm to roadm links */ private List getRoadmLinks() { List result = new ArrayList(); if (this.network.getRoadmToroadm().getLinks().size() > 0) { for (String tmp : this.network.getRoadmToroadm().getLinks()) { result.add(tmp); } } return result; } /** * create NodeLinkNode * structure. * * @param links String list of roadm to roadm links * @param aend beginning Supernode * @param zend ending Supernode * @param direct determine if link is direct or not */ private void fill(List links,String aend, String zend, boolean direct) { String term = "indirect"; if (direct) { term = "direct"; } if (!links.isEmpty()) { List atoz = new ArrayList(); List ztoa = new ArrayList(); for (String tmp : links) { String [] split = tmp.split("/"); if (split.length == 2) { atoz.add(split[0]); ztoa.add(split[1]); } } if (!atoz.isEmpty() && (atoz.size() == ztoa.size())) { NodeLinkNode node = new NodeLinkNode(aend, zend, atoz,ztoa,direct); this.paths.add(node); } } else { LOG.info("{} links not found !", term); } } /** * launch SupernodePath process * to build NodeLinkNode. * * @param aend beginning extremity path * @param zend ending extremity path */ public void run(String aend, String zend) { if (this.network != null) { List supernodes = getSuperNodeId(); List roadmLinks = getRoadmLinks(); if ((aend != null) && (zend != null)) { int size = supernodes.size(); String hop = null; List links = null; if (size > 0) { if (endNode(aend, supernodes) && endNode(zend, supernodes)) { LOG.info("Getting direct links ..."); links = new ArrayList(); links = findLinks(aend,zend,roadmLinks,true); fill(links, aend, zend, true); LOG.info("Getting indirect links .."); links = new ArrayList(); for (String tmp : roadmLinks) { hop = findHop(tmp, aend, supernodes); if (hop != null) { if (hop.compareTo(zend.replace("Node", "ROADM")) != 0) { LOG.info("next hop found : {}", hop); links.addAll(findLinks(aend,hop,roadmLinks,false)); links.addAll(findLinks(hop,zend,roadmLinks,false)); } else { break; } } } fill(links, aend, zend, false); } else { LOG.info("aend or/and zend not exists !"); } } } else { LOG.info("aend or/and is null !"); } } else { LOG.info("network is null !!"); } } /** * modify all AToZ Id * in AToZ List containing * in AToZdirection. * * @param order beginning order * @param atozDirection AToZdirection List * @return AToZdirection List */ public List modifyOrder(int order, List atozDirection) { List result = new ArrayList(); for (AToZDirection tmp : atozDirection) { List atozList = tmp.getAToZ(); int size = atozList.size(); if (size > 0) { for (ListIterator it = atozList.listIterator(); it.hasNext();) { AToZ atoz = it.next(); org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription .rev170426.pce.resource.resource.Resource res = atoz.getResource().getResource(); int tmpkey = order + Integer.parseInt(atoz.key().getId()); AToZKey atozKey = new AToZKey(Integer.toString(tmpkey)); org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface .pathdescription.rev170426.pce.resource.Resource resource = new ResourceBuilder() .setResource(res).build(); AToZ hop = new AToZBuilder().setId(atozKey.getId()).withKey(atozKey).setResource(resource).build(); it.remove(); it.add(hop); tmpkey++; } result.add(tmp); } } return result; } /** * merge two AToZdirection List. * * @param cleanInterA first AToZdirection List * @param cleanInterZ second AToZdirection List * @param first boolean to determine if it is the first time merge is done * @return AToZDirection List */ public List merge(List cleanInterA, List cleanInterZ, boolean first) { List result = new ArrayList(); if (!cleanInterA.isEmpty()) { int order = cleanInterA.get(0).getAToZ().size(); if (order > 0) { List modify = modifyOrder(order, cleanInterZ); if (!modify.isEmpty()) { for (AToZDirection tmp : cleanInterA) { List atozList = new ArrayList(tmp.getAToZ()); for (AToZDirection add : modify) { ListIterator it = atozList.listIterator(); /** on va a la fin de la liste */ while (it.hasNext()) { it.next(); } List addList = add.getAToZ(); for (AToZ atoz : addList) { it.add(atoz); } AToZDirectionBuilder newDirection = new AToZDirectionBuilder(); newDirection.setRate((long) 100).setAToZWavelengthNumber((long) 200).setAToZ(atozList); result.add(newDirection.build()); atozList = new ArrayList(tmp.getAToZ()); } } } else { LOG.info("modify List is empty ! "); } } else { LOG.info("order is not superior to 0"); } } else { if (first && !cleanInterZ.isEmpty()) { LOG.info("first merge so result is a copy of second AToZDirection List !"); result = new ArrayList(cleanInterZ); } else { LOG.info("cleanInterA is empty !"); } } return result; } /** * gets Degree number * for roadm links. * * @param atozLink atoz roadm link * @param ztoaLink ztoa roadm link * @return String list of degree */ public List getDeg(String atozLink, String ztoaLink) { List result = new ArrayList(); if ((atozLink != null) && (ztoaLink != null)) { String [] split = atozLink.split("-", 4); if (split.length == 4) { result = Lists.newArrayList(split[1],split[3]); } } else { LOG.info("atozlink and/or ztoalink is null !"); } return result; } /** * reverse link name * (ROADMA-DEG1-ROADMZ-DEG2 * to * ROADMZ-DEG2-ROADMA-DEG1). * * @param linkId Link name * @return String link name reversed */ public String reverseLinkId(String linkId) { StringBuilder builder = new StringBuilder(); String [] split = linkId.split("-"); int size = split.length; switch (size) { case 3: if (linkId.contains("XPDR")) { if (linkId.startsWith("XPDR")) { builder.append(split[1]).append("-") .append(split[2]).append("-") .append(split[0]); } else { builder.append(split[2]).append("-") .append(split[0]).append("-") .append(split[1]); } } break; case 4: builder.append(split[2]).append("-") .append(split[3]).append("-") .append(split[0]).append("-") .append(split[1]); break; default: break; } return builder.toString(); } /** * convert AToAdirection to * ZToAdirection. * * @param atozDirection AToZdirection to convert * @return ZToAdirection */ public ZToADirection convertToZtoaDirection(AToZDirection atozDirection) { ZToADirectionBuilder ztoaDirection = new ZToADirectionBuilder(); if (atozDirection != null) { List atozList = atozDirection.getAToZ(); List ztoaList = new ArrayList(); if (!atozList.isEmpty()) { List reverse = Lists.reverse(atozList); /** Building path. */ ZToAKey ztoaKey = null; Resource resource = null; org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription .rev170426.pce.resource.resource.Resource resLink = null; ZToA hop = null; int odr = 0; for (AToZ atoz : reverse) { ztoaKey = new ZToAKey(Integer.toString(odr)); resLink = atoz.getResource().getResource(); if (resLink != null) { if (resLink instanceof Link) { Link link = (Link) resLink; String newLinkId = reverseLinkId(link.getLinkIdentifier().getLinkId()); if (newLinkId != null) { resource = new ResourceBuilder().setResource(new LinkBuilder() .setLinkIdentifier(new LinkIdentifierBuilder() .setLinkId(newLinkId) .build()) .build()) .build(); } } else { resource = new ResourceBuilder().setResource(resLink).build(); } } if (resource != null) { hop = new ZToABuilder() .withKey(ztoaKey) .setResource(resource) .build(); ztoaList.add(hop); odr++; } else { LOG.info("resource is null "); } } if (!ztoaList.isEmpty()) { ztoaDirection.setRate((long) 100).setZToAWavelengthNumber((long) 200).setZToA(ztoaList); } else { LOG.info("ztoaList is empty !"); } } } return ztoaDirection.build(); } /** *build Pathdescritions ordered List *to be loaded in Pathdescriptions *datastore. * * @param atozDirection AToZdirection List * @param term direct ou indirect * @return PathDescriptionsOrdered List */ private SortedSet buildPathDescription(List atozDirection, String term) { SortedSet result = new TreeSet(); PathDescriptionsBuilder pathDescr = new PathDescriptionsBuilder(); int size = atozDirection.size(); if (!atozDirection.isEmpty()) { LOG.info("result list AToZDirection size : {}", atozDirection.size()); List ztoadirList = new ArrayList(); for (AToZDirection atozdir : atozDirection) { ZToADirection ztodir = convertToZtoaDirection(atozdir); if (ztodir != null) { ztoadirList.add(ztodir); } } if (!ztoadirList.isEmpty() && (size == ztoadirList.size())) { LOG.info("building PathDescriptions ..."); int index = 1; String pathName = null; for (int indexPath = 0 ; indexPath < size ; indexPath++) { pathName = term.concat(Integer.toString(index)); LOG.info("pathName : {}", pathName); pathDescr.setAToZDirection(atozDirection.get(indexPath)) .setZToADirection(ztoadirList.get(indexPath)).setPathName(pathName); LOG.info("pathdesciption : {}", pathDescr.build().toString()); result.add(new PathDescriptionsOrdered(pathDescr.build(),index)); index++; } } else { LOG.info("Something wrong happen during atodir conversion..."); } } else { LOG.info("atozDirection is empty"); } return result; } /** * gets link extremity. * * @param link link * @return Supernode List of extremities */ public List getSuperNodeEndLink(String link) { List result = new ArrayList(); if (link != null) { String [] split = link.split("-"); if (split.length == 4) { String aend = split[0].replaceAll("ROADM", "Node"); String zend = split[2].replaceAll("ROADM", "Node"); if ((aend != null) && (zend != null)) { LOG.info("getting super node for : {} and {}", aend, zend); SuperNode aendSp = getSuperNode(aend); SuperNode zendSp = getSuperNode(zend); if ((aendSp != null) && (zendSp != null)) { result.add(aendSp); result.add(zendSp); } } } } return result; } /** * build all direct paths. * * @param aend beginning extremity path * @param zend ending extremity path * @param nodeLinkNodes list paths * @return PathDescriptionsOrdered List of direct paths */ public SortedSet getDirectPathDesc(String aend, String zend, List nodeLinkNodes) { List atozdirectionPaths = new ArrayList(); SortedSet result = new TreeSet(); SuperNode aendSp = getSuperNode(aend); SuperNode zendSp = getSuperNode(zend); if (!nodeLinkNodes.isEmpty()) { for (NodeLinkNode tmp : nodeLinkNodes) { if (tmp.getDirect()) { LOG.info("Direct NodeLinkNode : {}", tmp.toString()); String atozLink = null; String ztoaLink = null; atozLink = tmp.getAtozLink().get(0); ztoaLink = tmp.getZtoaLink().get(0); if ((atozLink != null) && (ztoaLink != null)) { LOG.info("atozlink : {}", atozLink); LOG.info("ztoalink : {}", ztoaLink); InterNodePath interAend = new InterNodePath(aendSp); interAend.buildPath(zend); InterNodePath interZend = new InterNodePath(zendSp); interZend.buildPath(zend); List deg = getDeg(atozLink,ztoaLink); LOG.info("deg : {}", deg.toString()); if (deg.size() == 2) { List cleanInterA = interAend.replaceOrRemoveAToZDirectionEndLink(deg.get(0),"",atozLink, interAend.getAtoz(),false); List cleanInterZ = interZend.replaceOrRemoveAToZDirectionEndLink("TAIL-LINKS",deg.get(1),"", interZend.getAtoz(),true); if (!cleanInterA.isEmpty() && !cleanInterZ.isEmpty()) { atozdirectionPaths.addAll(merge(cleanInterA,cleanInterZ,false)); } else { LOG.info("cleanInterA ad/or cleanInterZ is empty !"); } } else { LOG.info("deg size is not correct, must be 2 ! "); } } else { LOG.info("atozlink and / or ztoalink is null"); } } } } else { LOG.info("List of direct path is empty !"); } if (!atozdirectionPaths.isEmpty()) { LOG.info("result size : {}", result.size()); result = buildPathDescription(atozdirectionPaths,aend.concat("To").concat(zend).concat("_direct_")); } else { LOG.info("result is empty"); } return result; } /** * build all indirect paths. * * @param aend beginning extremity path * @param zend ending extremity path * @param nodeLinkNodes list paths * @return PathDescriptionsOrdered List of indirect paths */ public SortedSet getIndirectPathDesc(String aend, String zend, List nodeLinkNodes) { List atozdirectionPaths = new ArrayList(); SortedSet result = new TreeSet(); SuperNode aendSp = getSuperNode(aend); SuperNode zendSp = getSuperNode(zend); if (!nodeLinkNodes.isEmpty()) { for (NodeLinkNode tmp : nodeLinkNodes) { if (!tmp.getDirect()) { LOG.info("Indirect NodeLinkNode : {}", tmp.toString()); int size = tmp.getAtozLink().size(); /** must be two for now just one hop. */ LOG.info("number of links : {}", size); boolean first = true; if (size == 2) { List atozLinks = tmp.getAtozLink(); List ztoaLinks = tmp.getZtoaLink(); if (!atozLinks.isEmpty() && !ztoaLinks.isEmpty()) { LOG.info("atozlink : {}", atozLinks.toString()); LOG.info("ztoalink : {}", ztoaLinks.toString()); int loop = 0; while (loop < 2) { List hop = getSuperNodeEndLink(atozLinks.get(loop)); if (!hop.isEmpty() && (hop.size() == 2)) { aendSp = hop.get(0); zendSp = hop.get(1); InterNodePath interAend = new InterNodePath(aendSp); interAend.buildPath(zend); LOG.info("interAend : {}", interAend.getAtoz().toString()); InterNodePath interZend = new InterNodePath(zendSp); interZend.buildPath(zend); LOG.info("interZend : {}", interZend.getAtoz().toString()); List deg1 = getDeg(atozLinks.get(loop),ztoaLinks.get(loop)); LOG.info("deg1 : {}", deg1.toString()); if (!deg1.isEmpty() && (deg1.size() == 2)) { List cleanInterA = null; List cleanInterZ = null; if (zendSp.getSuperNodeId().compareTo(zend) == 0) { cleanInterA = interAend.replaceOrRemoveAToZDirectionEndLink(deg1.get(0), "",atozLinks.get(loop),interAend.getAtoz(),false); LOG.info("next hop is zend"); cleanInterZ = interZend.replaceOrRemoveAToZDirectionEndLink("TAIL-LINKS", deg1.get(1),"",interZend.getAtoz(),true); } else if (loop < 1) { cleanInterA = interAend.replaceOrRemoveAToZDirectionEndLink(deg1.get(0), "",atozLinks.get(loop),interAend.getAtoz(),false); cleanInterZ = interZend.getAToZDirectionEndBy(deg1.get(1), interZend.getAtoz(), 1); } if (!cleanInterA.isEmpty() && !cleanInterZ.isEmpty()) { atozdirectionPaths = merge(atozdirectionPaths,cleanInterA,first); atozdirectionPaths = merge(atozdirectionPaths, cleanInterZ,false); first = false; } else { LOG.info("cleanInterA ad/or cleanInterZ is empty !"); break; } } } else { LOG.info("Hop list is empty"); } loop++; } } } else { LOG.info("Link size is not supported , must be two !"); } } } } else { LOG.info("List of indirect path is empty !"); } if (!atozdirectionPaths.isEmpty()) { LOG.info("result size : {}", result.size()); result = buildPathDescription(atozdirectionPaths,aend.concat("To").concat(zend).concat("_indirect_")); } else { LOG.info("result is empty"); } return result; } public static void main(String[] args) { Topology topo = new Topology(); topo.start(); SuperNodePath path = new SuperNodePath(topo.getNetwork()); String aend = "NodeA"; String zend = "NodeZ"; path.run(aend, zend); path.getDirectPathDesc(aend, zend, path.getPaths()); path.getIndirectPathDesc(aend, zend, path.getPaths()); } public List getPaths() { return this.paths; } public void setPaths(List paths) { this.paths = paths; } }