Xmpp客戶端庫Smack(4.1.4)文檔整理

一、Smack庫概述

????Smack是一個開源畜吊、易用的XMPP/Jabber客戶端庫泽疆,它使用Java語言開發(fā),由Jive Software開發(fā)玲献。
????Smack的優(yōu)點是編程簡單殉疼。
????Smack的缺點是其API并非為大量并發(fā)用戶設(shè)計,每個客戶都要1個線程捌年,占用資源相對較大瓢娜,因此用Smack做模擬測試時,1臺機器只能模擬有限(數(shù)千個)客戶礼预。
????截止2015年10月25日眠砾,Smack庫已經(jīng)發(fā)展到4.1.4版。最新的好消息是Smack在4.1.0版后將直接支持Android系統(tǒng)托酸,而無需再使用以前的Smack移植版aSmack庫了荠藤。Smack庫源碼托管于GitHub,主頁見: https://github.com/igniterealtime/Smack/

1.1 Smack 4的改變

Smack庫從3.4版發(fā)展到4.0.x版后获高,其API有較大的變化哈肖,主要有:
??1. 把Connection類重命名為XMPPConnection類,XMPPConnection類是XMPPTCPConnection類和XMPPBOSHConnection類的父類念秧。
??2. 把各種Provider類進行了分包
??3. keep-alive(持久連接)機制從smack-core庫移到了smack-extensions庫,keep-alive機制現(xiàn)在由PingManager類提供淤井。
??4. PrivacyList類的toString()方法重命名為getName()
??5. 當(dāng)Chat實例的所有引用都撤掉后,應(yīng)該調(diào)用Chat.close()方法
否則Chat對象會有內(nèi)存泄露的隱患,直到ChatManager對象被垃圾回收器回收后內(nèi)存泄露隱患才會消失币狠。
??6. ServerTrustManager類被移除了,如果要使用帶SSL認(rèn)證的XMPP游两,你只需提供自己的SSLContext對象給ConnectionConfiguration對象即可。
??7. Packet.setProperty()從smack-core庫移到了smack-extensions庫,其API現(xiàn)在可以在org.jivesoftware.smackx.jiveproperties包中找到漩绵。
??8. Connection.getAccountManager()方法現(xiàn)在改成了AccountManager.getInstance(XMPPConnection)方法
??9. 異常API做了改進
??10.ToContains過濾器被移除了

1.2 Smack庫的組成

Smack庫可以內(nèi)嵌到任意的Java應(yīng)用程序中贱案。Smack庫有數(shù)個JAR文件組成,非常具有靈活性止吐。
??1. smack-core.jar提供了核心XMPP功能宝踪。都是XMPP RFC規(guī)范定義的XMPP特性。
??2. smack-extensions.jar支持許多由XMPP Standards Foundation定義的擴展(XEP)功能碍扔。包括群聊瘩燥、文件傳輸、用戶搜索等等不同。以后可查看文檔《擴展手冊》:https://github.com/igniterealtime/Smack/blob/master/documentation/extensions/index.html(目前還是無效的)
??3. smack-experimental.jar支持許多由XMPP Standards Foundation定義的體驗性(XEP)功能厉膀。其API和功能特性都被認(rèn)為是不穩(wěn)定的。
??4.smack-legacy.jar支持許多由XMPP Standards Foundation定義的遺留(XEP)功能二拐。
??5. smack-bosh.jar支持BOSH通信(XEP-0124規(guī)范定義的)服鹅。此代碼被認(rèn)為處于Beta階段。
??6. smack-jingle.jar支持Jingle百新。此代碼很老企软,目前處于無維護的狀態(tài)。
??7. smack-resolver-dnsjava.jar支持對DNS SRV記錄的解析吟孙,主要用于那些不支持javax.naming API的平臺。
??8. smack-debug.jar用于協(xié)議流量的增強型GUI調(diào)試器聚蝶。當(dāng)調(diào)試模式開啟后杰妓,如果它在類路徑下,它會自動被使用碘勉。以后可查看文檔《調(diào)試模式》:https://github.com/igniterealtime/Smack/blob/master/documentation/debugging.html(目前還是無效的)

二巷挥、Smack的配置

Smack的初始化過程涉及到2階段的調(diào)用。
??1.初始化系統(tǒng)屬性通過SmackConfiguration類初始化所有的系統(tǒng)可訪問屬性验靡,這些屬性都是通過getXXX方法取回屬性值的倍宾。
??2. 初始化啟動類如果繼承了SmackInitializer接口后,都可以在調(diào)用initialize()方法后得到初始化胜嗓,這意味著得到初始化的類在啟動后都是活動的高职。如果沒有繼承SmackInitializer接口,那么要實現(xiàn)初始化辞州,必須要放置一個靜態(tài)代碼塊來實現(xiàn)——他在類裝載時會自動執(zhí)行怔锌。初始化是通過配置文件來完成的。默認(rèn)情況下,Smack會載入Smack JAR文件中內(nèi)嵌的配置文件(它位于org.jivesoftware.smack/smack-config.xml)埃元。這個指定的配置文件包含了一系列需載入初始化的類列表涝涤。所有的管理器類型的類都需要被初始化,這些管理器類就包含在上面所說的初始化列表中岛杀。

三阔拳、XMPPConnection管理

3.1 創(chuàng)建連接

org.jivesoftware.smack.XMPPConnection類可管理到XMPP服務(wù)器的連接,它默認(rèn)的連接實現(xiàn)類是org.jivesoftware.smack.XMPPTCPConnection类嗤。它主要使用兩個構(gòu)造方法糊肠,
??一個是XMPPTCPConnection(StringserverName)方法,參數(shù)為服務(wù)器名土浸。連接會使用所有默認(rèn)的設(shè)置罪针,有:
????1)執(zhí)行DNSSRV查詢,找到服務(wù)器確切的地址和端口(通常是5222)黄伊。
????2)與服務(wù)器協(xié)商最大數(shù)安全泪酱,包括TLS加密。但如果有必要还最,連接會回落到較低的安全設(shè)置墓阀。
????3)XMPP資源名“Smack”會被用于連接。
??第二個是XMPPTCPConnection(ConnectionConfigurationcc)構(gòu)造器拓轻,它會指定高級的連接設(shè)置斯撮。其中包括:
????1)手動指定服務(wù)器地址和端口,而不是通過DNSSRV查詢扶叉。
????2)能開啟連接壓縮勿锅。
????3)指定自定義的連接資源名(如Work或Home)。用戶到服務(wù)器的每一個連接都必須有唯一的資源名枣氧。比如對于用戶"jsmith@example.com"溢十,完整的帶資源的地址應(yīng)該是"jsmith@example.com/Smack"。通過攜帶唯一的資源名达吞,用戶可以同時從不同的位置登錄到同一個服務(wù)器张弛,這適用于多設(shè)備的情況。每一個資源使用的在線優(yōu)先級值:用于決定由哪一個帶資源的指定連接來接收到地址"jsmith@example.com"的消息酪劫。

第一種連接方式:

    boolean target = false;  
    AbstractXMPPConnection conn = new XMPPTCPConnection(username, password, serverName);  
    try {  
        conn.connect();  
        target = conn.isConnected();  
        if(target){  
            System.out.println("XMPP 服務(wù)器連接成功");  
        }else{  
            System.out.println("XMPP 服務(wù)器連接不成功");  
        }  
    } catch (SmackException | IOException | XMPPException e) {  
        e.printStackTrace();  
    }  

第二種連接方式:

   boolean target=false;  
   XMPPTCPConnectionConfiguration config = XMPPTCPConnectionConfiguration.builder()  
                  .setUsernameAndPassword(username, password)  
                  .setServiceName(serverName)  
                  .setHost(serverName)  
                  .setPort(5222)  
                  .build();  
   AbstractXMPPConnection conn = new XMPPTCPConnection(config);  
        try {  
            conn.connect();  
            target = conn.isConnected();  
            if(target){  
                System.out.println("XMPP 服務(wù)器連接成功");  
            }else{  
                System.out.println("XMPP 服務(wù)器連接不成功");  
            }  
        } catch (SmackException | IOException | XMPPException e) {  
            e.printStackTrace();  
        }  

3.2 連接和關(guān)閉連接

//為新連接創(chuàng)建配置
ConnectionConfigurationconfig = new ConnectionConfiguration(“jabber.org”, 5222);
AbstractXMPPConnectionconn = new XMPPTCPConnection(config);
//連接到服務(wù)器
conn.connect();
//登錄到服務(wù)器
conn.login(“username”,“password”,“SomeResource”);
 
…
//關(guān)閉連接
conn.disconnect();

????默認(rèn)情況下吞鸭,一旦連接斷開,Smack會嘗試重建連接覆糟。使用ConnectionConfiguration類的setReconnectionAllowed(Boolean)方法可以開啟或關(guān)閉重連的功能刻剥。重連管理器會立即嘗試重連到服務(wù)器,并且會增加延時設(shè)置滩字,以便提高重連的成功率透敌。在重連管理器正在等待下一次重連的期間盯滚,如果你想強制重連,可以使用AbstractXMPPConnection類的connect()方法酗电,它會嘗試建立一個新連接魄藕。如果手動嘗試也失敗了,那么重連管理器會繼續(xù)重連的工作撵术。

四背率、使用Chat消息通信

????來回收發(fā)消息是即時通信的核心功能。盡管單條消息是以包的形式發(fā)送和接收的嫩与,通常還是把他視為聊天的消息字符串寝姿,使用org.jivesoftware.smack.Chat類。

4.1 Chat類

????一個聊天Chat會在兩個用戶之間創(chuàng)建一個消息線程(通過線程ID)划滋。下面的代碼片段演示了怎樣創(chuàng)建一個新聊天饵筑,然后向用戶發(fā)送一條文本消息:

  //假設(shè)已經(jīng)創(chuàng)建了一個名為"connection"的XMPPConnection
  ChatManager chatmanager = connection.getChatManager();
  Chat newChat = chatmanager.createChat("jsmith@jivesoftware.com", newMessageListener(){

    public void processMessage(Chat chat,Message message){
          System.out.println(“Receivedmessage: “+ message);
    }
  });
  try{
      newChat.sendMessage(“Howdy!”);
  }catch(XMPPExceptione){
      System.out.println(“Error Deliveringblock”);
  }

Chat.sendMessage(String)方法可以方便地創(chuàng)建一個消息Message對象,用字符串參數(shù)設(shè)置消息正文Body处坪,然后發(fā)送消息根资。在某些情況下你可能希望在發(fā)送消息前設(shè)置額外的值,使用Chat.createMessage()方法和Chat.sendMessage(Message)方法同窘,如下面的代碼片段所示:

   Message newMessage = new Message();
   newMessage.setBody(“Howdy!”);
   message.setProperty(“favoriteColor”,“red”);
   newChat.sendMessage(newMessage);

前面的例子中玄帕,我們可以注意到,在創(chuàng)建聊天Chat時指定了一個消息監(jiān)聽器MessageListener想邦,在任意時刻裤纹,當(dāng)來自其它用戶的聊天消息到達后,消息監(jiān)聽器會得到通知丧没。下面的代碼片段使用了監(jiān)聽器做鸚鵡學(xué)舌鹰椒,它會回顯來自其他用戶傳遞的消息。
//假設(shè)在聊天Chat中已經(jīng)設(shè)置了消息監(jiān)聽器MessageListener

   publicvoid processMessage(Chat chat, Message message){
       // 把用戶發(fā)送的消息內(nèi)容發(fā)送給用戶
       chat.sendMessage(message.getBody());
   }

4.2 來電聊天

????當(dāng)提示有另一個用戶的聊天消息到了后呕童,設(shè)置有輕微的不同漆际,因為你是首次接收到聊天消息。取代明確地創(chuàng)建一個Chat來發(fā)送消息拉庵,當(dāng)ChatManager創(chuàng)建了Chat實例后灿椅,你需要注冊處理新創(chuàng)建的Chat實例套蒂。ChatManager會通過線程ID找到匹配的Chat钞支,如果Chat不存在,那么它會創(chuàng)建一個新Chat對象來匹配操刀。要得到這個新Chat烁挟,你必須注冊來得到通知」强樱可以注冊一個消息監(jiān)聽器來接收所有要到來的消息撼嗓。

  //假定已經(jīng)創(chuàng)建了名為”connection”的XMPPConnection
  ChatManager  cm = connection.getChatManager().addChatListener(
   new ChatManagerListener(){
      @Override
      public void chatCreated(Chat chat, BooleancreatedLocally){
          if(!createdLocally)
              chat.addMessageListener(newMyNewMessageListener());
    }
});

????除了基于線程的Chat消息柬采,也有一些客戶端不發(fā)送線程ID作為Chat的一部分。要處理這種情況且警,Smack會基于JID嘗試匹配接收的消息到最匹配現(xiàn)有的Chat粉捻。它會嘗試用完整的JID來查找Chat,如果搜不到斑芜,再嘗試用基本的JID來查找Chat肩刃。如果找不到現(xiàn)有的Chat來匹配,那么會創(chuàng)建一個新Chat杏头。

五盈包、名單Roster和在線狀態(tài)Presence

名單可以讓你跟蹤其他用戶是否在線,而且名單可以讓你把用戶組織到群組醇王,比如朋友群或工作群呢燥。而其它的即時通信IM系統(tǒng)則把名單Roster視為好友列表、聯(lián)系人列表等等寓娩。

5.1 名單條目

????Roster用于跟蹤其他用戶是否在線叛氨。用戶的聯(lián)系人可以以分組的方式進行組織,比如“好友”根暑、“同事”力试。然后就可以查看組中的每個用戶是否在線了。要檢索Roster排嫌,使用XMPPConnection.getRoster()方法畸裳。Roster類允許你查找所有的Roster實體,以及他們屬于哪個組淳地,每個實體當(dāng)前的在線狀態(tài)怖糊。名單中的每一個用戶都由RosterEntry來表示,它包括:
????1)一個XMPP地址(比如”jsmith@example.com”)
????2)你為用戶編寫的備注姓名(比如”Joe”)
????3)名單中的群列表颇象。如果名單的條目不屬于任何群組伍伤,那么它被稱為"unfiledentry"。
下面的代碼片段會打印名單中所有的條目:

   //假定已經(jīng)創(chuàng)建了名為”connection”的XMPPConnection
   Rosterroster = connection.getRoster();
   Collection<RosterEntry>entries = roster.getEntries();
   for(RosterEntryentry : entries){
             System.out.println(entry);
   }

還有獲取單個條目的方法遣钳、獲取"unfiledentry"的方法扰魂,獲取一個群或所有群的方法。

5.2 在線狀態(tài)

????名單中的每個條目都有一個與之相關(guān)的在線狀態(tài)蕴茴。Roster.getPresence(Stringuser)方法會返回一個表示用戶是否在線的Presence對象劝评。如果為空是你還沒有訂閱用戶是否在線的返回。注意:通常情況下倦淀,在線狀態(tài)的訂閱總是綁定到名單中的用戶蒋畜,但這并不適應(yīng)所有的情況。
????一個用戶的在線狀態(tài)要么是在線撞叽,要么是離線姻成。當(dāng)用戶在線時插龄,他們的在線狀態(tài)還可以包含擴展的信息,比如用戶當(dāng)前正在做什么科展,用戶是否愿意被打擾等等均牢。具體參考Presence類。

5.3 監(jiān)聽名單Roster和在線狀態(tài)Presence的改變

????Roster類的典型應(yīng)用場景是以樹狀結(jié)構(gòu)顯示用戶群和列表才睹,并且用戶列表中包含用戶是否在線的狀態(tài)膨处。比如,參考下圖所示的一個ExodusXMPP客戶端的Roster砂竖。



????在線狀態(tài)的信息可能會經(jīng)常變化真椿,Roster條目也可能經(jīng)常修改或刪除。要監(jiān)聽Roster和Presence數(shù)據(jù)的變化乎澄,你應(yīng)該使用RosterListener突硝。要得到Roster改變的所有提醒,那么必須在登錄XMPP服務(wù)器之前注冊RosterListener置济。下面的代碼片段注冊了一個Roster的RosterListener解恰,它能夠在標(biāo)準(zhǔn)輸出中打印任何Presence的改變。一個標(biāo)準(zhǔn)的客戶端可以使用類似的代碼用變化的信息來更新Roster界面浙于。

   //假定已經(jīng)創(chuàng)建了名為”connection”的XMPPConnection
   Roster roster = connection.getRoster();
   roster.addRosterListener(new RosterListener(){
       // 忽略事件
       public void entriesAdded(Collection<String> addresses){}

       public void entriesDeleted(Collection<String>addresses){}

       public void entriesUpdated(Collection<String> addresses){}

       public void presenceChanged(Presencepresence){
           System.out.println(“Presencechanged: “+ presence.getFrom() + “ “ + presence);
    }
});

