openfire插件最佳实践(二)基于IQHandler 的Smack+openfire插件

简单插件开发已经讲解了简单的openfire插件怎样制作,本篇将会讲解如何实现一个简单的和客户端交互的插件。

首先我们要知道,openfire 的四种常用的插件集成方式:

1Component:可以接收一个特定子域(sub-domain)的所有包。比如test_componet.hoo.com。所以一个发送给jojo@test_componet.hoo.com的包将被转发给这个componet.

2IQHandler:相应包中特定的元素名或命名空间。下面的代码展示了如何注册一个IQHandler.

IQHandlermyHandler = new MyIQHander();

IQRouteriqRouter = XMPPServer.getInstance().getIQRouter();

iqRouter.addHandler(myHandler);

3PacketInterceptor:这种方式可以接收系统传输的所有包,并可以随意的丢弃它们。例如,一个interceptor可以拦截并丢弃所有含有不健康信息的消息,或者将它们报告给系统管理员。

4)使用JiveGlobals.getProperty(String) JiveGlobals.setProperty(String, String)方法将我们的插件设置为openfire的一个全局属性。通过实现org.jivesoftware.util.PropertyEventListener方法可以将我们的插件做成一个属性监听器监听任何属性的变化。通过PropertyEventDispatcher.addListener(PropertyEventListener)方法可以注册监听。要注意的一点是,一定要在destroyPlugin()方法中将注册的监听注销。

 

本篇文章将会主要使用IQHandler来实现openfire插件,有关使用PacketInterceptor实现可以参考文章:

http://www.cnblogs.com/hoojo/archive/2013/03/29/2988437.html

 

(一)确定客户端和服务器端进行通讯的IQ的样式

iq类型有四种:getseterrorresult

这里我们主要讨论get类型,其余类型的处理方式类似。

我们设计的客户端请求格式如下:

<iq id="H40yo-4" type="get"from="test@yourhost/Smack">

<username>111</username>

<query xmlns="hoo.iq.userinfo">

</query>

</iq>

服务器端返回格式如下:

<iq type="result" id="VKe0a-4"to="test@yourhost/Smack">

<query xmlns="hoo.iq.userinfos">

<username>111</username>

</query>

</iq>

(二)编写继承IQHandler的类,用于拦截来自客户端的IQ请求:

[java] view plaincopy

1.  package com.hoo.server.plugin;  

2.    

3.  import org.dom4j.DocumentHelper;  

4.  import org.dom4j.Element;    

5.  import org.dom4j.QName;  

6.  import org.jivesoftware.openfire.IQHandlerInfo;    

7.  import org.jivesoftware.openfire.XMPPServer;  

8.  import org.jivesoftware.openfire.auth.UnauthorizedException;    

9.  import org.jivesoftware.openfire.handler.IQHandler;    

10. import org.jivesoftware.openfire.session.ClientSession;  

11. import org.slf4j.Logger;  

12. import org.slf4j.LoggerFactory;  

13. import org.xmpp.packet.IQ;   

14. import org.xmpp.packet.PacketError;  

15.   

16. import com.hoo.server.plugin.entity.UserInfo;  

17. public class UserInfoIQHander extends IQHandler{  

18.     private static final Logger Log = LoggerFactory.getLogger(UserInfoIQHander.class);  

19.     private IQHandlerInfo info;   

20.     @Override  

21.     public void initialize(XMPPServer server) {  

22.         super.initialize(server);  

23.         dbUserInfoManager = DbUserInfoManager.getInstance();  

24.     }  

25.     public UserInfoIQHander() {    

26.         super("user info");    

27.         info = new IQHandlerInfo("query""hoo.iq.userinfo");  //这里和我们自定义的iq格式域相同  

28.     }    

29.     

30.     @Override    

31.     public IQHandlerInfo getInfo() {    

32.         return info;    

33.     }    

34.     

35.     @Override    

36.     public IQ handleIQ(IQ packet) throws UnauthorizedException {   

37.         System.out.println(packet.toXML());  

38.         IQ reply = null;  

[java] view plaincopy

1.   reply = IQ.createResultIQ(packet);//根据packet创建一个翻译iq</pre> try { ClientSession session = sessionManager.getSession(packet.getFrom()); if (session == null) { Log.error("Error  

2.   during userInfo. Session not found in " + sessionManager.getPreAuthenticatedKeys() + " for key " + packet.getFrom()); // This error packet will probably won't make it through

3.   reply.setChildElement(packet.getChildElement().createCopy()); 

4.  reply.setError(PacketError.Condition.internal_server_error);  

5.   return reply; } if (IQ.Type.get.equals(packet.getType())) { //获取数据 

6.  Element iq = packet.getElement(); //获取packet中的iq 

7.  Element query = iq.element("query"); //iq段中获取query

8.   Element username = query.element("username");

9.   String userNameStr = null; if(username!=null){  

10.  userNameStr = username.getText();//获取username段中的文字

11.  }else{ //没有传给我username reply.setChildElement(packet.getChildElement().createCopy()); 

12. reply.setError(PacketError.Condition.item_not_found);//为返回数据中填充错误信息 

13. return reply;

14.  } //在安卓端需要配置ProviderManager对数据进行解析 Element  

15.  probeResult = DocumentHelper.createElement(QName.get("query""hoo.iq.userinfo")) ; probeResult.addElement("username").setText("返回的username");return reply; }} catch (Exception e) {Log.error(e.getMessage(), e);  

16. reply.setChildElement(packet.getChildElement().createCopy());  

17. reply.setError(PacketError.Condition.internal_server_error);//远程服务器错误,客户端无法明确知道发生了什么,客户端也无需知道发生了什么。  

18. return reply;} 

19. return reply

20. } }

(三)在自定义的plugin中注册自定义IQHandler,只要在你的plugin类的initializePlugin方法中添加如下语句: 

21.  server.getIQRouter().addHandler(new UserInfoIQHander());   

这样在开启服务后,openfire就会自动监听hoo.iq.userinfo域的iq query请求。 

服务器端的编译和打包见上一篇文章。

(四)在客户端添加对hoo.iq.userinfo返回的数据的解析,首先自定义一个iq。

22. //自定义一个iq,用于接收和发送自定义iq</pre><pre code_snippet_id="134255" snippet_file_name="blog_20131230_5_2676678" name="code" class="java" style="color: rgb(51, 51, 51); font-size: 13px; line-height: 19px;">public class UserInfo extends IQ{  

23. private String username;  

24.   

25.   

26.     public String getElementName() {    

27.         return "query";    

28.     }    

29.     

30.     public String getNamespace() {    

31.         return "hoo.iq.userinfo";    

32.     }    

33.     

34.     public String getBody() {    

35.     StringBuilder sb = new StringBuilder();   

36.     if(null!=username){  

37.    sb.append("<username>").append(username).append("</username>");  

38.    }  

39.         return sb.toString();    

40.     }    

41. public String getUsername() {  

42. return username;  

43. }  

44.   

45.   

46. public void setUsername(String username) {  

47. this.username = username;  

48. }  

49.   

@Override    

50.     public String getChildElementXML() {    

51.         StringBuilder sb = new StringBuilder();    

52.         sb.append("<").append(getElementName()).append(" xmlns=\"").append(getNamespace()).append("\">").append(getBody()).append("</").append(getElementName()).append(">");    

53.         return sb.toString();    

54.     }    

55. }  

  

然后编写对服务器端传输来的数据进行解析的IQProvider  

56. import java.io.ByteArrayInputStream;  

57. import java.io.IOException;  

58.   

59. import javax.xml.parsers.DocumentBuilder;  

60. import javax.xml.parsers.DocumentBuilderFactory;  

61.   

62. import org.jivesoftware.smack.packet.IQ;  

63. import org.jivesoftware.smack.provider.IQProvider;  

64. import org.jivesoftware.smack.util.StringUtils;  

65. import org.w3c.dom.Document;  

66. import org.w3c.dom.Element;  

67. import org.w3c.dom.Node;  

68. import org.w3c.dom.NodeList;  

69. import org.xmlpull.v1.XmlPullParser;  

70. import org.xmlpull.v1.XmlPullParserException;  

71.   

72. import android.util.Log;  

73.   

74.   

75.   

76. public class UserInfoProvider implements IQProvider{  

77.   

78.     private static final String PREFERRED_ENCODING = "UTF-8";  

79.   

80. /***通过这个方法我们可以获取从服务器传来iq**/  

81.     public IQ parseIQ(XmlPullParser parser) throws Exception {  

82.         final StringBuilder sb = new StringBuilder();  

83.         try {  

84.             int event = parser.getEventType();  

85.             // get the content  

86.             while (true) {  

87.                 switch (event) {  

88.                     case XmlPullParser.TEXT:  

89.                         // We must re-escape the xml so that the DOM won't throw an exception  

90.                         sb.append(StringUtils.escapeForXML(parser.getText()));  

91.                         break;  

92.                     case XmlPullParser.START_TAG:  

93.                         sb.append('<').append(parser.getName()).append('>');  

94.                         break;  

95.                     case XmlPullParser.END_TAG:  

96.                         sb.append("</").append(parser.getName()).append('>');  

97.                         break;  

98.                     default:  

99.                 }  

100.      

101.                    if (event == XmlPullParser.END_TAG && "query".equals(parser.getName())) break;  

102.      

103.                    event = parser.next();  

104.                }  

105.            }  

106.            catch (XmlPullParserException e) {  

107.                e.printStackTrace();  

108.            }  

109.            catch (IOException e) {  

110.                e.printStackTrace();  

111.            }  

112.      

113.            String xmlText = sb.toString();  

114.            return new UserInfo();  

115.        }  

116.    }  

最后将IQProvider 在客户端注册下:在connect 时进行注册  

117.    ProviderManager.getInstance().addIQProvider("query""hoo.iq.userinfo"new UserInfoProvider());

 

(五)测试 

 

118.    在客户端拼接请求:  

119.    UserInfo b = newUserInfo ();  

120.    b.setUsername("111");

121.    b.setType(IQ.Type.GET);  

122.    PacketFilter filter = new AndFilter(new PacketIDFilter(  

123.    b.getPacketID()), new PacketTypeFilter(IQ.class));  

124.    PacketCollector collector = connection.createPacketCollector(filter);  

125.    connection.sendPacket(b);  

126.    UserInfo re = (UserInfo) collector.nextResult(SmackConfiguration.getPacketReplyTimeout());

127.    collector.cancel();// 停止请求results(是否成功的结果)System.out.println(re.toXML());


  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值