openfire插件IQHandle工作原理

1、 定义一个插件,在插件初始化的时候加载IQHandler实现类

public class AdtecPlugin implements Plugin {

	private XMPPServer server = XMPPServer.getInstance();

	@Override
	public void initializePlugin(PluginManager manager, File pluginDirectory) {
		System.out.println("hb initializePlugin");

		//发布webservice接口
		publish();
		
		//注册IQHandle对象
		server.getIQRouter().addHandler(new AdtecIQHandle("huangbiaoMyIQHandle"));
		//添加拦截器
		//InterceptorManager.getInstance().addInterceptor(new AdtecInterceptor());
		
		System.out.println("初始化…… 安装插件!");
		System.out.println(server.getServerInfo());
	}

	@Override
	public void destroyPlugin() {
		// TODO Auto-generated method stub
		System.out.println("hb destroyPlugin");
	}

	public void publish() {

		JaxWsServerFactoryBean msgfactory = new JaxWsServerFactoryBean();
		MessageService msgservice = new MessageService();
		msgfactory.setAddress("http://127.0.0.1:9999/ws/msgservice");
		// 对外公布接口类
		msgfactory.setServiceClass(IMessageService.class);
		msgfactory.setServiceBean(msgservice);
		msgfactory.create();

		JaxWsServerFactoryBean sysFactory = new JaxWsServerFactoryBean();
		XMPPSystemService sysService = new XMPPSystemService();
		sysFactory.setServiceClass(IXMPPSystemService.class);
		sysFactory.setServiceBean(sysService);
		sysFactory.setAddress("http://127.0.0.1:9999/ws/sysservice");
		sysFactory.create();

	}
}

 备注:

server.getIQRouter().addHandler(new AdtecIQHandle("huangbiaoMyIQHandle"));

注册实际上是用map存储的,key就是命名空间,代码:

namespace2Handlers.put(handler.getInfo().getNamespace(), handler);

2、 创建一个类继承IQHandler接口,并添加一个IQHandlerInfo类做为私有属性

package com.jivesoftware.openfire.iqhandle;

import java.util.Iterator;
import java.util.List;

import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.QName;
import org.jivesoftware.openfire.IQHandlerInfo;
import org.jivesoftware.openfire.XMPPServer;
import org.jivesoftware.openfire.auth.UnauthorizedException;
import org.jivesoftware.openfire.handler.IQHandler;
import org.xmpp.packet.IQ;

public class AdtecIQHandle extends IQHandler{

	private IQHandlerInfo iqHandlerInfo;
	
	public AdtecIQHandle(String moduleName) {
		super(moduleName);
		//第一个参数 : 名字
		//第二个参数 : 命名空间,可以根据报名来确定
		iqHandlerInfo = new IQHandlerInfo(moduleName, "hb:iqhandle");
		
//		XMPPServer.getInstance().getIQHandlers().add(this);
	}

	@Override
	public IQHandlerInfo getInfo() {
		
		return iqHandlerInfo;
	}

	@Override
	public IQ handleIQ(IQ packet) throws UnauthorizedException {
		System.out.println(packet.toXML());
//		IQ mypacket = packet.createResultIQ(iq);
		IQ response = IQ.createResultIQ(packet);
		Element queryElement = response.setChildElement("query", "hb:iqhandle");
				
		Element userElement = queryElement.addElement("username");
		Element passElement = queryElement.addElement("password");
		
		userElement.setText("HUANGBIAO");
		passElement.setText("password");
		
		System.out.println(response.toXML());

		return response;
	}

}

3、在IQRouter类中handle(IQ packet) 这个方法来处理对应请求,会根据请求调用查找是否注册了该请求的IQHandle对象

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.toXML());
		}
		/**
		 * 用户没有登录过
		 * 登录过的用户并且是已经验证了的
		 * 请求是给本机并且扩展名是jabber:iq:auth/jabber:iq:register/urn:ietf:params:xml:ns:xmpp-bind
		 */
		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);
			}
		}
	}
}

/***************** public class IQRouter*******************/
private void handle(IQ packet) {
	JID recipientJID = packet.getTo();
	// Check if the packet was sent to the server hostname
	if (recipientJID != null && recipientJID.getNode() == null &&
			recipientJID.getResource() == null && serverName.equals(recipientJID.getDomain())) {
		Element childElement = packet.getChildElement();
		if (childElement != null && childElement.element("addresses") != null) {
			// Packet includes multicast processing instructions. Ask the multicastRouter
			// to route this packet
			multicastRouter.route(packet);
			return;
		}
	}
	if (packet.getID() != null && (IQ.Type.result == packet.getType() || IQ.Type.error == packet.getType())) {
		// The server got an answer to an IQ packet that was sent from the server
		IQResultListener iqResultListener = resultListeners.remove(packet.getID());
		if (iqResultListener != null) {
			resultTimeout.remove(packet.getID());
			if (iqResultListener != null) {
				try {
					iqResultListener.receivedAnswer(packet);
				}
				catch (Exception e) {
					Log.error(
							"Error processing answer of remote entity. Answer: "
									+ packet.toXML(), e);
				}
				return;
			}
		}
	}
	try {
		// Check for registered components, services or remote servers
		if (recipientJID != null &&
				(routingTable.hasComponentRoute(recipientJID) || routingTable.hasServerRoute(recipientJID))) {
			// A component/service/remote server was found that can handle the Packet
			routingTable.routePacket(recipientJID, packet, false);
			return;
		}
		if (isLocalServer(recipientJID)) {
			// Let the server handle the Packet
			Element childElement = packet.getChildElement();
			String namespace = null;
			if (childElement != null) {
				namespace = childElement.getNamespaceURI();
			}
			if (namespace == null) {
				if (packet.getType() != IQ.Type.result && packet.getType() != IQ.Type.error) {
					// Do nothing. We can't handle queries outside of a valid namespace
					Log.warn("Unknown packet " + packet.toXML());
				}
			}
			else {
				// Check if communication to local users is allowed
				if (recipientJID != null && userManager.isRegisteredUser(recipientJID.getNode())) {
					PrivacyList list =
							PrivacyListManager.getInstance().getDefaultPrivacyList(recipientJID.getNode());
					if (list != null && list.shouldBlockPacket(packet)) {
						// Communication is blocked
						if (IQ.Type.set == packet.getType() || IQ.Type.get == packet.getType()) {
							// Answer that the service is unavailable
							sendErrorPacket(packet, PacketError.Condition.service_unavailable);
						}
						return;
					}
				}
				//根据命名空间获取IQHandler对象
				IQHandler handler = getHandler(namespace);
				if (handler == null) {
					if (recipientJID == null) {
						// Answer an error since the server can't handle the requested namespace
						sendErrorPacket(packet, PacketError.Condition.service_unavailable);
					}
					else if (recipientJID.getNode() == null ||
							"".equals(recipientJID.getNode())) {
						// Answer an error if JID is of the form <domain>
						sendErrorPacket(packet, PacketError.Condition.feature_not_implemented);
					}
					else {
						// JID is of the form <node@domain>
						// Answer an error since the server can't handle packets sent to a node
						sendErrorPacket(packet, PacketError.Condition.service_unavailable);
					}
				}
				else {
				//获取 handler 来处理packet请求,这个handler就是根据命名空间获取的
					handler.process(packet);
				}
			}
		}
		else {
			// JID is of the form <node@domain/resource> or belongs to a remote server
			// or to an uninstalled component
			routingTable.routePacket(recipientJID, packet, false);
		}
	}
	catch (Exception e) {
		Log.error(LocaleUtils.getLocalizedString("admin.error.routing"), e);
		Session session = sessionManager.getSession(packet.getFrom());
		if (session != null) {
			IQ reply = IQ.createResultIQ(packet);
			reply.setError(PacketError.Condition.internal_server_error);
			session.process(reply);
		}
	}
}

/*************** abstract class IQHandler***********************/
public void process(Packet packet) throws PacketException {
	IQ iq = (IQ) packet;
	try {
		//自定义处理iq请求,返回server响应的请求
		IQ reply = handleIQ(iq);
		if (reply != null) {
		//将已经处理的reply请求再次发送到客户端,底层是socket
			deliverer.deliver(reply);
		}
	}
	catch (org.jivesoftware.openfire.auth.UnauthorizedException e) {
		if (iq != null) {
			try {
				IQ response = IQ.createResultIQ(iq);
				response.setChildElement(iq.getChildElement().createCopy());
				response.setError(PacketError.Condition.not_authorized);
				sessionManager.getSession(iq.getFrom()).process(response);
			}
			catch (Exception de) {
				Log.error(LocaleUtils.getLocalizedString("admin.error"), de);
				sessionManager.getSession(iq.getFrom()).close();
			}
		}
	}
	catch (Exception e) {
		Log.error(LocaleUtils.getLocalizedString("admin.error"), e);
		try {
			IQ response = IQ.createResultIQ(iq);
			response.setChildElement(iq.getChildElement().createCopy());
			response.setError(PacketError.Condition.internal_server_error);
			sessionManager.getSession(iq.getFrom()).process(response);
		}
		catch (Exception e1) {
			// Do nothing
		}
	}
}

备注:在handle(IQ packet) 和 route(IQ packet) 这两个方法会调用handle(IQ packet)这个方法,其中route(IQ packet)是会根据发送过来的请求,根据是否有指定的“命名空间”来判断是否有指定的IQHandle请求,

String namespace = null;
                if (childElement != null) {
                    namespace = childElement.getNamespaceURI();
                }
IQHandler handler = getHandler(namespace);
handler.process(packet);

4、IQ请求一定要是登录的用户,否则无法响应。因为发送的IQ请求经过处理之后,会返回一个IQXML字符串,这个字符串需要客户端接收,如果没有用户登录,则无法接受服务器处理的请求

下面这段代码是我用jwchat客户端测试的,在jsjac.js文件中添加如下代码:

JSJaCConnection.prototype._dohuangbiao = function () {
alert(2222);
	if (this.authtype == 'saslanon' || this.authtype == 'anonymous') return;
	var iq = new JSJaCIQ();
	iq.setType('set');
	iq.setID('reg1');
	iq.appendNode("query", {
		xmlns: "hb:iqhandle"
	}, [
		["username", "huangbiao"],
		["password", "liumei"]
	]);
	this.send(iq, this._dohuangbiaoDone);
};

JSJaCConnection.prototype._dohuangbiaoDone = function (iq) {
/*
	if (iq && iq.getType() == 'error') {
		this.oDbg.log("registration failed for " + this.username, 0);
		this._handleEvent('onerror', iq.getChild('error'));
		return;
	}
	this.oDbg.log(this.username + " registered succesfully", 0);
	this._doAuth();
*/	
	this.oDbg.log("huangbiao : " + packet.xml());
};

会在jsjac.js文件中定义的方法

JSJaCConnection.prototype._process = function (timerval) {
	if (!this.connected()) {
		this.oDbg.log("Connection lost ...", 1);
		if (this._interval) clearInterval(this._interval);
		return;
	}
	this.setPollInterval(timerval);
	if (this._timeout) clearTimeout(this._timeout);
	var slot = this._getFreeSlot();
	if (slot < 0) return;
	if (typeof (this._req[slot]) != 'undefined' && typeof (this._req[slot].r) != 'undefined' && this._req[slot].r.readyState != 4) {
		this.oDbg.log("Slot " + slot + " is not ready");
		return;
	}
	if (!this.isPolling() && this._pQueue.length == 0 && this._req[(slot + 1) % 2] && this._req[(slot + 1) % 2].r.readyState != 4) {
		this.oDbg.log("all slots busy, standby ...", 2);
		return;
	}
	if (!this.isPolling()) this.oDbg.log("Found working slot at " + slot, 2);
	this._req[slot] = this._setupRequest(true);
	this._req[slot].r.onreadystatechange = JSJaC.bind(function () {
		if (!this.connected()) return;
		if (this._req[slot].r.readyState == 4) {
			this._setStatus('processing');
		//这里会接收服务器端响应的内容
			this.oDbg.log("async recv: " + this._req[slot].r.responseText, 4);
			this._handleResponse(this._req[slot]);
			if (this._pQueue.length) {
				this._timeout = setTimeout(JSJaC.bind(this._process, this), 100);
			} else {
				this.oDbg.log("scheduling next poll in " + this.getPollInterval() + " msec", 4);
				this._timeout = setTimeout(JSJaC.bind(this._process, this), this.getPollInterval());
			}
		}
	}, this);
	try {
		this._req[slot].r.onerror = JSJaC.bind(function () {
			if (!this.connected()) return;
			this._errcnt++;
			this.oDbg.log('XmlHttpRequest error (' + this._errcnt + ')', 1);
			if (this._errcnt > JSJAC_ERR_COUNT) {
				this._abort();
				return false;
			}
			this._setStatus('onerror_fallback');
			setTimeout(JSJaC.bind(this._resume, this), this.getPollInterval());
			return false;
		}, this);
	} catch (e) {}
	var reqstr = this._getRequestString();
	if (typeof (this._rid) != 'undefined') this._req[slot].rid = this._rid;
	this.oDbg.log("sending: " + reqstr, 4);
	this._req[slot].r.send(reqstr);
};

猜你喜欢

转载自hbiao68.iteye.com/blog/1997466