5.4 添加Entries到Roster

????Roster和Presence使用一種基于權(quán)限的模型护盈,用戶必須得到其他人的許可才能把這些人添加到Roster。這樣可以保護用戶的隱私羞酗,確保了只有獲得同意的用戶才能查看到他們的Presence信息腐宋。因此,當(dāng)你想添加某個用戶到你的Roster中檀轨,必須得到該用戶接受你的請求才可以胸竞。
如果有用戶請求訂閱你的在線狀態(tài)Presence,這個用戶必須先把你添加到他的Roster参萄,因此他會發(fā)起請求卫枝,你必須選擇接受或拒絕該請求。Smack通過以下三種方式來處理Presence的預(yù)訂請求:
????1)自動接受所有Presence的預(yù)訂請求
????2)自動拒絕所有Presence的預(yù)訂請求
????3)手動處理每一個Presence預(yù)訂請求
????這三種方式可以通過Roster.setSubscriptionMode(intsubscriptionMode)方法來設(shè)置請求的處理方式讹挎。簡單的客戶端通常使用第一種自動方式處理預(yù)訂請求校赤,而功能比較全的客戶端應(yīng)該選擇第三種手動處理請求的方式,讓終端用戶自行決定是接受請求或是拒絕請求筒溃。如果使用手動方式马篮,應(yīng)該注冊一個PacketListener來監(jiān)聽Presence.Type.SUBSCRIBE類型的Presence包。

六铡羡、讀寫Packet(數(shù)據(jù)包)

????從客戶端發(fā)送到XMPP服務(wù)器的每一條消息都稱為一個Packet(數(shù)據(jù)包)积蔚。org.jivesoftware.smack.packet庫中包含了XMPP支持的消息Message意鲸、在線狀態(tài)Presence烦周、IQ)三種不同的基本數(shù)據(jù)包類型的封裝類尽爆。而像Chat或GroupChat這樣的類則提供了更高層的結(jié)構(gòu)來管理數(shù)據(jù)包的自動創(chuàng)建和發(fā)送。但是读慎,開發(fā)者還是可以直接創(chuàng)建和發(fā)送數(shù)據(jù)包的漱贱。下面的代碼就是修改自己的在線狀態(tài),讓其他人知道你不在線夭委。

   //假設(shè)已經(jīng)創(chuàng)建了一個名為"connection"的XMPPConnection
   Presence presence = new Presence(Presence.Type.unavailable);  
   presence.setStatus("Gone fishing");  

   connection.sendStanza(presence);  

6.1 PacketListener與PacketCollector

Smack提供了兩種讀取到來的數(shù)據(jù)包的方式:
????org.jivesoftware.smack.PacketCollector(包收集器):該類提供synchronously(同步)方法幅狮,等待接受數(shù)據(jù)包(Packets).
????org.jivesoftware.smack.PacketListener(包監(jiān)聽器): 該接口提供asynchronously(異步)方法,等待結(jié)束數(shù)據(jù)(Packets)株灸。
????兩者都使用PacketFilter實例來判斷應(yīng)該處理哪一個數(shù)據(jù)包崇摄。PacketListener(包監(jiān)聽器)用于事件風(fēng)格的編程,而PacketCollector(包收集器)有一個數(shù)據(jù)包的結(jié)果隊列慌烧,你可以做輪詢或阻塞等操作逐抑。也就是說,如果你想在數(shù)據(jù)包到來時執(zhí)行一些動作屹蚊,那么包監(jiān)聽器很適合厕氨。如果你想等待指定的數(shù)據(jù)包的到來,那么包收集器很適合汹粤。包收集器和包監(jiān)聽器都使用Connection連接實例創(chuàng)建命斧。
????數(shù)據(jù)包集合(PacketCollector)和數(shù)據(jù)包接口(PacketListener)是通過XMPPConnection實例對象創(chuàng)建。

6.2 攔截器

????org.jivesoftware.smack.filter.StanzaFilter接口可以決定,那些特定的數(shù)據(jù)包會被傳遞到PacketCollector 或者PacketListener嘱兼。
許多預(yù)先定義的攔截器都實現(xiàn)了org.jivesoftware.smack.filter接口国葬。

下面的代碼片段,演示了注冊的數(shù)據(jù)包監(jiān)聽器和數(shù)據(jù)包集合

// Create a packet filter to listen for new messages from a particular  
// user. We use an AndFilter to combine two other filters._  
StanzaFilter filter = new AndFilter(new StanzaTypeFilter(Message.class),  
        new FromContainsFilter("mary@jivesoftware.com"));  

// Assume we've created an XMPPConnection name "connection".  
// First, register a packet collector using the filter we created.  
PacketCollector myCollector = connection.createPacketCollector(filter);  

// Normally, you'd do something with the collector, like wait for new packets.   
// Next, create a packet listener. We use an anonymous inner class for brevity.
PacketListener myListener = new PacketListener() {  
        **public** **void** processPacket(Packet packet) {  
            // Do something with the incoming packet here._  
        }  
    };  
// Register the listener._  
connection.addPacketListener(myListener, filter);  

標(biāo)準(zhǔn)段落(字符)攔截器
????smack 類庫中已經(jīng)包含很多包攔截器芹壕,你也可以創(chuàng)建屬于自己的攔截器胃惜,只需要代碼實現(xiàn)StanzaFilter接口,默認(rèn)的攔截器包含如下:

  • StanzaTypeFilter --特定類型的數(shù)據(jù)包過濾器
  • StanzaIdFilter -- 特定數(shù)據(jù)包標(biāo)識篩選器
  • ThreadFilter -- 特定線程標(biāo)識數(shù)據(jù)包過濾器
  • ToContainsFilter -- 特定發(fā)送地址數(shù)據(jù)包過濾器
  • FromContainsFilter -- 特定接受地址數(shù)據(jù)包過濾器.
  • StanzaExtensionFilter -- 特定包擴展數(shù)據(jù)包過濾器
  • AndFilter -- implements the logical AND operation over two filters.
  • OrFilter -- implements the logical OR operation over two filters.
  • NotFilter -- implements the logical NOT operation on a filter.

七哪雕、信息包插件提供者

????Smack提供的體系是堵塞自定義的XML信息包擴展和IQ包分析器的系統(tǒng)(The Smack provider architecture is a system for plugging in custom XML parsing of packet extensions and IQ packets)船殉。標(biāo)準(zhǔn)的Smack擴展(Smack Extensions)是使用提供者的體系結(jié)構(gòu)搭建的。存在以下兩種類型的提供者:

  • IQProvider –將IQ請求( IQ requests)解析成Java對象(Java objects)
  • PacketExtension – 將附屬在信息包上的XML子文檔解析成信息包擴展實例(PacketExtension instances)

7.1 IQProvider

???? IQProvider 默認(rèn)情況下斯嚎,Smack只知道如何處理類似以下幾個名字空間的子信息包的IQ信息包(IQ packets):
???? jabber:iq:auth
???? jabber:iq:roster
???? jabber:iq:register
因為許多IQ類型是XMPP及其擴展部分的一部分利虫,所以提供一個可插入的IQ分析機制。IQ Providers被程序自動的注冊或通過創(chuàng)建在你的JAR 文件的META-INF目錄下創(chuàng)建一個mack.providers文件堡僻。該文件是一個包含一個或多個iqProvider條目(iqProvider entries)的XML文檔糠惫,如下例所示:

<?xml version="1.0"?>  
<smackProviders>
       <iqProvider>          
                <elementName>query</elementName>          
                <namespace>jabber:iq:time</namespace>          
                <className>org.jivesoftware.smack.packet.Time</className>      
       </iqProvider> 
</smackProviders>  

????每一個IQ provider都和一個元素名(element name)和名字空間( namespace)相聯(lián)系。在上面的例子中钉疫,元素名是query硼讽,名字空間是abber:iq:time。如果有多重提供者條目(multiple provider entries)嘗試注冊并控制相同的名字空間牲阁,那么從類路徑(classpath)載入的第一個條目將有優(yōu)先權(quán)固阁。
????IQ provider類可以實現(xiàn)IQProvide接口壤躲,或者繼承IQ類。在前面的例子中备燃,每一個IQProvider負(fù)責(zé)解析原始的XML流從而創(chuàng)建一個IQ實例碉克。在下面的例子中,bean introspection將被用于嘗試自動使用在IQ packet XML中發(fā)現(xiàn)的值設(shè)置IQ實例的屬性并齐。一個XMPP時間信息包如下所示:

