openfire插件IQHandle工作原理

来源:互联网 发布:五轴加工中心编程 编辑:程序博客网 时间:2024/06/05 04:16

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

public class AdtecPlugin implements Plugin {private XMPPServer server = XMPPServer.getInstance();@Overridepublic 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());}@Overridepublic void destroyPlugin() {// TODO Auto-generated method stubSystem.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);}@Overridepublic IQHandlerInfo getInfo() {return iqHandlerInfo;}@Overridepublic 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 packetInterceptorManager.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 errorIQ 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 packetInterceptorManager.getInstance().invokeInterceptors(packet, session, true, true);}catch (PacketRejectedException e) {if (session != null) {// An interceptor rejected this packet so answer a not_allowed errorIQ 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 sentif (e.getRejectionMessage() != null && e.getRejectionMessage().trim().length() > 0) {// A message for the rejection will be sent to the sender of the rejected packetMessage 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 hostnameif (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 packetmulticastRouter.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 serverIQResultListener 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 serversif (recipientJID != null &&(routingTable.hasComponentRoute(recipientJID) || routingTable.hasServerRoute(recipientJID))) {// A component/service/remote server was found that can handle the PacketroutingTable.routePacket(recipientJID, packet, false);return;}if (isLocalServer(recipientJID)) {// Let the server handle the PacketElement 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 namespaceLog.warn("Unknown packet " + packet.toXML());}}else {// Check if communication to local users is allowedif (recipientJID != null && userManager.isRegisteredUser(recipientJID.getNode())) {PrivacyList list =PrivacyListManager.getInstance().getDefaultPrivacyList(recipientJID.getNode());if (list != null && list.shouldBlockPacket(packet)) {// Communication is blockedif (IQ.Type.set == packet.getType() || IQ.Type.get == packet.getType()) {// Answer that the service is unavailablesendErrorPacket(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 namespacesendErrorPacket(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 nodesendErrorPacket(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 componentroutingTable.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请求再次发送到客户端,底层是socketdeliverer.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);};

 

0 0
原创粉丝点击