/* * Copyright 2016 christopher.metter. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package de.uniwuerzburg.info3.ofcprobe.vswitch.graphml; import java.io.FileWriter; import java.io.IOException; import java.io.Writer; import java.text.DecimalFormat; import java.text.NumberFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Iterator; import java.util.List; import java.util.Scanner; import org.jdom2.Attribute; import org.jdom2.Document; import org.jdom2.Element; import org.jdom2.JDOMException; import org.jdom2.Namespace; import org.jdom2.input.SAXBuilder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * GraphMLparser * * @author christian rachor */ public class GraphmlParser { private static final Logger logger = LoggerFactory.getLogger(GraphmlParser.class); private ArrayList<Node> nodelist = new ArrayList<>(); private ArrayList<Edge> edgelist = new ArrayList<>(); private int[] edgesST; private Namespace ns; private Element graph; private String latitude_key = ""; private String country_key = ""; private String id_key = ""; private String longitude_key = ""; private String label_key = ""; private String linklabel_key = ""; private String internal_key = ""; /** * Constructor * * @param graphml_filename the GraphML Filenam */ public GraphmlParser(String graphml_filename) { try { Document doc = new SAXBuilder().build(graphml_filename); Element graphml = doc.getRootElement(); this.ns = graphml.getNamespace(); this.graph = graphml.getChild("graph", this.ns); List<Element> list = graphml.getChildren("key", ns); for (Element e : list) { String s = e.getAttributeValue("attr.name"); switch (s) { case "Latitude": latitude_key = e.getAttributeValue("id"); break; case "Country": country_key = e.getAttributeValue("id"); break; case "Internal": internal_key = e.getAttributeValue("id"); break; case "id": if (e.getAttributeValue("for").equals("node")) { id_key = e.getAttributeValue("id"); } break; case "Longitude": longitude_key = e.getAttributeValue("id"); break; case "label": if (e.getAttributeValue("for").equals("node")) { label_key = e.getAttributeValue("id"); } break; case "LinkLabel": linklabel_key = e.getAttributeValue("id"); break; default: break; } } } catch (JDOMException | IOException e) { logger.error("Error in GraphmlParser"); System.exit(-1); } } /** * finds Element in List by Key * * @param list the List * @param key the Key * @return the Element */ private Element findElementById(List<Element> list, String key) { for (Element e : list) { if (e.getAttributeValue("key").equals(key)) { return e; } } return null; } /** * Finds Node by Coordinates * * @param list the List * @param longitude the Longitude Coordinate * @param latitude the Latitude Coordinate * @return the Node */ private Node findNodeByCoords(ArrayList<Node> list, double longitude, double latitude) { for (Node node : list) { if (Math.abs(node.getLongitude() - longitude) < 0.1 && Math.abs(node.getLatitude() - latitude) < 0.1) { return node; } } return null; } /** * Finds an Edge between source- and targetNode * * @param list the list * @param sourcenode the source Node * @param targetnode the target Node * @return the Edge between the Nodes */ private Edge findEdge(ArrayList<Edge> list, Node sourcenode, Node targetnode) { for (Edge edge : list) { if ((edge.getSource().equals(sourcenode) && edge.getTarget().equals(targetnode)) || (edge.getSource().equals(targetnode) && edge.getTarget().equals(sourcenode))) { return edge; } } return null; } /** * Finds Edge between Source and Target Node, identified by NodeNumber * * @param list the list * @param source the source node number * @param target the target node number * @return the edge between source and target Node */ private Edge findEdge(ArrayList<Edge> list, int source, int target) { for (Edge edge : list) { if ((edge.getSource().getNumber() == source && edge.getTarget().getNumber() == target) || (edge.getSource().getNumber() == target && edge.getTarget().getNumber() == source)) { return edge; } } return null; } /** * Parses Nodes */ public void readNodes() { List<Element> nodeelemlist = this.graph.getChildren("node", this.ns); int number = 1; for (Element e : nodeelemlist) { Element latitude_elem = findElementById(e.getChildren(), latitude_key); double latitude = (latitude_elem == null) ? 0 : Double.parseDouble(latitude_elem.getText()); Element longitude_elem = findElementById(e.getChildren(), longitude_key); double longitude = (longitude_elem == null) ? 0 : Double.parseDouble(longitude_elem.getText()); if (latitude == 0 || longitude == 0) { continue; } Element country_elem = findElementById(e.getChildren(), country_key); String country = (country_elem == null) ? "" : country_elem.getText(); Element city_elem = findElementById(e.getChildren(), label_key); String city = (city_elem == null) ? "" : city_elem.getText(); Element id_elem = findElementById(e.getChildren(), id_key); int id = Integer.parseInt(id_elem.getText()); Node n = findNodeByCoords(nodelist, longitude, latitude); if (n != null) { n.addId(id); } else { Node node = new Node(number, city, id, country, longitude, latitude); nodelist.add(node); number++; } } } /** * Parses Edges */ public void readEdges() { if (nodelist.isEmpty()) { logger.error("Read in Nodes first!"); System.exit(-1); } List<Element> edgeelemlist = this.graph.getChildren("edge", this.ns); for (Element e : edgeelemlist) { Attribute source_attr = e.getAttribute("source"); int source = Integer.parseInt(source_attr.getValue()); Attribute target_attr = e.getAttribute("target"); int target = Integer.parseInt(target_attr.getValue()); Element linkspeed_elem = findElementById(e.getChildren(), linklabel_key); double linkspeed = 0.0; if (linkspeed_elem != null) { Scanner scanner = new Scanner(linkspeed_elem.getText()); while (!scanner.hasNextDouble() && scanner.hasNext()) { scanner.next(); } if (scanner.hasNextDouble()) { linkspeed = scanner.nextDouble(); } if (linkspeed_elem.getText().contains("Mbps")) { linkspeed *= 1E06; } if (linkspeed_elem.getText().contains("Gbps")) { linkspeed *= 1E09; } scanner.close(); } Node sourcenode = null; Node targetnode = null; for (Node n : this.nodelist) { if (n.getIds().contains(source)) { sourcenode = n; } if (n.getIds().contains(target)) { targetnode = n; } } if (sourcenode == null || targetnode == null || sourcenode == targetnode || findEdge(edgelist, sourcenode, targetnode) != null) { continue; } Edge edge = new Edge(sourcenode, targetnode, linkspeed); this.edgelist.add(edge); } } /** * Creates Routing Table for Startnode using Dijkstra Algorithm * * @param startnode Startnode * @return Maximum Distance between Startnode and possible TargetNode */ public int Dijkstra(Node startnode) { int[] distance = new int[nodelist.size()]; int[] predecessor = new int[nodelist.size()]; ArrayList<Node> q = new ArrayList<>(); initializeDijkstra(startnode, distance, predecessor, q); while (!q.isEmpty()) { Node u = q.get(0); for (Node node : q) { if (distance[node.getNumber() - 1] < distance[u.getNumber() - 1]) { u = node; } } q.remove(u); for (Edge e : edgelist) { if (e.getSource().getNumber() == u.getNumber()) { Node v = e.getTarget(); if (q.contains(v)) { distance_update(u, v, distance, predecessor); } } else if (e.getTarget().getNumber() == u.getNumber()) { Node v = e.getSource(); if (q.contains(v)) { distance_update(u, v, distance, predecessor); } } } } int maxD = distance[0]; for (int i = 0; i < distance.length; i++) { if (distance[i] > maxD) { maxD = distance[i]; } } edgesST = Arrays.copyOf(predecessor, predecessor.length); return maxD; } /** * Updates the Distance between two Nodes * * @param u * @param v * @param distance * @param predecessor */ private void distance_update(Node u, Node v, int[] distance, int[] predecessor) { int alt = distance[u.getNumber() - 1] + 1; if (alt < distance[v.getNumber() - 1]) { distance[v.getNumber() - 1] = alt; predecessor[v.getNumber() - 1] = u.getNumber(); } } /** * * @param startnode * @param distance * @param predecessor * @param q */ private void initializeDijkstra(Node startnode, int[] distance, int[] predecessor, ArrayList<Node> q) { for (Node node : nodelist) { distance[node.getNumber() - 1] = Integer.MAX_VALUE; predecessor[node.getNumber() - 1] = -1; q.add(node); } distance[startnode.getNumber() - 1] = 0; } /** * Writes Parsed GraphML file to OFCProbe compatible Topology.ini File * Overwrites (possibly) existing File without asking */ public void writeToTopologyFile() { if (nodelist.isEmpty() || edgelist.isEmpty()) { logger.error("No nodes or edges provided."); System.exit(-1); } int distance = Integer.MAX_VALUE; Node startnode = null; for (Node node : nodelist) { if (Dijkstra(node) <= distance) { distance = Dijkstra(node); startnode = node; } } Dijkstra(startnode); Iterator<Edge> iter = edgelist.iterator(); while (iter.hasNext()) { Edge edge = iter.next(); if ((edge.getTarget().getNumber() == edgesST[edge.getSource().getNumber() - 1]) || (edge.getSource().getNumber() == edgesST[edge.getTarget().getNumber() - 1])) { continue; } iter.remove(); } int[] ports = new int[nodelist.size()]; for (int i = 0; i < ports.length; i++) { ports[i] = 1; } Writer fw = null; try { fw = new FileWriter("topology.ini"); fw.write("###Topology"); fw.append(System.getProperty("line.separator")); fw.write("#ofSwitch:Port==ofSwitch:Port"); fw.append(System.getProperty("line.separator")); for (Edge edge : edgelist) { fw.write(edge.getSource().getNumber() + ":" + (ports[edge.getSource().getNumber() - 1]++) + "==" + edge.getTarget().getNumber() + ":" + (ports[edge.getTarget().getNumber() - 1]++)); fw.append(System.getProperty("line.separator")); } NumberFormat dpidFormatter = new DecimalFormat("#000"); for (int i = 0; i < nodelist.size(); i++) { String dpid = dpidFormatter.format(nodelist.get(i).getNumber()); logger.info("Switch#{} \"{}\" (Nodeid:{}) has {} connections", dpid, nodelist.get(i).getName(), nodelist.get(i).getIds(), (ports[i] - 1)); } } catch (IOException e) { logger.error("Exception during Creation of topology file"); } finally { if (fw != null) { try { fw.close(); logger.info("Writing Topology-File successful!"); } catch (IOException e) { logger.error(e.getLocalizedMessage()); } } } } /** * get the Node Count * * @return node Count */ public int getNodeCount() { return nodelist.size(); } }