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); };