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

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

/**
 * 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.Log;
import org.coos.messaging.util.UuidHelper;

import java.io.StringWriter;
import java.util.*;

/**
 * @author Knut Eilif Husa, Tellu AS
 * 
 */
public class LinkStateAlgorithm extends DefaultRoutingAlgorithm implements TopologyMapListener {

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

	private Random r = new Random();
	private TopologyMap topologyMap;
	private Timer timer;
	private int refreshInterval = 100; // Default value
	private int agingFactor = 10; // Default value

	public LinkStateAlgorithm() {
	}

	public LinkStateAlgorithm(Router router, String routerUuid) {
		init(routerUuid, router, new HashMap());
	}

	public void init(String routerUuid, Router router, Map properties) {

		// Setting the refreshinterval property
		String refIntvStr = (String) properties.get(REFRESH_INTERVAL);
		if (refIntvStr != null) {
			refreshInterval = Integer.parseInt(refIntvStr);
		}

		// Setting the ageing factor property
		String agefactStr = (String) properties.get(AGING_FACTOR);
		if (agefactStr != null) {
			agingFactor = Integer.parseInt(agefactStr);
		}

		topologyMap = new TopologyMap(routerUuid, refreshInterval, agingFactor * refreshInterval);
		topologyMap.addListener(this);
		topologyMap.start();
		super.init(routerUuid, router, properties);

	}

	public TopologyMap getTopologyMap() {
		return topologyMap;
	}

	public void setTopologyMap(TopologyMap topologyMap) {
		this.topologyMap = topologyMap;
	}

	public void publishLink(Link link) {
		List links = new LinkedList();
		links.add(link);
		broadcastRoutingInfo(links);
	}

	public synchronized void processRoutingInfo(Message routingInfo) {
		Vector linkCosts = (Vector) routingInfo.getBody();
		String s = "";
		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() + ", ";
		}
		logger.trace("Receiving on " + router.getCOOSInstanceName() + ", from " + routingInfo.getSenderEndpointUri()
				+ " linkinfo: " + s);
		topologyMap.update(linkCosts);
	}

	private void calculateOptimalPaths() {
		QoSClasses = router.getQoSClasses();
		for (String qos : QoSClasses) {
			calculateOptimalPaths(qos);
		}
	}

	void calculateOptimalPaths(String qos) {
		logger.debug(this.router.getCOOSInstanceName() + ": Calculating optimal paths for: "
				+ topologyMap.getRouterUuid());
		Map optimalPath = new HashMap();
		Set uuids = topologyMap.getNodeUuids();
		uuids.remove(topologyMap.getRouterUuid());
		// initialize optimal path with neighbours
		Iterator iter = uuids.iterator();
		while (iter.hasNext()) {
			String uuid = iter.next();
			optimalPath.put(uuid, new LinkCost(topologyMap.getLinkCost(uuid)));
		}

		while (!uuids.isEmpty()) {
			LinkCost minimalCost = null;
			iter = optimalPath.keySet().iterator();

			// identify node with smallest cost
			while (iter.hasNext()) {
				String uuid = iter.next();
				if (uuids.contains(uuid)) {
					if (minimalCost == null || (optimalPath.get(uuid)).getCost(qos) < minimalCost.getCost(qos)) {
						minimalCost = optimalPath.get(uuid);
					}
				}
			}

			String minimalCostUuid = minimalCost.getToUuid();
			uuids.remove(minimalCostUuid);

			iter = uuids.iterator();
			while (iter.hasNext()) {
				String nodeUuid = iter.next();

				if (topologyMap.isNeighbourNode(minimalCostUuid, nodeUuid)) {
					int candidateCost = minimalCost.getCost(qos)
							+ topologyMap.getLinkCost(minimalCostUuid, nodeUuid).getCost(qos);
					int currentCost;
					if (optimalPath.get(nodeUuid) != null) {
						currentCost = (optimalPath.get(nodeUuid)).getCost(qos);
					} else {
						currentCost = topologyMap.getLinkCost(nodeUuid).getCost(qos); // return
																						// large
																						// number
					}
					if (candidateCost < currentCost) {
						LinkCost linkCost = optimalPath.get(nodeUuid);
						linkCost.setCost(qos, candidateCost);
						linkCost.setNextLinkCost(optimalPath.get(minimalCostUuid));

					}
				}
			}
		}

		Iterator valIter = optimalPath.values().iterator();

		// populate routing table with smallest costs paths.
		while (valIter.hasNext()) {
			LinkCost linkCost = valIter.next();
			String toUuid = linkCost.getToUuid();
			while (linkCost.getNextLink() != null) {
				linkCost = linkCost.getNextLink();
			}
			// Now linkCost points to the link from the router

			if (linkCost.getCost(qos) < LinkCost.MAX_VALUE) {
				// insert Link into routing table
				Link l = links.get(linkCost.getLinkId());
				if (l != null) {
					routingTables.get(qos).put(toUuid, links.get(linkCost.getLinkId()));
					for (String alias : topologyMap.getAliases(toUuid)) {
						router.putAlias(alias, toUuid);
					}
				}
			} else {
				// remove Link from routing table
				routingTables.get(qos).remove(linkCost.getToUuid());
				links.remove(linkCost.getLinkId());
				for (String alias : topologyMap.getAliases(toUuid)) {
					router.removeAlias(alias);
				}
				if (loggingEnabled) {
					logger.debug(routerUuid + " removing from routerTable Link to: " + linkCost.getToUuid());
				}
			}
		}

		if (loggingEnabled) {
			printRoutingTable(routerUuid, qos, routingTables.get(qos), logger);
			printAliasTable(routerUuid, aliasTable, logger);
			printOptimalPath(routerUuid, qos, optimalPath, logger);
		}

	}

	private static synchronized void printOptimalPath(String routerUuid, String qos, Map optimalPath,
			Log logger) {
		StringWriter writer = new StringWriter();
		writer.write("-------------optimal paths for Qos: " + qos + " in router: " + routerUuid + "------------\n");
		Iterator keys = optimalPath.keySet().iterator();
		while (keys.hasNext()) {
			String uuid = keys.next();

			writer.write("'" + uuid + "': ");
			LinkCost linkCost = optimalPath.get(uuid);
			while (linkCost != null) {
				writer.write("'" + linkCost.getFromUuid() + "', '" + linkCost.getToUuid() + "': "
						+ linkCost.getCost(qos));
				linkCost = linkCost.getNextLink();
				if (linkCost != null) {
					writer.write(" --> ");
				}
			}
			writer.write("\n");
		}
		writer.write("-------------------------\n");

		logger.debug(writer.toString());

	}

	public void notifyChanged(TopologyMap topologyMap) {

		try {
			calculateOptimalPaths();
		} catch (Exception e) {
			logger.warn("Exception occured in " + topologyMap.getRouterUuid());
			e.printStackTrace();
		}
	}

	public void start() {
		timer = new Timer();
		broadcastRoutingInfoAndSchedule();
	}

	private void broadcastRoutingInfoAndSchedule() {
		broadcastRoutingInfo(links.values());
		try {
			timer.schedule(new TimerTask() {

				public void run() {
					broadcastRoutingInfoAndSchedule();
				}
			}, refreshInterval + r.nextInt((int) (0.1 * 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.
		}
	}

	private void broadcastRoutingInfo(Collection links) {
		try {
			String s = "";
			for (Link link : links) {
				s += link.getDestinationUuid() + ": " + link.getAlises() + ", ";
			}
			Vector routingInfo = new Vector();
			Vector routingInfoLocal = new Vector();

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

				if (uuidSegment.equals(segment) && !UuidHelper.isSegment(uuid)) {
					routingInfo.addElement(new LinkCost(routerUuid, uuid, link.getLinkId(), link.getCostMap(), link
							.getAlises()));
					routingInfoLocal.addElement(new LinkCost(routerUuid, uuid, link.getLinkId(), link.getCostMap(),
							link.getAlises()));
				} else if (UuidHelper.isSegment(uuid) && !uuidSegment.equals(segment)) {
					// 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
					routingInfo.addElement(new LinkCost(routerUuid, uuid, link.getLinkId(), link.getCostMap(), link
							.getAlises()));
					// Aliases are not part of cross segment linkcost to gateway
					// (local) topology map.
					routingInfoLocal.addElement(new LinkCost(routerUuid, uuid, link.getLinkId(), link.getCostMap(),
							null));
				}
			}

			// Send routinginfo to all router elements in routing table

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

			for (Map routingTable : routingTables.values()) {
				uuids.addAll(routingTable.keySet());
			}

			for (String uuid : uuids) {
				// Only sending routerinfo to routers
				if (UuidHelper.getSegment(uuid).equals(segment) && UuidHelper.isRouterUuid(uuid)) {
					sendRouterInfo(uuid, routingInfo);
					logger.trace("RouterInfo from: " + router.getCOOSInstanceName() + ", to:" + uuid + ":: " + s);
				}
			}

			// Send info to self
			sendRouterInfo(routerUuid, routingInfoLocal);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	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) {
			e.printStackTrace();
		}

	}

	public void stop() {
		topologyMap.stop();
		if (timer != null) {
			timer.cancel();
		}
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy