CharafeddineMechalikh/PureEdgeSim

View on GitHub
PureEdgeSim/com/mechalikh/pureedgesim/datacentersmanager/DefaultTopologyCreator.java

Summary

Maintainability
A
3 hrs
Test Coverage
/**
 *     PureEdgeSim:  A Simulation Framework for Performance Evaluation of Cloud, Edge and Mist Computing Environments 
 *
 *     This file is part of PureEdgeSim Project.
 *
 *     PureEdgeSim is free software: you can redistribute it and/or modify
 *     it under the terms of the GNU General Public License as published by
 *     the Free Software Foundation, either version 3 of the License, or
 *     (at your option) any later version.
 *
 *     PureEdgeSim is distributed in the hope that it will be useful,
 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *     GNU General Public License for more details.
 *
 *     You should have received a copy of the GNU General Public License
 *     along with PureEdgeSim. If not, see <http://www.gnu.org/licenses/>.
 *     
 *     @author Charafeddine Mechalikh
 **/
package com.mechalikh.pureedgesim.datacentersmanager;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream; 

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import com.mechalikh.pureedgesim.datacentersmanager.ComputingNode.LinkOrientation;
import com.mechalikh.pureedgesim.network.InfrastructureGraph;
import com.mechalikh.pureedgesim.network.NetworkLink;
import com.mechalikh.pureedgesim.network.NetworkLink.NetworkLinkTypes;
import com.mechalikh.pureedgesim.network.NetworkLinkCellularDown;
import com.mechalikh.pureedgesim.network.NetworkLinkCellularUp;
import com.mechalikh.pureedgesim.network.NetworkLinkEthernet;
import com.mechalikh.pureedgesim.network.NetworkLinkMan;
import com.mechalikh.pureedgesim.network.NetworkLinkWanDown;
import com.mechalikh.pureedgesim.network.NetworkLinkWanUp;
import com.mechalikh.pureedgesim.network.NetworkLinkWifiDeviceToDevice;
import com.mechalikh.pureedgesim.network.NetworkLinkWifiDown;
import com.mechalikh.pureedgesim.network.NetworkLinkWifiUp;
import com.mechalikh.pureedgesim.scenariomanager.SimulationParameters;
import com.mechalikh.pureedgesim.simulationmanager.SimulationManager;


/**
 * A class that generates a default topology graph for the simulation. It reads
 * the topology information from an XML file and creates the corresponding
 * infrastructure graph.
 * 
 * @author Charafeddine Mechalikh
 * @since PureEdgeSim 5.0
 */
public class DefaultTopologyCreator extends TopologyCreator {

    /**
     * Creates a new DefaultTopologyCreator object with the specified simulation
     * manager and computing nodes generator.
     * 
     * @param simulationManager       the simulation manager
     * @param computingNodesGenerator the computing nodes generator
     */
    public DefaultTopologyCreator(SimulationManager simulationManager,
            ComputingNodesGenerator computingNodesGenerator) {
        super(simulationManager, computingNodesGenerator);
    }

    /**
     * Generates the topology graph by reading the topology information from an XML
     * file and creating the corresponding infrastructure graph.
     */
    @Override
    public void generateTopologyGraph() {
        // Create a WAN link to connect all the edge devices to the cloud data center
        ComputingNode wanNode = createWanLink();

        // Connect each edge device to the cloud data center using WAN link
        for (ComputingNode edgeDevice : computingNodesGenerator.getMistOnlyList()) {
            connect(edgeDevice, wanNode, NetworkLinkTypes.WAN);
        }

        // Generate the topology of edge data centers from an XML file
        generateTopologyFromXmlFile();

        // Connect one edge data center with the cloud data center using WAN link
        ComputingNode dc1 = getDataCenterByName("dc1");
        infrastructureTopology.addLink(new NetworkLinkWanUp(dc1, wanNode, simulationManager, NetworkLinkTypes.WAN));
        infrastructureTopology.addLink(new NetworkLinkWanDown(wanNode, dc1, simulationManager, NetworkLinkTypes.WAN));

        // Connect each edge device with the closest edge data center using LAN link
        double range = SimulationParameters.edgeDataCentersRange;
        for (ComputingNode edgeDevice : computingNodesGenerator.getMistOnlyList()) {
            ComputingNode closestDC = ComputingNode.NULL;
            double shortestDistance = Double.MAX_VALUE;
            for (ComputingNode edgeDC : computingNodesGenerator.getEdgeOnlyList()) {
                if (edgeDC.isPeripheral()) {
                    double distance = edgeDevice.getMobilityModel().distanceTo(edgeDC);
                    if (distance <= range && distance < shortestDistance) {
                        shortestDistance = distance;
                        closestDC = edgeDC;
                    }
                }
            }
            connect(edgeDevice, closestDC, NetworkLinkTypes.LAN);

            // Set the current link of the edge device to the closest edge data center
            edgeDevice.setCurrentLink(
                    new NetworkLinkWifiDeviceToDevice(edgeDevice, closestDC, simulationManager, NetworkLinkTypes.LAN),
                    LinkOrientation.DEVICE_TO_DEVICE);
        }

        // Save the shortest paths between all computing nodes
        infrastructureTopology.savePathsToMap(computingNodesGenerator.getEdgeAndCloudList());
    }

    /**
     * This function creates a WAN link between the cloud data center and the
     * infrastructure node.
     * 
     * @return the WAN node used for linking edge devices to the cloud.
     */
    protected ComputingNode createWanLink() {

        // To do so, first let's get the cloud data center.
        // If you have more than one data center, you will need to link them all
        ComputingNode cloud = computingNodesGenerator.getCloudOnlyList().get(0);

        // If we want all data to be sent over the same wan network.
        if (SimulationParameters.useOneSharedWanLink) {
            // We need to create another node to link with the cloud.
            ComputingNode metroRouter = new Router(simulationManager);

            // After that, we can link it with the cloud. We select type IGNORE to avoid
            // measuring energy consumption twice.
            NetworkLinkWanUp wanUp = new NetworkLinkWanUp(metroRouter, cloud, simulationManager,
                    NetworkLinkTypes.IGNORE);
            NetworkLinkWanDown wanDown = new NetworkLinkWanDown(cloud, metroRouter, simulationManager,
                    NetworkLinkTypes.IGNORE);
            infrastructureTopology.addLink(wanUp);
            infrastructureTopology.addLink(wanDown);

            // To enable the real time WAN chart, and use the WAN bandwidth in orchestration
            // algorithms like in Example 8:
            simulationManager.getNetworkModel().setWanLinks(wanUp, wanDown);
            return metroRouter;
        } else
            return cloud;

    }

    /**
     * Generates the network topology from the edge data centers file.
     */
    protected void generateTopologyFromXmlFile() {
        try (InputStream serversFile = new FileInputStream(SimulationParameters.edgeDataCentersFile)) {
            DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();

            // Disable access to external entities in XML parsing, by disallowing DocType
            // declaration
            dbFactory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
            DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
            Document doc = dBuilder.parse(serversFile);

            // Create the network topology
            NodeList networkLinks = doc.getElementsByTagName("link");
            for (int i = 0; i < networkLinks.getLength(); i++) {
                Element networkLink = (Element) networkLinks.item(i);
                createNetworkLink(networkLink);
            }
        } catch (ParserConfigurationException | SAXException | IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * Creates a network link between two data centers.
     *
     * @param networkLinkElement the XML element containing the network link
     *                           information. It should have "from" and "to" child
     *                           elements with the names of the data centers to
     *                           connect.
     */
    protected void createNetworkLink(Element networkLinkElement) {
        ComputingNode dcFrom = getDataCenterByName(
                networkLinkElement.getElementsByTagName("from").item(0).getTextContent());
        ComputingNode dcTo = getDataCenterByName(
                networkLinkElement.getElementsByTagName("to").item(0).getTextContent());
        // Connect the data centers with a MAN link in both directions
        infrastructureTopology.addLink(new NetworkLinkMan(dcFrom, dcTo, simulationManager, NetworkLinkTypes.MAN));
        infrastructureTopology.addLink(new NetworkLinkMan(dcTo, dcFrom, simulationManager, NetworkLinkTypes.MAN));
    }

    /**
     * Finds a data center in the list of edge data centers by name.
     *
     * @param name the name of the data center to find.
     * @return the data center with the given name, or ComputingNode.NULL if it was
     *         not found. Time complexity: O(n), where n is the number of edge data
     *         centers.
     */
    protected ComputingNode getDataCenterByName(String name) {
        for (ComputingNode dc : computingNodesGenerator.getEdgeOnlyList()) {
            if (dc.getName().equals(name)) {
                return dc;
            }
        }
        return ComputingNode.NULL;
    }

    /**
     * Connects two computing nodes with a network link of the specified type.
     *
     * @param computingNode1 the first computing node to connect
     * @param computingNode2 the second computing node to connect
     * @param type           the type of network link to create
     * @throws IllegalArgumentException if the connectivity type of either computing
     *                                  node is not wifi, ethernet, or cellular
     *                                  (case-sensitive)
     */
    protected void connect(ComputingNode computingNode1, ComputingNode computingNode2, NetworkLinkTypes type)
            throws IllegalArgumentException {
        NetworkLink up;
        NetworkLink down;

        // Determine the connectivity type of the first computing node
        String connectivityType = computingNode1.getEnergyModel().getConnectivityType();

        // Create the appropriate network link based on the connectivity type
        switch (connectivityType) {
        case "wifi":
            up = new NetworkLinkWifiUp(computingNode1, computingNode2, simulationManager, type);
            down = new NetworkLinkWifiDown(computingNode2, computingNode1, simulationManager, type);
            break;
        case "cellular":
            up = new NetworkLinkCellularUp(computingNode1, computingNode2, simulationManager, type);
            down = new NetworkLinkCellularDown(computingNode2, computingNode1, simulationManager, type);
            break;
        case "ethernet":
            up = new NetworkLinkEthernet(computingNode1, computingNode2, simulationManager, type);
            down = new NetworkLinkEthernet(computingNode2, computingNode1, simulationManager, type);
            break;
        default:
            throw new IllegalArgumentException(
                    getClass().getSimpleName() + " - Unknown connectivity type: " + connectivityType
                            + ". Available types for edge devices are: wifi, ethernet, and cellular (case sensitive)");
        }

        // Add the links to the topology
        infrastructureTopology.addLink(up);
        infrastructureTopology.addLink(down);

        // If this link is used to connect with the closest edge server, set the current
        // links of computingNode1
        if (type == NetworkLinkTypes.LAN) {
            computingNode1.setCurrentLink(up, LinkOrientation.UP_LINK);
            computingNode1.setCurrentLink(down, LinkOrientation.DOWN_LINK);
        }
    }

    /**
     * Returns the simulation manager responsible for running the simulation.
     *
     * @return the simulation manager
     */
    public SimulationManager getSimulationManager() {
        return simulationManager;
    }

    /**
     * Returns the topology of the infrastructure as an {@link InfrastructureGraph}
     * object.
     *
     * @return the infrastructure topology
     */
    public InfrastructureGraph getInfrastructureTopology() {
        return infrastructureTopology;
    }

}