📄 routingtableimpl.java
字号:
localRoutingTable.getRoute(jid.getDomain()).process(packet);
routed = true;
break;
} catch (UnauthorizedException e) {
Log.error(e);
}
}
else {
// This is a route to a local component hosted in other node
if (remotePacketRouter != null) {
routed = remotePacketRouter.routePacket(nodeID.toByteArray(), jid, packet);
if (routed) {
break;
}
}
}
}
}
}
}
else {
// Packet sent to remote server
byte[] nodeID = serversCache.get(jid.getDomain());
if (nodeID != null) {
if (server.getNodeID().equals(nodeID)) {
// This is a route to a remote server connected from this node
try {
localRoutingTable.getRoute(jid.getDomain()).process(packet);
routed = true;
} catch (UnauthorizedException e) {
Log.error(e);
}
}
else {
// This is a route to a remote server connected from other node
if (remotePacketRouter != null) {
routed = remotePacketRouter.routePacket(nodeID, jid, packet);
}
}
}
else {
// Return a promise of a remote session. This object will queue packets pending
// to be sent to remote servers
OutgoingSessionPromise.getInstance().process(packet);
routed = true;
}
}
if (!routed) {
if (Log.isDebugEnabled()) {
Log.debug("RoutingTableImpl: Failed to route packet to JID: " + jid + " packet: " + packet);
}
if (packet instanceof IQ) {
iqRouter.routingFailed(jid, packet);
}
else if (packet instanceof Message) {
messageRouter.routingFailed(jid, packet);
}
else if (packet instanceof Presence) {
presenceRouter.routingFailed(jid, packet);
}
}
}
/**
* Returns true if the specified packet must only be route to available client sessions.
*
* @param packet the packet to route.
* @param fromServer true if the packet was created by the server.
* @return true if the specified packet must only be route to available client sessions.
*/
private boolean routeOnlyAvailable(Packet packet, boolean fromServer) {
if (fromServer) {
// Packets created by the server (no matter their FROM value) must always be delivered no
// matter the available presence of the user
return false;
}
boolean onlyAvailable = true;
JID from = packet.getFrom();
boolean hasSender = from != null;
if (packet instanceof IQ) {
onlyAvailable = hasSender && !(serverName.equals(from.getDomain()) && from.getResource() == null) &&
!componentsCache.containsKey(from.toString());
}
else if (packet instanceof Message) {
onlyAvailable = !hasSender ||
(!serverName.equals(from.toString()) && !componentsCache.containsKey(from.toString()));
}
else if (packet instanceof Presence) {
onlyAvailable = !hasSender ||
(!serverName.equals(from.toString()) && !componentsCache.containsKey(from.toString()));
}
return onlyAvailable;
}
/**
* Deliver the message sent to the bare JID of a local user to the best connected resource. If the
* target user is not online then messages will be stored offline according to the offline strategy.
* However, if the user is connected from only one resource then the message will be delivered to
* that resource. In the case that the user is connected from many resources the logic will be the
* following:
* <ol>
* <li>Select resources with highest priority</li>
* <li>Select resources with highest show value (chat, available, away, xa, dnd)</li>
* <li>Select resource with most recent activity</li>
* </ol>
*
* Admins can override the above logic and just send the message to all connected resources
* with highest priority by setting the system property <tt>route.all-resources</tt> to
* <tt>true</tt>.
*
* @param recipientJID the bare JID of the target local user.
* @param packet the message to send.
* @return true if at least one target session was found
*/
private boolean routeToBareJID(JID recipientJID, Message packet) {
List<ClientSession> sessions = new ArrayList<ClientSession>();
// Get existing AVAILABLE sessions of this user or AVAILABLE to the sender of the packet
for (JID address : getRoutes(recipientJID, packet.getFrom())) {
ClientSession session = getClientRoute(address);
if (session != null) {
sessions.add(session);
}
}
sessions = getHighestPrioritySessions(sessions);
if (sessions.isEmpty()) {
// No session is available so store offline
return false;
}
else if (sessions.size() == 1) {
// Found only one session so deliver message
sessions.get(0).process(packet);
}
else {
// Many sessions have the highest priority (be smart now) :)
if (!JiveGlobals.getBooleanProperty("route.all-resources", false)) {
// Sort sessions by show value (e.g. away, xa)
Collections.sort(sessions, new Comparator<ClientSession>() {
public int compare(ClientSession o1, ClientSession o2) {
int thisVal = getShowValue(o1);
int anotherVal = getShowValue(o2);
return (thisVal<anotherVal ? -1 : (thisVal==anotherVal ? 0 : 1));
}
/**
* Priorities are: chat, available, away, xa, dnd.
*/
private int getShowValue(ClientSession session) {
Presence.Show show = session.getPresence().getShow();
if (show == Presence.Show.chat) {
return 1;
}
else if (show == null) {
return 2;
}
else if (show == Presence.Show.away) {
return 3;
}
else if (show == Presence.Show.xa) {
return 4;
}
else {
return 5;
}
}
});
// Get same sessions with same max show value
List<ClientSession> targets = new ArrayList<ClientSession>();
Presence.Show showFilter = sessions.get(0).getPresence().getShow();
for (ClientSession session : sessions) {
if (session.getPresence().getShow() == showFilter) {
targets.add(session);
}
else {
break;
}
}
// Get session with most recent activity (and highest show value)
Collections.sort(targets, new Comparator<ClientSession>() {
public int compare(ClientSession o1, ClientSession o2) {
return o2.getLastActiveDate().compareTo(o1.getLastActiveDate());
}
});
// Deliver stanza to session with highest priority, highest show value and most recent activity
targets.get(0).process(packet);
}
else {
// Deliver stanza to all connected resources with highest priority
for (ClientSession session : sessions) {
session.process(packet);
}
}
}
return true;
}
/**
* Returns the sessions that had the highest presence priority greater than zero.
*
* @param sessions the list of user sessions that filter and get the ones with highest priority.
* @return the sessions that had the highest presence priority greater than zero or empty collection
* if all were negative.
*/
private List<ClientSession> getHighestPrioritySessions(List<ClientSession> sessions) {
int highest = Integer.MIN_VALUE;
// Get the highest priority amongst the sessions
for (ClientSession session : sessions) {
int priority = session.getPresence().getPriority();
if (priority >= 0 && priority > highest) {
highest = priority;
}
}
// Answer an empty collection if all have negative priority
if (highest == Integer.MIN_VALUE) {
return Collections.emptyList();
}
// Get sessions that have the highest priority
List<ClientSession> answer = new ArrayList<ClientSession>(sessions.size());
for (ClientSession session : sessions) {
if (session.getPresence().getPriority() == highest) {
answer.add(session);
}
}
return answer;
}
public ClientSession getClientRoute(JID jid) {
// Check if this session is hosted by this cluster node
ClientSession session = (ClientSession) localRoutingTable.getRoute(jid.toString());
if (session == null) {
// The session is not in this JVM so assume remote
RemoteSessionLocator locator = server.getRemoteSessionLocator();
if (locator != null) {
// Check if the session is hosted by other cluster node
ClientRoute route = usersCache.get(jid.toString());
if (route == null) {
route = anonymousUsersCache.get(jid.toString());
}
if (route != null) {
session = locator.getClientSession(route.getNodeID().toByteArray(), jid);
}
}
}
return session;
}
public Collection<ClientSession> getClientsRoutes(boolean onlyLocal) {
// Add sessions hosted by this cluster node
Collection<ClientSession> sessions = new ArrayList<ClientSession>(localRoutingTable.getClientRoutes());
if (!onlyLocal) {
// Add sessions not hosted by this JVM
RemoteSessionLocator locator = server.getRemoteSessionLocator();
if (locator != null) {
// Add sessions of non-anonymous users hosted by other cluster nodes
for (Map.Entry<String, ClientRoute> entry : usersCache.entrySet()) {
ClientRoute route = entry.getValue();
if (!server.getNodeID().equals(route.getNodeID())) {
sessions.add(locator.getClientSession(route.getNodeID().toByteArray(), new JID(entry.getKey())));
}
}
// Add sessions of anonymous users hosted by other cluster nodes
for (Map.Entry<String, ClientRoute> entry : anonymousUsersCache.entrySet()) {
ClientRoute route = entry.getValue();
if (!server.getNodeID().equals(route.getNodeID())) {
sessions.add(locator.getClientSession(route.getNodeID().toByteArray(), new JID(entry.getKey())));
}
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -