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.
/**
* 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 java.util.Collection;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Map;
import java.util.Vector;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import org.coos.messaging.COOS;
import org.coos.messaging.ConnectingException;
import org.coos.messaging.Link;
import org.coos.messaging.Message;
import org.coos.messaging.Processor;
import org.coos.messaging.ProcessorException;
import org.coos.messaging.ProcessorInterruptException;
import org.coos.messaging.impl.DefaultProcessor;
import org.coos.messaging.util.Log;
import org.coos.messaging.util.LogFactory;
import org.coos.messaging.util.URIHelper;
import org.coos.messaging.util.UuidGenerator;
import org.coos.messaging.util.UuidHelper;
/**
* The DefaultRouter (actually default point to point router) contains the point
* to point routing mechanisms
*
* @author Knut Eilif Husa, Tellu AS
*/
public class DefaultRouter extends DefaultProcessor implements Router {
private Collection preProcessors = new ConcurrentLinkedQueue();
private Collection postProcessors = new ConcurrentLinkedQueue();
private Map routingTables = new ConcurrentHashMap();
private Map aliasTable = new ConcurrentHashMap();
// todo let the links be handled by the coos instance
private Map links = new ConcurrentHashMap();
private Map routingAlgorithms = new ConcurrentHashMap();
private Map segmentMapping = new ConcurrentHashMap();
// The uuid of the router in the different segments it participates in. If
// more than one uuid, this router is a gateway router
private Collection routerUuids = new ConcurrentLinkedQueue();
private Collection QoSClasses = new ConcurrentLinkedQueue();
private String defaultQoSClass;
private String COOSInstanceName;
private boolean running = false;
private boolean enabled = true;
private boolean loggingEnabled = false;
private Link defaultGw = null;
private final Log logger = LogFactory.getLog(this.getClass(), false);
private COOS COOS;
// This constructor is only used by tests
public DefaultRouter(String routerUuid) {
COOSInstanceName = routerUuid;
new LinkStateAlgorithm(this, routerUuid);
addQoSClass(Link.DEFAULT_QOS_CLASS, true);
addSegmentMapping(UuidHelper.getSegmentFromSegmentOrEndpointUuid(routerUuid), routerUuid, "linkstate");
}
public DefaultRouter() {
addQoSClass(Link.DEFAULT_QOS_CLASS, true);
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
public void removeRouterUuid(String routerUuid) {
routerUuids.remove(routerUuid);
}
public void setLoggingEnabled(boolean loggingEnabled) {
this.loggingEnabled = loggingEnabled;
for (RoutingAlgorithm routingAlgorithm : routingAlgorithms.values()) {
routingAlgorithm.setLoggingEnabled(loggingEnabled);
}
}
public void processMessage(Message msg) {
// Router preprocessors
for (RouterProcessor routerProcessor : preProcessors) {
try {
routerProcessor.processMessage(msg);
} catch (ProcessorInterruptException e) {
return;
} catch (ProcessorException e) {
e.printStackTrace();
}
}
if (msg.getReceiverEndpointUri() == null) {
logger.warn("Message from " + msg.getSenderEndpointUri() + " missing receiver address");
replyErrorReason(msg, Message.ERROR_NO_RECEIVER);
return;
}
String qosClass = msg.getHeader(Message.QOS_CLASS);
if (qosClass == null) {
qosClass = defaultQoSClass;
}
Map routingTable = routingTables.get(qosClass);
String hops = msg.getHeader(Message.HOPS);
if (hops == null) {
hops = "1";
} else {
hops = String.valueOf(Integer.parseInt(hops) + 1);
}
msg.setHeader(Message.HOPS, hops);
if (Integer.parseInt(hops) > 244) {
logger.warn("Message from " + msg.getSenderEndpointUri() + ", to: " + msg.getReceiverEndpointUri()
+ " too many hops");
replyErrorReason(msg, Message.ERROR_TOO_MANY_HOPS);
return;
}
String uuid = resolveAlias(msg);
if (uuid == null) {
// will never occur except for localcoos
replyErrorReason(msg, Message.ERROR_NO_ALIAS + ":" + msg.getReceiverEndpointUri());
return;
}
Link link;
// check if the message is destined towards this router
if (routerUuids.contains(uuid)) {
logger.putMDC(UUID_PREFIX, uuid);
if (msg.getType().equals(Message.TYPE_ROUTING_INFO)) {
routingAlgorithms.get(UuidHelper.getSegmentFromEndpointNameOrEndpointUuid(uuid))
.processRoutingInfo(msg);
} else if (msg.getType().equals(Message.TYPE_ALIAS)) {
try {
setLinkAliases((Vector) msg.getBody(), msg.getMessageContext().getInBoundChannel().getOutLink());
} catch (ProcessorException e) {
e.printStackTrace();
}
}
} else {
// The routing step
link = route(uuid, msg, routingTable);
if (link != null) {
msg.getMessageContext().setNextLink(link);
}
// Router postprocessors
for (RouterProcessor routerProcessor : postProcessors) {
try {
routerProcessor.processMessage(msg);
} catch (ProcessorInterruptException e) {
return;
} catch (ProcessorException e) {
e.printStackTrace();
}
}
// The sending step
if (link != null) {
if (msg.getHeader(Message.TRACE_ROUTE) != null) {
String trace = msg.getHeader(Message.TRACE);
if (trace == null) {
trace = COOSInstanceName;
}
msg.setHeader(Message.TRACE, trace + " -> " + link.getDestinationUuid());
}
try {
link.processMessage(msg);
} catch (ProcessorException e) {
replyErrorReason(msg, e.getMessage());
}
} else {
String errorMsg;
URIHelper helper = new URIHelper(msg.getReceiverEndpointUri());
String alias = helper.getEndpoint();
if (uuid.equals("null")) {
errorMsg = COOSInstanceName + ": No uuid for alias " + alias + ", No route from "
+ COOSInstanceName;
} else {
if (uuid.equals(alias)) {
errorMsg = COOSInstanceName + ": No route to: " + alias + " from " + COOSInstanceName;
} else {
errorMsg = COOSInstanceName + ": No route to: " + alias + " / " + uuid + " from "
+ COOSInstanceName;
}
}
logger.warn(errorMsg);
replyErrorReason(msg, Message.ERROR_NO_ROUTE);
}
}
}
/**
* This method does dynamic registers and unregisters aliases to link
*
* @param regAliases
* - An vector containing all aliases to be registered
* @param outlink
* - The link to register the aliases with. This link is always
* directed towards an endpoint
* @throws ProcessorException
*/
public void setLinkAliases(Vector regAliases, Link outlink) throws ProcessorException {
String segment = UuidHelper.getSegmentFromEndpointNameOrEndpointUuid(outlink.getDestinationUuid());
if (!segment.equals(".")) {
segment += ".";
}
// Qualify aliases
for (int i = 0; i < regAliases.size(); i++) {
String alias = (String) regAliases.get(i);
if (!alias.startsWith(Router.DICO_SEGMENT + ".")
&& !alias.startsWith(Router.LOCAL_SEGMENT + ".")
&& !alias.startsWith(segment)) {
// unqualified aliases are qualified by prefixing with segment
// name
String qualifiedAlias = segment + alias;
regAliases.remove(alias);
regAliases.add(qualifiedAlias);
}
}
Vector curAliases = outlink.getAlises();
Iterator itCurAliases = curAliases.iterator();
// remove aliases that are not present anymore
while (itCurAliases.hasNext()) {
String alias = (String) itCurAliases.next();
if (!regAliases.contains(alias)) {
itCurAliases.remove();
removeAlias(alias);
}
}
// Add all aliases
Iterator itRegAliases = regAliases.iterator();
while (itRegAliases.hasNext()) {
String alias = (String) itRegAliases.next();
outlink.addAlias(alias);
String oldToUuid = aliasTable.get(alias);
if (oldToUuid != null && !oldToUuid.equals(outlink.getDestinationUuid())) {
Iterator itRegAliases2 = regAliases.iterator();
while (itRegAliases2.hasNext()) {
removeAlias((String) itRegAliases2.next());
}
throw new ProcessorException("Can not register alias:" + alias
+ " since this alias is occupied for endpoint with uuid " + outlink.getDestinationUuid());
}
putAlias(alias, outlink.getDestinationUuid());
}
}
/**
* This method resolves receiver URIs into uuids. It handles both URIs
* containing aliases and uuids
*
* @param msg
* the message to resolve alias for
* @return the uuid
*/
public String resolveAlias(Message msg) {
URIHelper helper = new URIHelper(msg.getReceiverEndpointUri());
String uuid;
String alias;
alias = helper.getEndpoint();
String segment;
if (alias != null && !helper.isEndpointUuid()) {
// routing on alias
if (!helper.isEndpointQualified()) {
// To account for that not all messages arrives the router via an
// incoming link.
// I.e. the routingInfo from this router
if (msg.getMessageContext().getInBoundLink() != null
&& msg.getMessageContext().getInBoundLink().getDestinationUuid() != null) {
segment = UuidHelper.getSegmentFromEndpointNameOrEndpointUuid(msg.getMessageContext().getInBoundLink()
.getDestinationUuid());
} else {
segment = ".";
}
if (!segment.equals(".")) {
segment += ".";
}
// the alias is unqualified, first try to route in segment
// namespace
String qualifiedAlias = segment + alias;
uuid = aliasTable.get(qualifiedAlias);
if (uuid == null) {
// If not found in segment namespace, then try to route in
// dico namespace
qualifiedAlias = DICO_SEGMENT + "." + alias;
uuid = aliasTable.get(qualifiedAlias);
}
} else {
// If fully qualified alias then lookup in aliasTable
uuid = aliasTable.get(alias);
}
if (uuid == null
&& !helper.getSegment().equals(Router.LOCAL_SEGMENT)
&& !helper.getSegment().equals(Router.DICO_SEGMENT)) {
// we return with the segmented alias in order to allow for
// routing on segments
uuid = alias;
}
} else {
uuid = alias;
}
return uuid;
}
/**
* This is the core of the routing algorithm
*
*/
public Link route(String uuid, Message msg, Map routingTable) {
URIHelper helper = new URIHelper(msg.getSenderEndpointUri());
if (msg.getMessageContext().getInBoundChannel() != null) {
// Only populate routingtable with senderSegment/senderUuid if the
// message enters the router through an incoming channel
String destUuid = msg.getMessageContext().getInBoundLink().getDestinationUuid();
String curSegment = UuidHelper.getSegmentFromEndpointNameOrEndpointUuid(destUuid);
String senderEndpointUuid = helper.getEndpoint();
String senderSegment = UuidHelper.getSegmentFromEndpointNameOrEndpointUuid(senderEndpointUuid);
if (senderSegment.equals(curSegment)) {
// If senderEndpointUuid belongs to the same segment as the
// incoming channel
// populate routingtable with senderUuid
if (!routingTable.containsKey(senderEndpointUuid)) {
routingTable.put(senderEndpointUuid, msg.getMessageContext().getInBoundChannel().getOutLink());
}
} else {
// If senderEndpointUuid not belongs to the same segment as the
// incoming channel
// populate routingtable with segment of the senderUuid
if (!routingTable.containsKey(senderSegment)) {
routingTable.put(senderSegment, msg.getMessageContext().getInBoundChannel().getOutLink());
}
}
}
Link link = routingTable.get(uuid);
// route down
if (link == null) {
String toSegment = UuidHelper.getSegmentFromEndpointNameOrEndpointUuid(uuid);
Link inboundLink = msg.getMessageContext().getInBoundLink();
if (inboundLink == null) {
return null; // The message has not arrived this router through
// an inboundLink. It is invalid and can not be
// routed
}
String destUuid = inboundLink.getDestinationUuid();
if (destUuid == null) {
logger.warn(COOSInstanceName + ":destinationUuid is null on incoming link : "
+ inboundLink.getLinkId());
}
String curSegment = UuidHelper.getSegmentFromEndpointNameOrEndpointUuid(destUuid);
if (!toSegment.equals(curSegment)) {
// route down
while (!toSegment.equals("")) {
link = routingTable.get(toSegment);
if (link != null) {
break;
} else {
toSegment = UuidHelper.getParentSegment(toSegment);
}
}
// route up
/*if (link == null) {
if (curSegment != null) {
String parentSegment = UuidHelper.getParentSegment(curSegment);
if (parentSegment != null) {
link = routingTable.get(parentSegment);
}
}
}*/
}
}
// route along defaultGw if set. Must be different from the incoming link
if (link == null) {
if (defaultGw != null && defaultGw != msg.getMessageContext().getInBoundChannel().getOutLink()) {
link = defaultGw;
} else {
if (defaultGw == null) {
logger.warn("Defaultgw is not set!");
} else if (defaultGw == msg.getMessageContext().getInBoundChannel().getOutLink()) {
logger.warn("Incoming link is defaultgw!");
}
}
}
return link;
}
public void replyErrorReason(Message msg, String message) {
// Only send error indication on type msg. i.e. from an endpoint
if (msg.getHeader(Message.TYPE).equals(Message.TYPE_MSG)) {
msg.setReceiverEndpointUri(msg.getSenderEndpointUri());
msg.setHeader(Message.TYPE, Message.TYPE_ERROR);
msg.setHeader(Message.ERROR_REASON, message);
processMessage(msg);
}
}
public Processor getDefaultProcessor() {
return this;
}
/**
* Adding a link to the router. Can either be a link to an endpoint/router
* or a link to another segment
*
* @param routerUuid
* @param link
* @throws ConnectingException
*/
public void addLink(String routerUuid, Link link) throws ConnectingException {
if (UuidHelper.isUuid(routerUuid)) {
// It is a router or endpoint
String seg = UuidHelper.getSegmentFromEndpointNameOrEndpointUuid(routerUuid);
RoutingAlgorithm algorithm = routingAlgorithms.get(seg);
if (algorithm == null) {
throw new ConnectingException("Router is not attached to segment: " + seg);
}
RouterSegment rs = segmentMapping.get(seg);
rs.setTimestamp(0);
link.setDestinationUuid(routerUuid);
links.put(link.getLinkId(), link);
if (link.getChannel() != null && link.getChannel().isDefaultGw()) {
defaultGw = link;
logger.debug("Setting defaultgw " + link);
}
algorithm.publishLink(link);
} else {
// it is a segment
link.setDestinationUuid(routerUuid);
links.put(link.getLinkId(), link);
routingAlgorithms.get(routerUuid).publishLink(link);
}
logger.debug(getCOOSInstanceName() + ": Adding link: " + link);
}
public Link getLink(String destinationUuid) {
if (destinationUuid != null) {
for (Link link : links.values()) {
if (link.getDestinationUuid().equals(destinationUuid)) {
return link;
}
}
}
return null;
}
public void removeLinkById(String linkId) {
Link link = links.get(linkId);
if (link != null) {
link.setCost(LinkCost.MAX_VALUE);
// remove from routing table can be done here
for (Map routingTable : routingTables.values()) {
for (String key : routingTable.keySet()) {
Link l = routingTable.get(key);
if (l != null && l.equals((link))) {
routingTable.remove(key);
}
}
}
}
}
public void removeLink(String destinationUuid) {
for (Link link : links.values()) {
if (link.getDestinationUuid().equals(destinationUuid)) {
link.setCost(LinkCost.MAX_VALUE);
routingAlgorithms.get(UuidHelper.getSegmentFromEndpointNameOrEndpointUuid(destinationUuid))
.publishLink(link);
// remove from routing table can be done here
for (Map routingTable : routingTables.values()) {
for (String key : routingTable.keySet()) {
if (routingTable.get(key).equals((link))) {
routingTable.remove(key);
}
}
}
}
}
}
public void addQoSClass(String QoSClass, boolean isDefaultQoSClass) {
this.QoSClasses.add(QoSClass);
if (defaultQoSClass == null || isDefaultQoSClass) {
defaultQoSClass = QoSClass;
}
// create routing tables
if (routingTables.get(QoSClass) == null) {
routingTables.put(QoSClass, new ConcurrentHashMap());
}
}
public Collection getQoSClasses() {
return this.QoSClasses;
}
public void addPreProcessor(RouterProcessor preProcessor) {
preProcessor.setRouter(this);
preProcessors.add(preProcessor);
}
public void addPostProcessor(RouterProcessor postProcessor) {
postProcessor.setRouter(this);
postProcessors.add(postProcessor);
}
public String getCOOSInstanceName() {
return this.COOSInstanceName;
}
public void setCOOSInstanceName(String COOSInstanceName) {
this.COOSInstanceName = COOSInstanceName;
}
public void setCOOS(COOS coos) {
this.COOSInstanceName = coos.getName();
this.COOS = coos;
}
public COOS getCOOS() {
return COOS;
}
public void setSegmentMappings(Hashtable segmentMapping) {
this.segmentMapping = new ConcurrentHashMap(segmentMapping);
}
public void addSegmentMapping(String segment, String routerUUID, String routerAlgorithm) {
this.segmentMapping.put(segment, new RouterSegment(segment, routerUUID, routerAlgorithm, false));
}
public synchronized void addRoutingAlgorithm(String routerUuid, RoutingAlgorithm routingAlgorithm) {
if (!UuidHelper.isRouterUuid(routerUuid)) {
throw new IllegalArgumentException("Router uuid must start with prefix " + ROUTER_UUID_PREFIX);
}
Processor processor = null;
this.routingAlgorithms.put(UuidHelper.getSegmentFromEndpointNameOrEndpointUuid(routerUuid), routingAlgorithm);
routerUuids.add(routerUuid);
if (routerUuids.size() > 1) {
for (String uuid : routerUuids) {
if (!routerUuid.equals(uuid)) {
Link link = new Link(0);
link.addFilterProcessor(processor);
link.setChainedProcessor(this);
try {
addLink(UuidHelper.getSegmentFromEndpointNameOrEndpointUuid(uuid), link);
} catch (Exception e) {
e.printStackTrace();
}
link = new Link(0);
link.addFilterProcessor(processor);
link.setChainedProcessor(this);
try {
addLink(UuidHelper.getSegmentFromEndpointNameOrEndpointUuid(routerUuid), link);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
if (running) {
try {
routingAlgorithm.start();
} catch (Exception e) {
e.printStackTrace();
}
}
}
public void aliasesUpdated() {
// remove global aliases
for (Link link : links.values()) {
Collection aliases = link.getAlises();
synchronized (aliases) {
//Synchronizes on alias since concurrent access to this member can cause exceptions,
//Can not use ConcurrentHashmap cause of java 1.3
for (Iterator iterator = aliases.iterator(); iterator.hasNext();) {
String alias = (String) iterator.next();
if (alias.startsWith(Router.DICO_SEGMENT + ".") && !aliasTable.containsKey(alias)) {
iterator.remove();
}
}
}
}
// add global aliases in crossegment links
for (String alias : aliasTable.keySet()) {
if (alias.startsWith(Router.DICO_SEGMENT + ".")) {
String aliasUuid = aliasTable.get(alias);
String aliasSegment = UuidHelper.getSegmentFromEndpointNameOrEndpointUuid(aliasUuid);
for (Link link : links.values()) {
String segment = UuidHelper.getSegmentFromSegmentOrEndpointUuid(link.getDestinationUuid());
if (aliasSegment.equals(segment) && UuidHelper.isSegment(link.getDestinationUuid())) {
link.addAlias(alias);
}
}
}
}
}
public String getDefaultQoSClass() {
return defaultQoSClass;
}
public RoutingAlgorithm getRoutingAlgorithm(String segment) {
return routingAlgorithms.get(segment);
}
public Map getRoutingTables() {
return routingTables;
}
public Map getRoutingTable(String qos) {
return routingTables.get(qos);
}
public Map getLinks() {
return links;
}
public Link getLinkById(String id) {
return links.get(id);
}
public void start() throws Exception {
if (!running && enabled) {
for (RoutingAlgorithm routingAlgorithm : routingAlgorithms.values()) {
routingAlgorithm.start();
}
running = true;
}
}
public void stop() throws Exception {
for (RoutingAlgorithm routingAlgorithm : routingAlgorithms.values()) {
routingAlgorithm.stop();
}
running = false;
}
public String toString() {
return "Router " + COOSInstanceName;
}
public Map getAliasTable() {
return aliasTable;
}
public void putAlias(String alias, String toUuid) {
String oldToUuid = aliasTable.get(alias);
if (oldToUuid != null && !oldToUuid.equals(toUuid)) {
logger.warn("Possible alias conflict for alias: " + alias + ". Was pointing to : " + oldToUuid
+ ". Now pointing to :" + toUuid + ".");
}
aliasTable.put(alias, toUuid);
aliasesUpdated();
}
public void removeAlias(String alias) {
aliasTable.remove(alias);
aliasesUpdated();
}
@Override
public void addDynamicSegment(String segmentName, String routingAlg) throws ConnectingException {
RoutingAlgorithm prototype = COOS.getRoutingAlgorithm(routingAlg);
if (prototype == null) {
throw new ConnectingException("Routingalgorithm: " + routingAlg
+ " not defined. Refusing dynamic segment allocation: " + segmentName);
}
RoutingAlgorithm algorithm = prototype.copy();
UuidGenerator uuidGenerator = new UuidGenerator(ROUTER_UUID_PREFIX);
String routerUuid = segmentName + "." + uuidGenerator.generateSanitizedId();
segmentMapping.put(segmentName, new RouterSegment(segmentName, routerUuid, routingAlg, false, true));
algorithm.init(routerUuid, this);
}
@Override
public RouterSegment getSegment(String segmentName) {
return segmentMapping.get(segmentName);
}
@Override
public Map getSegmentMap() {
return segmentMapping;
}
@Override
public void removeSegment(String segmentName) {
segmentMapping.remove(segmentName);
routingAlgorithms.remove(segmentName);
removeLink(segmentName);
}
}