📄 iqrouter.java
字号:
/**
* $RCSfile: IQRouter.java,v $
* $Revision: 3135 $
* $Date: 2005-12-01 02:03:04 -0300 (Thu, 01 Dec 2005) $
*
* Copyright (C) 2008 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, or a commercial license
* agreement with Jive.
*/
package org.jivesoftware.openfire;
import org.dom4j.Element;
import org.jivesoftware.openfire.container.BasicModule;
import org.jivesoftware.openfire.handler.IQHandler;
import org.jivesoftware.openfire.interceptor.InterceptorManager;
import org.jivesoftware.openfire.interceptor.PacketRejectedException;
import org.jivesoftware.openfire.privacy.PrivacyList;
import org.jivesoftware.openfire.privacy.PrivacyListManager;
import org.jivesoftware.openfire.session.ClientSession;
import org.jivesoftware.openfire.session.Session;
import org.jivesoftware.openfire.user.UserManager;
import org.jivesoftware.util.LocaleUtils;
import org.jivesoftware.util.Log;
import org.jivesoftware.util.TaskEngine;
import org.xmpp.packet.*;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
/**
* Routes iq packets throughout the server. Routing is based on the recipient
* and sender addresses. The typical packet will often be routed twice, once
* from the sender to some internal server component for handling or processing,
* and then back to the router to be delivered to it's final destination.
*
* @author Iain Shigeoka
*/
public class IQRouter extends BasicModule {
private RoutingTable routingTable;
private MulticastRouter multicastRouter;
private String serverName;
private List<IQHandler> iqHandlers = new ArrayList<IQHandler>();
private Map<String, IQHandler> namespace2Handlers = new ConcurrentHashMap<String, IQHandler>();
private Map<String, IQResultListener> resultListeners = new ConcurrentHashMap<String, IQResultListener>();
private Map<String, Long> resultTimeout = new ConcurrentHashMap<String, Long>();
private SessionManager sessionManager;
private UserManager userManager;
/**
* Creates a packet router.
*/
public IQRouter() {
super("XMPP IQ Router");
}
/**
* <p>Performs the actual packet routing.</p>
* <p>You routing is considered 'quick' and implementations may not take
* excessive amounts of time to complete the routing. If routing will take
* a long amount of time, the actual routing should be done in another thread
* so this method returns quickly.</p>
* <h2>Warning</h2>
* <p>Be careful to enforce concurrency DbC of concurrent by synchronizing
* any accesses to class resources.</p>
*
* @param packet The packet to route
* @throws NullPointerException If the packet is null
*/
public void route(IQ packet) {
if (packet == null) {
throw new NullPointerException();
}
JID sender = packet.getFrom();
ClientSession session = sessionManager.getSession(sender);
try {
// Invoke the interceptors before we process the read packet
InterceptorManager.getInstance().invokeInterceptors(packet, session, true, false);
JID to = packet.getTo();
if (session != null && to != null && session.getStatus() == Session.STATUS_CONNECTED &&
!serverName.equals(to.toString())) {
// User is requesting this server to authenticate for another server. Return
// a bad-request error
IQ reply = IQ.createResultIQ(packet);
reply.setChildElement(packet.getChildElement().createCopy());
reply.setError(PacketError.Condition.bad_request);
session.process(reply);
Log.warn("User tried to authenticate with this server using an unknown receipient: " +
packet);
}
else if (session == null || session.getStatus() == Session.STATUS_AUTHENTICATED || (
isLocalServer(to) && (
"jabber:iq:auth".equals(packet.getChildElement().getNamespaceURI()) ||
"jabber:iq:register"
.equals(packet.getChildElement().getNamespaceURI()) ||
"urn:ietf:params:xml:ns:xmpp-bind"
.equals(packet.getChildElement().getNamespaceURI())))) {
handle(packet);
}
else {
IQ reply = IQ.createResultIQ(packet);
reply.setChildElement(packet.getChildElement().createCopy());
reply.setError(PacketError.Condition.not_authorized);
session.process(reply);
}
// Invoke the interceptors after we have processed the read packet
InterceptorManager.getInstance().invokeInterceptors(packet, session, true, true);
}
catch (PacketRejectedException e) {
if (session != null) {
// An interceptor rejected this packet so answer a not_allowed error
IQ reply = new IQ();
reply.setChildElement(packet.getChildElement().createCopy());
reply.setID(packet.getID());
reply.setTo(session.getAddress());
reply.setFrom(packet.getTo());
reply.setError(PacketError.Condition.not_allowed);
session.process(reply);
// Check if a message notifying the rejection should be sent
if (e.getRejectionMessage() != null && e.getRejectionMessage().trim().length() > 0) {
// A message for the rejection will be sent to the sender of the rejected packet
Message notification = new Message();
notification.setTo(session.getAddress());
notification.setFrom(packet.getTo());
notification.setBody(e.getRejectionMessage());
session.process(notification);
}
}
}
}
/**
* <p>Adds a new IQHandler to the list of registered handler. The new IQHandler will be
* responsible for handling IQ packet whose namespace matches the namespace of the
* IQHandler.</p>
*
* An IllegalArgumentException may be thrown if the IQHandler to register was already provided
* by the server. The server provides a certain list of IQHandlers when the server is
* started up.
*
* @param handler the IQHandler to add to the list of registered handler.
*/
public void addHandler(IQHandler handler) {
if (iqHandlers.contains(handler)) {
throw new IllegalArgumentException("IQHandler already provided by the server");
}
// Ask the handler to be initialized
handler.initialize(XMPPServer.getInstance());
// Register the handler as the handler of the namespace
namespace2Handlers.put(handler.getInfo().getNamespace(), handler);
}
/**
* <p>Removes an IQHandler from the list of registered handler. The IQHandler to remove was
* responsible for handling IQ packet whose namespace matches the namespace of the
* IQHandler.</p>
*
* An IllegalArgumentException may be thrown if the IQHandler to remove was already provided
* by the server. The server provides a certain list of IQHandlers when the server is
* started up.
*
* @param handler the IQHandler to remove from the list of registered handler.
*/
public void removeHandler(IQHandler handler) {
if (iqHandlers.contains(handler)) {
throw new IllegalArgumentException("Cannot remove an IQHandler provided by the server");
}
// Unregister the handler as the handler of the namespace
namespace2Handlers.remove(handler.getInfo().getNamespace());
}
/**
* Adds an {@link IQResultListener} that will be invoked when an IQ result
* is sent to the server itself and is of type result or error. This is a
* nice way for the server to send IQ packets to other XMPP entities and be
* waked up when a response is received back.<p>
*
* Once an IQ result was received, the listener will be invoked and removed
* from the list of listeners.<p>
*
* If no result was received within one minute, the timeout method of the
* listener will be invoked and the listener will be removed from the list
* of listeners.
*
* @param id
* the id of the IQ packet being sent from the server to an XMPP
* entity.
* @param listener
* the IQResultListener that will be invoked when an answer is
* received
*/
public void addIQResultListener(String id, IQResultListener listener) {
addIQResultListener(id, listener, 60 * 1000);
}
/**
* Adds an {@link IQResultListener} that will be invoked when an IQ result
* is sent to the server itself and is of type result or error. This is a
* nice way for the server to send IQ packets to other XMPP entities and be
* waked up when a response is received back.<p>
*
* Once an IQ result was received, the listener will be invoked and removed
* from the list of listeners.<p>
*
* If no result was received within the specified amount of milliseconds,
* the timeout method of the listener will be invoked and the listener will
* be removed from the list of listeners.<p>
*
* Note that the listener will remain active for <em>at least</em> the
* specified timeout value. The listener will not be removed at the exact
* moment it times out. Instead, purging of timed out listeners is a
* periodic scheduled job.
*
* @param id
* the id of the IQ packet being sent from the server to an XMPP
* entity.
* @param listener
* the IQResultListener that will be invoked when an answer is
* received.
* @param timeoutmillis
* The amount of milliseconds after which waiting for a response
* should be stopped.
*/
public void addIQResultListener(String id, IQResultListener listener, long timeoutmillis) {
resultListeners.put(id, listener);
resultTimeout.put(id, System.currentTimeMillis() + timeoutmillis);
}
public void initialize(XMPPServer server) {
super.initialize(server);
TaskEngine.getInstance().scheduleAtFixedRate(new TimeoutTask(), 5000, 5000);
serverName = server.getServerInfo().getXMPPDomain();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -