Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
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.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.Random;
import java.util.Set;
import java.util.Timer;
import java.util.TimerTask;
import java.util.Vector;
/**
* @author Knut Eilif Husa, Tellu AS
*
*/
public class LinkStateAlgorithm extends DefaultRoutingAlgorithm implements TopologyMapListener {
public static final String ALG_NAME = "linkstate";
public static final String REFRESH_INTERVAL = "refreshInterval";
public static final String AGING_FACTOR = "agingFactor";
public static final String EMPTY_SEG_FACTOR = "emptyDynamicSegmentFactor";
private final Random r = new Random();
private TopologyMap topologyMap;
private Timer timer;
private int refreshInterval = 100; // Default value
private int agingFactor = 5; // Default value
private long emptyDynamicSegmentFactor = 2 * agingFactor; // Default value
public LinkStateAlgorithm() {
}
public LinkStateAlgorithm(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);
}
// Setting the aging factor for the dynamic segment property
String emptySegfactStr = properties.get(EMPTY_SEG_FACTOR);
if (emptySegfactStr != null) {
emptyDynamicSegmentFactor = Integer.parseInt(emptySegfactStr);
}
topologyMap = new TopologyMap(routerUuid, refreshInterval, agingFactor * refreshInterval);
topologyMap.addListener(this);
topologyMap.start();
super.init(routerUuid, router);
}
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);
}
@SuppressWarnings("unchecked")
public synchronized void processRoutingInfo(Message routingInfo) {
Vector linkCosts = (Vector) routingInfo.getBody();
String s = "";
for (int i = 0; i < linkCosts.size(); i++) {
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() + " QoS: " + qos);
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
Link l = links.get(linkCost.getLinkId());
if (linkCost.getCost(qos) < LinkCost.MAX_VALUE) {
// insert Link into routing table
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(toUuid);
if ((l != null) && (l.getChannel() != null) && !l.getChannel().isDefaultGw()) {
//Never remove the default gateway
links.remove(linkCost.getLinkId());
if (loggingEnabled) {
logger.debug(routerUuid + " removing from routerTable Link to: " +
linkCost.getToUuid());
}
for (String alias : topologyMap.getAliases(toUuid)) {
router.removeAlias(alias);
}
}
}
}
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);
}
if (topologyMap.isEmpty() && router.getSegment(segment).isDynamicSegment()) {
RouterSegment rs = router.getSegment(segment);
long now = System.currentTimeMillis();
if (rs.getTimestamp() == 0) {
rs.setTimestamp(now);
} else if ((rs.getTimestamp() + (emptyDynamicSegmentFactor * refreshInterval)) > now) {
router.removeSegment(segment);
for (TimedConcurrentHashMap routingTable : routingTables.values()) {
routingTable.remove(segment);
}
stop();
logger.info("Removing dynamic segment: " + segment);
}
}
}
public void start() {
timer = new Timer("LinkStateThread", true);
broadcastRoutingInfoAndSchedule();
}
private void broadcastRoutingInfoAndSchedule() {
broadcastRoutingInfo(links.values());
try {
timer.schedule(new TimerTask() {
@Override 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() + ", ";
}
// 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()) {
for (String uuid : routingTable.keySet()) {
if ((routingTable.get(uuid).getChannel() != null) &&
!routingTable.get(uuid).getChannel().isReceiveRoutingInfo()) {
continue;
}
uuids.add(uuid);
}
}
/*for (Map routingTable : routingTables.values()) {
uuids.addAll(routingTable.keySet());
}*/
for (String uuid : uuids) {
// Only sending routerinfo to routers
if (UuidHelper.getSegmentFromEndpointNameOrEndpointUuid(uuid).equals(segment) &&
UuidHelper.isRouterUuid(uuid)) {
sendRouterInfo(uuid, constructRoutingInfo(uuid, links));
logger.trace("RouterInfo from: " + router.getCOOSInstanceName() + ", to:" +
uuid + ":: " + s);
}
}
// Send info to self
sendRouterInfo(routerUuid, constructLocalRoutingInfo(links));
} catch (Exception e) {
logger.error("Exception ignored.", e);
}
}
@SuppressWarnings("unchecked")
private Vector constructRoutingInfo(String receivingRouterUuid,
Collection links) {
Vector routingInfo = new Vector();
for (Link link : links) {
String uuid = link.getDestinationUuid();
String uuidSegment = UuidHelper.getSegmentFromSegmentOrEndpointUuid(uuid);
//Do not propagate localcoos aliases to other coos nodes
Vector aliases = link.getAlises();
Vector broadCastAliases = new Vector();
for (String alias : aliases) {
if (!alias.startsWith(Router.LOCAL_SEGMENT)) {
broadCastAliases.add(alias);
}
}
if (uuidSegment.equals(segment) && !UuidHelper.isSegment(uuid)) {
//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()));
}
}
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);
}
}
public void stop() {
topologyMap.stop();
if (timer != null) {
timer.cancel();
}
}
@Override public String getAlgorithmName() {
return ALG_NAME;
}
}