All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.btrplace.model.view.network.DefaultRouting Maven / Gradle / Ivy

/*
 * Copyright (c) 2016 University Nice Sophia Antipolis
 *
 * This file is part of btrplace.
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 3 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see .
 */

package org.btrplace.model.view.network;

import org.btrplace.model.Node;

import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;

/**
 * Default implementation of {@link Routing}.
 * Allows to retrieve physical path (L2) between network elements by looking at physical connections.
 *
 * If instantiated manually, it should be first attached to an existing network view,
 * see {@link #setNetwork(Network)}.
 *
 * @author Vincent Kherbache
 * @see #setNetwork(Network)
 */
public class DefaultRouting extends Routing {

    /**
     * Recursive method to get the first physical path found from a switch to a destination node
     *
     * @param   currentPath the current or initial path containing the link(s) crossed
     * @param   sw the current switch to browse
     * @param   dst the destination node to reach
     * @return  the ordered list of links that make the path to dst
     */
    private LinkedHashMap getFirstPhysicalPath(LinkedHashMap currentPath, Switch sw, Node dst) {

        // Iterate through the current switch's links
        for (Link l : net.getConnectedLinks(sw)) {
            // Wrong link
            if (currentPath.keySet().contains(l)) {
                continue;
            }

            /*
             * Go through the link and track the direction for full-duplex purpose
             * From switch to element => false : DownLink
             * From element to switch => true : UpLink
             */
            currentPath.put(l, !l.getSwitch().equals(sw));

            // Check what is after
            if (l.getElement() instanceof Node) {
                // Node found, path complete
                if (l.getElement().equals(dst)) {
                    return currentPath;
                }
            }
            else {
                // Go to the next switch
                LinkedHashMap  recall = getFirstPhysicalPath(
                        currentPath, l.getSwitch().equals(sw) ? (Switch) l.getElement() : l.getSwitch(), dst);
                // Return the complete path if found
                if (!recall.isEmpty()) {
                    return recall;
                }
            }
            // Wrong link, go back
            currentPath.remove(l);
        }
        // No path found through this switch
        return new LinkedHashMap<>();
    }

    @Override
    public List getPath(Node n1, Node n2) {
        if (net == null || n1.equals(n2)) {
            return Collections.emptyList();
        }

        // Initialize the cache
        if (routingCache == null) {
            int cacheSize = net.getConnectedNodes().size();
            routingCache = new LinkedHashMap[cacheSize][cacheSize]; // OK for the warning
        }

        // Fill the cache if needed
        if (routingCache[n1.id()][n2.id()] == null) {
            // Create an initial path from the node to its switch => true : UpLink
            LinkedHashMap initialPath = new LinkedHashMap<>();
            initialPath.put(net.getConnectedLinks(n1).get(0), true);
            // Get the first physical path found between the two nodes
            routingCache[n1.id()][n2.id()] =
                    getFirstPhysicalPath(
                            initialPath, // Only one link per node
                            net.getConnectedLinks(n1).get(0).getSwitch(), // A node is always connected to a switch
                            n2
                    );
        }

        return new ArrayList<>(routingCache[n1.id()][n2.id()].keySet());
    }

    @Override
    public LinkDirection getLinkDirection(Node n1, Node n2, Link l) {
        if (n1.equals(n2)) {
            return LinkDirection.NONE;
        }

        // Initialize the cache (should be already done)
        if (routingCache == null) {
            int cacheSize = net.getConnectedNodes().size();
            routingCache = new LinkedHashMap[cacheSize][cacheSize]; // OK for the warning
        }

        // Fill the appropriate cache entry from getPath method if needed
        if (routingCache[n1.id()][n2.id()] == null) {
            getPath(n1, n2);
        }

        // Link is not on route!
        if (!routingCache[n1.id()][n2.id()].containsKey(l)) {
            return LinkDirection.NONE;
        }

        // Return the direction if the given link in on path
        if (routingCache[n1.id()][n2.id()].containsKey(l)) {
            return routingCache[n1.id()][n2.id()].get(l) ?
                    LinkDirection.DOWNLINK : LinkDirection.UPLINK;
        }
        return LinkDirection.NONE;
    }

    @Override
    public Routing copy() {
        DefaultRouting clone = new DefaultRouting();
        clone.net = net; // Do not associate view->routing, only routing->view
        return clone;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy