一、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.