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

org.coos.messaging.routing.SimpleDVAlgorithm Maven / Gradle / Ivy

The newest version!
/**
 * COOS - Connected Objects Operating System (www.connectedobjects.org).
 *
 * Copyright (C) 2009 Telenor ASA and Tellu AS. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * 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 program 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 .
 *
 * You may also contact one of the following for additional information:
 * Telenor ASA, Snaroyveien 30, N-1331 Fornebu, Norway (www.telenor.no)
 * Tellu AS, Hagalokkveien 13, N-1383 Asker, Norway (www.tellu.no)
 */
package org.coos.messaging.routing;

import org.coos.messaging.Link;
import org.coos.messaging.Message;
import org.coos.messaging.impl.DefaultMessage;
import org.coos.messaging.util.UuidHelper;

import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Timer;
import java.util.TimerTask;
import java.util.Vector;


public class SimpleDVAlgorithm extends DefaultRoutingAlgorithm implements HashMapCallback {

    public static final String ALG_NAME = "simpledv";
    public static final String REFRESH_INTERVAL = "refreshInterval";
    public static final String AGING_FACTOR = "agingFactor";

    private Timer timer;
    private int refreshInterval = 100; // Default value
    private int agingFactor = 5; // Default value

    public SimpleDVAlgorithm() {
    }

    public SimpleDVAlgorithm(Router router, String routerUuid) {
        init(routerUuid, router);
    }

    @Override public void init(String routerUuid, Router router) {

        // Setting the refreshinterval property
        String refIntvStr = properties.get(REFRESH_INTERVAL);

        if (refIntvStr != null) {
            refreshInterval = Integer.parseInt(refIntvStr);
        }

        //Setting the aging factor property
        String agefactStr = properties.get(AGING_FACTOR);

        if (agefactStr != null) {
            agingFactor = Integer.parseInt(agefactStr);
        }

        super.init(routerUuid, router);

    }

    @SuppressWarnings("unchecked")
    public void processRoutingInfo(Message routingInfo) {

        Vector linkCosts = (Vector) routingInfo.getBody();
        String s = "";

        for (Map routingTable : routingTables.values()) {

            for (int i = 0; i < linkCosts.size(); i++) {
                LinkCost linkCost = (LinkCost) linkCosts.elementAt(i);
                s += linkCost.getFromUuid() + "<->" + linkCost.getToUuid() + ": " +
                    linkCost.getCost(Link.DEFAULT_QOS_CLASS) + ": " + linkCost.getAliases() + ", ";

                if (routingInfo.getMessageContext().getInBoundChannel() != null) {

                    //It is remote routingInfo
                    String toUuid = linkCost.getToUuid();
                    Link link = routingInfo.getMessageContext().getInBoundChannel().getOutLink();

                    if (linkCost.getCost(Link.DEFAULT_QOS_CLASS) < LinkCost.MAX_VALUE) {
                        ((TimedConcurrentHashMap) routingTable).put(toUuid, link,
                            agingFactor * refreshInterval, this);

                        List aliases = linkCost.getAliases();

                        for (String alias : aliases) {
                            router.putAlias(alias, toUuid);
                        }
                    }
                } else {

                    //It is local routingInfo
                    String toUuid = linkCost.getToUuid();
                    Link link = links.get(linkCost.getLinkId());

                    if ((linkCost.getCost(Link.DEFAULT_QOS_CLASS) < LinkCost.MAX_VALUE) &&
                            (link != null)) {
                        ((TimedConcurrentHashMap) routingTable).put(toUuid, link,
                            agingFactor * refreshInterval, this);

                        List aliases = linkCost.getAliases();

                        for (String alias : aliases) {
                            router.putAlias(alias, toUuid);
                        }
                    }
                }
            }
        }

        logger.trace("Receiving on " + router.getCOOSInstanceName() + ", from " +
            routingInfo.getSenderEndpointUri() + " linkinfo: " + s);

        if (loggingEnabled) {

            for (String qos : routingTables.keySet()) {
                printRoutingTable(routerUuid, qos, routingTables.get(qos), logger);
            }

            printAliasTable(routerUuid, aliasTable, logger);
        }
    }

    @SuppressWarnings("unchecked")
    public void publishLink(Link link) {

        //from the local node
        List links = new LinkedList();
        links.add(link);

        Iterator iter = routingTables.keySet().iterator();

        while (iter.hasNext()) {
            String qos = iter.next();
            TimedConcurrentHashMap routingTable = routingTables.get(qos);

            if (link.getCost() < LinkCost.MAX_VALUE) {
                routingTable.put(link.getDestinationUuid(), link, agingFactor * refreshInterval,
                    this);

                //This approach by broadcasting every new connection results in more traffic than
                //handling it on a scheduled basis. However, it might not be a problem.
                //In case of very fast reconnection with same UUID it may be a problem with 
                //the strategy of broadcast for every link that is added. The new link will be added before
                //the old is removed and hence a problem may occur.
                //broadcastRoutingInfo(routingTable);
            }


        }

    }

    private void broadcastRoutingInfo(Map routingTable) {

        try {
            String s = "";

            for (Link link : routingTable.values()) {
                s += link.getDestinationUuid() + ": " + link.getAlises() + ", ";
            }

            // Send routinginfo to all router elements in routing table

            Set uuids = new HashSet();
            // Get routing table entries for all qos parameters


            for (Link link : routingTable.values()) {

                if ((link.getChannel() != null) && !link.getChannel().isReceiveRoutingInfo()) {
                    continue;
                }

                uuids.add(link.getDestinationUuid());
            }

            for (String uuid : uuids) {

                // Only sending routerinfo to neighbour routers
                if (UuidHelper.getSegmentFromEndpointNameOrEndpointUuid(uuid).equals(segment) &&
                        UuidHelper.isRouterUuid(uuid)) {
                    sendRouterInfo(uuid, constructRoutingInfo(uuid, routingTable));
                    logger.trace("RouterInfo from: " + router.getCOOSInstanceName() + ", to:" +
                        uuid + ":: " + s);
                }
            }

            // Send info to self
            sendRouterInfo(routerUuid, constructLocalRoutingInfo(links.values()));
        } catch (Exception e) {
            logger.error("Exception ignored.", e);
        }
    }

    @SuppressWarnings("unchecked")
    private Vector constructRoutingInfo(String receivingRouterUuid,
        Map routingTable) {
        Vector routingInfo = new Vector();

        for (String uuid : routingTable.keySet()) {
            Link link = routingTable.get(uuid);
            String uuidSegment = UuidHelper.getSegmentFromSegmentOrEndpointUuid(uuid);

            Vector broadCastAliases = new Vector();
            Map aliasTable = router.getAliasTable();

            for (String alias1 : aliasTable.keySet()) {
                String uuid1 = aliasTable.get(alias1);

                //Do not propagate localcoos aliases to other coos nodes
                if (!alias1.startsWith(Router.LOCAL_SEGMENT) && uuid.equals(uuid1)) {
                    broadCastAliases.add(alias1);
                }

            }

            if (uuidSegment.equals(segment) && !UuidHelper.isSegment(uuid) &&
                    !link.equals(routingTable.get(receivingRouterUuid))) {

                //The endpoints belonging to the router in the segment except from localcoos
                routingInfo.addElement(new LinkCost(routerUuid, uuid, link.getLinkId(),
                        link.getCostMap(), broadCastAliases));
            } else if (UuidHelper.isSegment(uuid) && !uuidSegment.equals(segment) &&
                    UuidHelper.isInParentChildRelation(uuidSegment,
                        UuidHelper.getSegmentFromSegmentOrEndpointUuid(receivingRouterUuid))) {

                //Other segments
                routingInfo.addElement(new LinkCost(routerUuid, uuid, link.getLinkId(),
                        link.getCostMap(), link.getAlises()));
            }
        }

        routingInfo.addElement(new LinkCost(routerUuid, routerUuid, null,
                new HashMap(), new Vector()));

        return routingInfo;
    }

    @SuppressWarnings("unchecked")
    private Vector constructLocalRoutingInfo(Collection links) {
        Vector routingInfoLocal = new Vector();

        for (Link link : links) {
            String uuid = link.getDestinationUuid();
            String uuidSegment = UuidHelper.getSegmentFromSegmentOrEndpointUuid(uuid);

            if (uuidSegment.equals(segment) && !UuidHelper.isSegment(uuid)) {
                routingInfoLocal.addElement(new LinkCost(routerUuid, uuid, link.getLinkId(),
                        link.getCostMap(), link.getAlises()));
            } else if (UuidHelper.isSegment(uuid) && !uuidSegment.equals(segment)) {
                // Aliases are not part of cross segment linkcost to gateway
                // (local) topology map.

                // Aliases in cross segment linkcosts pointing at other
                // segment must not be added since this is where dico
                // aliases pointing
                // to uuids in own segment is located
                routingInfoLocal.addElement(new LinkCost(routerUuid, uuid, link.getLinkId(),
                        link.getCostMap(), null));
            }
        }

        return routingInfoLocal;
    }

    private void sendRouterInfo(String uuid, Vector routingInfo) {

        try {
            DefaultMessage msg = new DefaultMessage();
            msg.setReceiverEndpointUri("coos://" + uuid);
            msg.setSenderEndpointUri("coos://" + routerUuid);
            msg.setHeader(Message.SERIALIZATION_METHOD, Message.SERIALIZATION_METHOD_JAVA);
            msg.setHeader(Message.TYPE, Message.TYPE_ROUTING_INFO);
            msg.setBody(routingInfo);
            router.processMessage(msg);
        } catch (Exception e) {
            logger.error("Exception ignored.", e);
        }

    }

    private void broadcastRoutingInfoAndSchedule() {


        broadcastRoutingInfo(routingTables.get(Link.DEFAULT_QOS_CLASS));

        try {
            timer.schedule(new TimerTask() {

                    @Override public void run() {
                        broadcastRoutingInfoAndSchedule();
                    }
                }, refreshInterval);
        } catch (IllegalStateException e) {
            // Nothing to be done. This situation occures when the timer is
            // cancelled in the stop routine
            // and the broadcastRoutingInfoAndSchedule is started. I.e. the
            // routing algorithm is about to stop.
        }
    }


    public void start() {
        timer = new Timer("SimpleDVTimer", true);
        broadcastRoutingInfoAndSchedule();
    }

    public void stop() throws Exception {

        if (timer != null) {
            timer.cancel();
        }

    }

    public boolean remove(Object key, TimedConcurrentHashMap routingTable) {
        Link link = (Link) routingTable.get(key);

        if ((link != null) && (link.getChannel() != null) && link.getChannel().isDefaultGw() &&
                link.getDestinationUuid().equals(key)) {
            return false;
        }

        for (String alias : aliasTable.keySet()) {

            if (aliasTable.get(alias).equals(key)) {
                aliasTable.remove(alias);
            }
        }

        return true;
    }

    public String getAlgorithmName() {
        return ALG_NAME;
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy