您的位置:首页 > 运维架构

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

2013-12-30 12:02 309 查看
简单插件开发已经讲解了简单的openfire插件怎样制作,本篇将会讲解如何实现一个简单的和客户端交互的插件。
首先我们要知道,openfire 的四种常用的插件集成方式:
(1)Component:可以接收一个特定子域(sub-domain)的所有包。比如test_componet.hoo.com。所以一个发送给jojo@test_componet.hoo.com的包将被转发给这个componet.
(2)IQHandler:相应包中特定的元素名或命名空间。下面的代码展示了如何注册一个IQHandler.
IQHandlermyHandler = new MyIQHander();
IQRouteriqRouter = XMPPServer.getInstance().getIQRouter();
iqRouter.addHandler(myHandler);
(3)PacketInterceptor:这种方式可以接收系统传输的所有包,并可以随意的丢弃它们。例如,一个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类型有四种:get、set、error、result。
这里我们主要讨论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());
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