<iq type=’result’ to=’joe@example.com’ from=’mary@example.com’ id=’time_1’>    
     <query xmlns=’jabber:iq:time’>         
          <utc>20020910T17:58:35</utc>         
          <tz>MDT</tz>         
          <display>Tue Sep 10 12:58:35 2002</display>     
    </query> 
</iq>  

????為了讓這個信息包自動的映射成上面的providers file中所列的時間對象(Time object)漏麦,它必須有以下幾個方法:setUtc(String), setTz(String), 和 setDisplay(String)。自動檢查(introspection)的服務(wù)將試著自動的將字符串值轉(zhuǎn)化成a boolean, int, long, float, double,或 Class 類型况褪。轉(zhuǎn)化成何種類型由IQ實例的需要來決定撕贞。

7.2 PacketExtensionProvider

????PacketExtensionProvider 信息包插件提供者(Packet extension providers)為信息包提供一個可插入的系統(tǒng),這些信息包是一個IQ, message和presence packets的自定義名字空間的子元素测垛。每一個插件提供者(extension provider)使用一個元素名(element name)和名字空間(namespace)在smack.providers文件中注冊麻掸,如下例所示:

 <?xml version="1.0"?> 
      <smackProviders>    
             <extensionProvider>        
                     <elementName>x</elementName>         
                     <namespace>jabber:iq:event</namespace>
 <className>org.jivesoftware.smack.packet.MessageEvent</className>
               </extensionProvider> 
</smackProviders>  

????如果有多重提供者條目(multiple provider entries)嘗試注冊并控制相同的名字空間,那么從類路徑(classpath)載入的第一個條目將有優(yōu)先權(quán)赐纱。 一旦在一個信息包中發(fā)現(xiàn)信息包插件脊奋,解析器將傳遞到正確的提供者。每一個提供者可以實現(xiàn)PacketExtensionProvider接口或者是一個標(biāo)準(zhǔn)的Java Bean疙描。在前面的例子中诚隙,每一個插件提供者(extension provider)負(fù)責(zé)解析原始的XML流去構(gòu)造一個實例。在下面的例子中起胰,bean introspection將被用于嘗試自動使用在信息包插件子元素(packet extension sub-element)中的值設(shè)置類的屬性久又。 當(dāng)一個插件提供者(extension provider)沒有用元素名(element name)和名字空間(namespace)對注冊是,Smack將存儲所有在缺省信息包插件(DefaultPacketExtension)對象中的最高級別元素(top-level elements)效五,并匹配到信息包上地消。

七、smack debug模式講解

????smakc 內(nèi)置兩套debuging 控制臺畏妖,讓你追蹤XMPP服務(wù)端和客戶端之間所有XML 流動脉执,在smack-debug.jar包含Lite調(diào)試器和增強調(diào)試器,在smack-core.jar包含debug輸出控制臺戒劫。
調(diào)試模式可以用不同的方式來啟用:
1半夷、在創(chuàng)建新連接之前,先添加以下代碼行:

SmackConfiguration.DEBUG = true;  

1迅细、設(shè)置Java系統(tǒng)屬性smack.debugenabled真實巫橄。可以在命令行上設(shè)置系統(tǒng)屬性茵典,例如:

java -Dsmack.debugEnabled=true SomeApp  

如果你希望在你的應(yīng)用程序中顯式禁用調(diào)試模式湘换,可以通過使用命令行參數(shù) 或者是在在打開新連接之前,請在應(yīng)用程序中添加以下行:

SmackConfiguration.DEBUG = false;  

smack 使用以下邏輯決定調(diào)試控制臺使用;
1、它首先會嘗試使用在Java系統(tǒng)屬性指定類smack.debuggerclass調(diào)試器彩倚。如果你需要開發(fā)屬于自己的Debug筹我,需要smackdebugger接口,然后設(shè)置系統(tǒng)屬性的命令行如:

java -Dsmack.debuggerClass=my.company.com.MyDebugger SomeApp  

2署恍、如果第一步失敗,Smack會嘗試使用增強型Debug,smackx-debug.jar文件中包含了增強型Debug蜻直,因此盯质,你需要將jar文件的路徑添加到ClassPath路徑中。smack-core.jar Lite調(diào)試器和增強調(diào)試器不可用的情況下概而,只有控制臺調(diào)試器呼巷。

