📄 routingtableimpl.java
字号:
/**
* $RCSfile: RoutingTableImpl.java,v $
* $Revision: 3138 $
* $Date: 2005-12-01 02:13:26 -0300 (Thu, 01 Dec 2005) $
*
* Copyright (C) 2004 Jive Software. All rights reserved.
*
* This software is published under the terms of the GNU Public License (GPL),
* a copy of which is included in this distribution.
*/
package org.jivesoftware.wildfire.spi;
import org.jivesoftware.util.Log;
import org.jivesoftware.wildfire.*;
import org.jivesoftware.wildfire.component.InternalComponentManager;
import org.jivesoftware.wildfire.container.BasicModule;
import org.jivesoftware.wildfire.server.OutgoingSessionPromise;
import org.xmpp.packet.JID;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
/**
* <p>Uses simple Maps for table storage.</p>
* <p>Leaves in the tree are indicated by a PacketHandler, while branches are stored in Maps.
* Traverse the tree according to an XMPPAddress' fields (host -> name -> resource) and when you
* hit a PacketHandler, you have found the handler for that node and all sub-nodes. </p>
*
* @author Iain Shigeoka
*/
public class RoutingTableImpl extends BasicModule implements RoutingTable {
/**
* We need a three level tree built of hashtables: host -> name -> resource
*/
private Map routes = new ConcurrentHashMap();
private String serverName;
private InternalComponentManager componentManager;
public RoutingTableImpl() {
super("Routing table");
componentManager = InternalComponentManager.getInstance();
}
public void addRoute(JID node, RoutableChannelHandler destination) {
String nodeJID = node.getNode() == null ? "" : node.getNode();
String resourceJID = node.getResource() == null ? "" : node.getResource();
if (destination instanceof ClientSession) {
Object nameRoutes = routes.get(node.getDomain());
if (nameRoutes == null) {
// No route to the requested domain. Create a new entry in the table
synchronized (node.getDomain().intern()) {
// Check again if a route exists now that we have a lock
nameRoutes = routes.get(node.getDomain());
if (nameRoutes == null) {
// Still nothing so create a new entry in the map for domain
nameRoutes = new ConcurrentHashMap();
routes.put(node.getDomain(), nameRoutes);
}
}
}
// Check if there is something associated with the node of the JID
Object resourceRoutes = ((Map) nameRoutes).get(nodeJID);
if (resourceRoutes == null) {
// Nothing was found so create a new entry for this node (a.k.a. user)
synchronized (nodeJID.intern()) {
resourceRoutes = ((Map) nameRoutes).get(nodeJID);
if (resourceRoutes == null) {
resourceRoutes = new ConcurrentHashMap();
((Map) nameRoutes).put(nodeJID, resourceRoutes);
}
}
}
// Add the connected resource to the node's Map
((Map) resourceRoutes).put(resourceJID, destination);
}
else {
routes.put(node.getDomain(), destination);
}
}
public RoutableChannelHandler getRoute(JID node) {
if (node == null) {
return null;
}
return getRoute(node.toString(), node.getNode() == null ? "" : node.getNode(),
node.getDomain(), node.getResource() == null ? "" : node.getResource());
}
private RoutableChannelHandler getRoute(String jid, String node, String domain,
String resource) {
RoutableChannelHandler route = null;
// Check if the address belongs to a remote server
if (!serverName.equals(domain) && routes.get(domain) == null &&
componentManager.getComponent(domain) == null) {
// Return a promise of a remote session. This object will queue packets pending
// to be sent to remote servers
return OutgoingSessionPromise.getInstance();
}
try {
Object nameRoutes = routes.get(domain);
if (nameRoutes instanceof ChannelHandler) {
route = (RoutableChannelHandler) nameRoutes;
}
else if (nameRoutes != null) {
Object resourceRoutes = ((Map) nameRoutes).get(node);
if (resourceRoutes instanceof ChannelHandler) {
route = (RoutableChannelHandler) resourceRoutes;
}
else if (resourceRoutes != null) {
route = (RoutableChannelHandler) ((Map) resourceRoutes).get(resource);
}
else {
route = null;
}
}
}
catch (Exception e) {
if (Log.isDebugEnabled()) {
Log.debug("Route not found for JID: " + jid, e);
}
}
return route;
}
public List<ChannelHandler> getRoutes(JID node) {
// Check if the address belongs to a remote server
if (!serverName.equals(node.getDomain()) && routes.get(node.getDomain()) == null &&
componentManager.getComponent(node) == null) {
// Return a promise of a remote session. This object will queue packets pending
// to be sent to remote servers
List<ChannelHandler> list = new ArrayList<ChannelHandler>();
list.add(OutgoingSessionPromise.getInstance());
return list;
}
LinkedList list = null;
Object nameRoutes = routes.get(node.getDomain());
if (nameRoutes != null) {
if (nameRoutes instanceof ChannelHandler) {
list = new LinkedList();
list.add(nameRoutes);
}
else if (node.getNode() == null) {
list = new LinkedList();
getRoutes(list, (Map) nameRoutes);
}
else {
Object resourceRoutes = ((Map) nameRoutes).get(node.getNode());
if (resourceRoutes != null) {
if (resourceRoutes instanceof ChannelHandler) {
list = new LinkedList();
list.add(resourceRoutes);
}
else if (node.getResource() == null || node.getResource().length() == 0) {
list = new LinkedList();
getRoutes(list, (Map) resourceRoutes);
}
else {
Object entry = ((Map) resourceRoutes).get(node.getResource());
if (entry != null) {
list = new LinkedList();
list.add(entry);
}
}
}
}
}
if (list == null) {
return Collections.emptyList();
}
else {
return list;
}
}
/**
* Recursive method to iterate through the given table (and any embedded map)
* and stuff non-Map values into the given list.<p>
*
* There should be no recursion problems since the routing table is at most 3 levels deep.
*
* @param list The list to stuff entries into
* @param table The hashtable who's values should be entered into the list
*/
private void getRoutes(LinkedList list, Map table) {
Iterator entryIter = table.values().iterator();
while (entryIter.hasNext()) {
Object entry = entryIter.next();
if (entry instanceof ConcurrentHashMap) {
getRoutes(list, (Map)entry);
}
else {
// Do not include the same entry many times. This could be the case when the same
// session is associated with the bareJID and with a given resource
if (!list.contains(entry)) {
list.add(entry);
}
}
}
}
public ChannelHandler getBestRoute(JID node) {
ChannelHandler route = getRoute(node);
if (route == null) {
// Try looking for a route based on the bare JID
String nodeJID = node.getNode() == null ? "" : node.getNode();
route = getRoute(node.toBareJID(), nodeJID, node.getDomain(), "");
}
return route;
}
public ChannelHandler removeRoute(JID node) {
ChannelHandler route = null;
String nodeJID = node.getNode() == null ? "" : node.getNode();
String resourceJID = node.getResource() == null ? "" : node.getResource();
try {
Object nameRoutes = routes.get(node.getDomain());
if (nameRoutes instanceof ConcurrentHashMap) {
Object resourceRoutes = ((Map) nameRoutes).get(nodeJID);
if (resourceRoutes instanceof ConcurrentHashMap) {
// Remove the requested resource for this user
route = (ChannelHandler) ((Map) resourceRoutes).remove(resourceJID);
if (((Map) resourceRoutes).isEmpty()) {
((Map) nameRoutes).remove(nodeJID);
if (((Map) nameRoutes).isEmpty()) {
routes.remove(node.getDomain());
}
}
}
else {
// Remove the unique route to this node
((Map) nameRoutes).remove(nodeJID);
}
}
else if (nameRoutes != null) {
// The retrieved route points to a RoutableChannelHandler
if (("".equals(nodeJID) && "".equals(resourceJID)) ||
((RoutableChannelHandler) nameRoutes).getAddress().equals(node)) {
// Remove the route to this domain
routes.remove(node.getDomain());
}
}
}
catch (Exception e) {
Log.error("Error removing route", e);
}
return route;
}
public void initialize(XMPPServer server) {
super.initialize(server);
serverName = server.getServerInfo().getName();
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -