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


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章