增強調(diào)試器



????當(dāng)smack Debug模式是啟動時,Debug窗口會顯示每一個創(chuàng)建連接信息赎瑰,同時也包含以下信息:

  • XMPPConnection tabs -- 每個選項卡顯示有關(guān)連接的調(diào)試信息.
  • Smack info tab -- shows information about Smack (e.g. Smack version, installed components, etc.). The connection tab will contain the following information:
  • All Stanzas --通過smack 分析發(fā)送和接收的數(shù)據(jù)包的信息分析.
  • Raw Sent Stanzas -- 通過Smack產(chǎn)生的原始XML流量發(fā)送到服務(wù)器.
  • Raw Received Stanzas -- 服務(wù)器向客戶端發(fā)送的原始XML.
  • Ad-hoc message -- 允許發(fā)送特定類型的數(shù)據(jù)包.
  • Information -- 顯示連接狀態(tài)和統(tǒng)計數(shù).

Lite Debugger



????當(dāng)smack Debug模式是啟動時王悍,Debug窗口會顯示每一個創(chuàng)建連接信息,同時也包含以下信息:

  • Client Traffic (red text) -- 通過Smack產(chǎn)生的原始XML流量發(fā)送到服務(wù)器.
  • Server Traffic (blue text) --服務(wù)器向客戶端發(fā)送的原始XML.
  • Interpreted Stanzas (green text) -- shows XML packets from the server as parsed by Smack. Right click on any of the panes to bring up a menu with the choices to copy of the contents to the system clipboard or to clear the contents of the pane.
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末餐曼,一起剝皮案震驚了整個濱河市压储,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌源譬,老刑警劉巖集惋,帶你破解...
    沈念sama閱讀 206,214評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異踩娘,居然都是意外死亡刮刑,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評論 2 382
  • 文/潘曉璐 我一進店門养渴,熙熙樓的掌柜王于貴愁眉苦臉地迎上來雷绢,“玉大人,你說我怎么就攤上這事理卑∏涛桑” “怎么了?”我有些...
    開封第一講書人閱讀 152,543評論 0 341
  • 文/不壞的土叔 我叫張陵藐唠,是天一觀的道長霞溪。 經(jīng)常有香客問我,道長中捆,這世上最難降的妖魔是什么鸯匹? 我笑而不...
    開封第一講書人閱讀 55,221評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮泄伪,結(jié)果婚禮上殴蓬,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好染厅,可當(dāng)我...
    茶點故事閱讀 64,224評論 5 371
  • 文/花漫 我一把揭開白布痘绎。 她就那樣靜靜地躺著,像睡著了一般肖粮。 火紅的嫁衣襯著肌膚如雪徽千。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,007評論 1 284
  • 那天署惯,我揣著相機與錄音烫沙,去河邊找鬼。 笑死魂那,一個胖子當(dāng)著我的面吹牛蛾号,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播涯雅,決...
    沈念sama閱讀 38,313評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼鲜结,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了活逆?” 一聲冷哼從身側(cè)響起精刷,我...
    開封第一講書人閱讀 36,956評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎蔗候,沒想到半個月后贬养,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,441評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡琴庵,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,925評論 2 323
  • 正文 我和宋清朗相戀三年误算,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片迷殿。...
    茶點故事閱讀 38,018評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡儿礼,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出庆寺,到底是詐尸還是另有隱情蚊夫,我是刑警寧澤,帶...
    沈念sama閱讀 33,685評論 4 322
  • 正文 年R本政府宣布懦尝,位于F島的核電站知纷,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏陵霉。R本人自食惡果不足惜琅轧,卻給世界環(huán)境...
    茶點故事閱讀 39,234評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望踊挠。 院中可真熱鬧乍桂,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至憋沿,卻和暖如春旺芽,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背辐啄。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評論 1 261
  • 我被黑心中介騙來泰國打工采章, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人则披。 一個月前我還...
    沈念sama閱讀 45,467評論 2 352
  • 正文 我出身青樓共缕,卻偏偏與公主長得像洗出,于是被迫代替她去往敵國和親士复。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,762評論 2 345

推薦閱讀更多精彩內(nèi)容