Smack是一個用於和XMPP服務器通訊的類庫,由此能夠實現即時通信和聊天。java
XMPPConnection connection = new XMPPConnection("jabber.org"); connection.login("mtucker", "password"); connection.createChat("jsmith@jivesoftware.com").sendMessage("Howdy!");
Smack的惟一必要條件是JDK 1.2 或更高版本。smack.jar文件已包含一個XML解析器,不須要其它第三方類庫。編程
XMPPConnection類用來創建到XMPP服務器的鏈接。要創建SSL鏈接,要使用SSLXMPPConnection類。服務器
下面是創建鏈接的例子:併發
// 創建一個到jabber.org服務器的鏈接。 XMPPConnection conn1 = new XMPPConnection("jabber.org"); // 經過一個特殊的端口創建一個到jabber.org服務器的鏈接。 XMPPConnection conn2 = new XMPPConnection("jabber.org", 5222); // 創建一個到jabber.org服務器的SSL鏈接。 XMPPConnection connection = new SSLXMPPConnection("jabber.org");
一旦您創建了一個鏈接,您必須經過方法XMPPConnection.login(String username, String password)使用用戶名和密碼登錄
框架
若是登錄成功,您能夠經過建立新的Chat或GroupChat對象和其它用戶聊天。 異步
Roster可以讓您跟蹤其它用戶的有效性(存在)ide
您能夠經過使用像「朋友」和「同事」這樣的組來組織用戶,這樣您能夠發現每一個用戶是否在線。this
使用XMPPConnection.getRoster()這個方法獲得Roster。編碼
經過Roster類您能夠找到全部Roster登錄、他們所屬的組以及每一個登錄當前的存在狀態。 spa
從客戶端以XML格式發送到XMPP服務器的每一個消息被稱爲一個「packet」。
org.jivesoftware.smack.packet包中包含了一些類,這些類封裝了XMPP所容許的三個不一樣的基本packet類型(message, presence, 和 IQ)。
像Chat和GroupChat這樣的類提供了更高類別的構造可以自動地建立和發送packet,可是您也能夠直接建立和發送packet。
下面是一個經過改變您的presence來讓別人知道您已無效,已經"out fishing"了:
// 建立一個新的presence. 傳入false以指示咱們已經無效了 Presence presence = new Presence(Presence.Type.UNAVAILABLE); presence.setStatus("Gone fishing"); // 發送packet (假設已經有了一個名爲"con"的XMPPConnection實例). con.sendPacket(presence);
Smack提供兩種方法讀取收到的packet:
往復地發送消息處於即時通信的核心地位。
兩個類輔助發送和接收消息:
Chat和 GroupCha類都是使用 org.jivesoftware.smack.packet.Message packet類來發送消息。
在某種特定狀況下,您可能不肯意使用高級的Chat和GroupChat類而直接發送和監聽消息。
一個chat在兩個用戶之間建立一個消息線程(經過線程ID)。
下面這段代碼演示了怎樣和用戶建立一個新的Chat並向他們發送一條文本消息:
// 假設咱們已經建立了一個名爲"connection"的XMPPConnection。 Chat newChat = connection.createChat("jsmith@jivesoftware.com"); newChat.sendMessage("Howdy!");
Chat.sendMessage(String)方法能夠方便地建立一個Message對象,用字符串參數設置消息正文,而後發送消息。
在必定狀況下您可能但願在發送消息前設置額外的值,使用Chat.createMessage()和 Chat.sendMessage(Message)方法,以下面代碼片斷所示:
// 假設咱們已經建立了一個名爲"connection"的XMPPConnection。 Chat newChat = connection.createChat("jsmith@jivesoftware.com"); Message newMessage = newChat.createMessage(); newMessage.setBody("Howdy!"); message.setProperty("favoriteColor", "red"); newChat.sendMessage(newMessage);
Chat對象可以讓您很容易監聽其它聊天參與者的回覆。
下面這段代碼演示的功能相似鸚鵡學舌--它將回復對方輸入的一切消息。
// 假設咱們已經建立了一個名爲"connection"的XMPPConnection。 Chat newChat = connection.createChat("jsmith@jivesoftware.com"); newMessage.setBody("Hi, I'm an annoying parrot-bot! Type something back to me."); while (true) { // 等待用戶發送給咱們的下一條消息。 Message message = newChat.nextMessage(); // 將對方發送過來的消息原樣發送給他。 newChat.sendMessage(message.getBody()); }
以上這段代碼使用了這個Chat.nextMessage() 方法獲得下一條消息,它將等待不肯定什麼時候到來的另外一條消息。
固然也有其它的方法用於等待特定時間段到來的新消息,或者您能夠添加一個監聽器,它將在每次有消息到來時通知您。
經過GroupChat鏈接到服務器上的聊天室,您能夠在一羣人中發送和接收消息。但在您發送或接收消息以前,您必須用一個暱稱加入聊天室。
下面這段代碼演示了鏈接到一個聊天室併發送一條消息:
// 假設咱們已經建立了一個名爲"connection"的XMPPConnection。 GroupChat newGroupChat = connection.createGroupChat("test@jivesoftware.com"); // 用暱稱"jsmith"加入這處羣。 newGroupChat.join("jsmith"); // 向聊天室中的其它人發送一條消息。 newGroupChat.sendMessage("Howdy!");
一般,在羣中發送和接收消息和在Chat類中很是類似。
同時還提供了用於獲得聊天室中其它人的列表的方法。
Smack提供靈活的框架來經過兩種構造處理收到的 packet:
packet監聽器用於事件樣式的編程,而packet收集器有一個能夠作輪詢和阻塞操做的packet的結果隊列。
因此,當您想對一個有可能隨時到來的packet採起一些操做時,使用packet監聽器;而當您想等待一個特別的packet到來時,使用packet收集器。
您可使用XMPPConnection實例建立packet收集器和監聽器。
org.jivesoftware.smack.filter.PacketFilter 接口決定哪一個特別的將會被傳遞到PacketCollector或PacketListener。
org.jivesoftware.smack.filter package包中有許多預約義的過濾器。
下面的代碼片斷演示註冊了一個packet收集器和一個packet 監聽器:
// 建立一個packet過濾器來監聽來自一個特定用戶的新的消息 //咱們可使用一個AndFilter來結合其它兩個過濾器。 PacketFilter filter = new AndFilter(new PacketTypeFilter(Message.class), new FromContainsFilter("mary@jivesoftware.com")); // 假設咱們已經建立了一個名爲"connection"的XMPPConnection。 // 首先,用咱們建立的過濾器註冊一個packet收集器。 PacketCollector myCollector = connection.createPacketCollector(filter); // 一般,您應該用收集器來些什麼,像等待新的packet。 // 接下來,建立一個packet監聽器。咱們能夠簡便地使用匿名內部類。 PacketListener myListener = new PacketListener() { public void processPacket(Packet packet) { // 在這裏用收到的packet作些什麼。 } }; // 註冊這個監聽器。 connection.addPacketListener(myListener, filter);
Smack包括豐富的packet 過濾器集,固然您能夠經過實現PacketFilter接口建立本身的過濾器。
默認的過濾器集包括:
Smack提供一個有效的機制,能夠向packet附加任意屬性。
每一個屬性有一個String名字,這是一個java簡單類型值(int, long, float, double, boolean)and a value that is a Java primitive () 或者任何序列化對象(java對象可序列化當它實現了Serializable接口)。
全部主要對象支持屬性,如Message對象。
下面的代碼顯示如何設置屬性:
Message message = chat.createMessage(); // 添加一個Color對象做爲屬性。 message.setProperty("favoriteColor", new Color(0, 0, 255)); // 添加一個int做爲屬性。 message.setProperty("favoriteNumber", 4); chat.sendMessage(message);
使用以下代碼得到這些屬性:
Message message = chat.nextMessage(); // 得到一個Color對象屬性。 Color favoriteColor = (Color)message.getProperty("favoriteColor"); // 得到一個intg屬性,注意屬性做爲對象返回,咱們必須把值轉換爲Integer,而後轉換爲int。 int favoriteNumber = ((Integer)message.getProperty("favoriteNumber")).intValue();
使用對象做爲屬性值是一個很是強大和容易的交換數據的方式。
然而,應該牢記以下:
當前用於發送屬性數據XML格式還不規範,因此極可能難以被不使用Smack的客戶端識別。
XML猶以下面所示(附清晰的註釋):
<!--某塊中的全部屬性。 --> <properties xmlns="http://www.jivesoftware.com/xmlns/xmpp/properties"> <!-- 首選,一個名爲"prop1"的integer型值。--> <property> <name>prop1</name> <value type="integer">123</value> <property> <!-- 其次,一個序列化的Java對象,而後從二進制數據轉換到base-64編碼的文本。 --> <property> <name>blah2</name> <value type="java-object">adf612fna9nab</value> <property> </properties>
前支持的類型有:integer, long, float, double, boolean, string, 和java對象。
roster能讓您跟蹤其它用戶的有效性(存在)。您能夠經過使用像「朋友」和「同事」這樣的組來組織用戶。
其它IM系統如朋友列表,聯繫列表引用roster。
一個roster實例經過XMPPConnection.getRoster()方法得到,但僅當成功登錄服務器以後對可用。
在roster中每一個用戶用一個RosterEntry表示,它包括:
下面的代碼片斷打印roster中的全部登錄:
Roster roster = con.getRoster(); for (Iterator i=roster.getEntries(); i.hasNext(); ) { System.out.println(i.next()); }
也可能用方法得到單個登錄,未定義登錄列表,或者得到一個或全部roster組。
roster中的每一個登錄有presence與之關聯。
Roster.getPresence(String user)方法能夠返回一個用戶Presence的對象,若是用戶不在線或您沒有預訂用戶的presence將會返回null。
注意:通常而言,presence預訂通常受用戶是否在roster中的約束,但這並不適應全部狀況。
一個用戶能夠有在線或離線兩種presence。
當用戶在線時,他們的可能包含外延信息,如他們正在作什麼,他們是否願意被打擾等等。參考Presence類以得到更多細節信息。
roster類的典型應用就是顯示組的樹型視圖和含有當前presence值的登錄。
presence信息極可能常常變化,roster登錄也可能常常改變或被刪除。
爲了監聽roster和presence數據的變化,應該使用RosterListener。
下面的代碼片斷註冊了一個roster的RosterListener,它可以在標準輸出中打印任何presence的變化。
一個標準的客戶端可使用相似的代碼用變化的信息來更新roster用戶界面。
final Roster roster = con.getRoster(); roster.addRosterListener(new RosterListener() { public void rosterModified() { // 這個例子中忽略這個事件。 } public void presenceChanged(String user) { // 若是presence無效,將會打印"null", // 這對本例來講很不錯。 System.out.println("Presence changed: " + roster.getPresence(user)); } });
roster和presence使用一種基於許可的模式,用戶只有在被許可的狀況下才能被添加到別人的roster中。
這樣能夠保護用戶的隱私由於只有經覈準的其它用戶才能查看他們的 presence信息。
所以,只有當其它用戶接受您的請求時您才能添加新的roster登錄。
若是一個用戶請求presence預訂,所以他們能夠把您添加到他們的roster中,您必須接受或拒絕該請求。
Smack經過如下三種方式中的一種處理presence預訂請求:
經過Roster.setSubscriptionMode(int subscriptionMode)方法設置對請求的處理方式。
簡易客戶端一般使用一種自動方式處理預訂請求,而複雜客戶端應該手動處理方式,請最終用戶接受或拒絕請求。
若是使用手動方式,應該註冊一個PacketListener以監聽Presence.Type.SUBSCRIBE類型的Presence packet。
Privacy是用戶阻擋其它個別用戶的通訊的方法。在XMPP中它經過操做隱私列表完成。
經過下面的用例服務器端隱私列表可以成功完成:
API實現有三個主公共類:
1.正確從頭開始,客戶端能夠得到他的/她的存儲在服務器上的隱私列表:
// 爲當前鏈接建立一個隱私管理器。 PrivacyListManager privacyManager = PrivacyListManager.getInstanceFor(myConnection); // 從新得到服務器隱私列表。 PrivacyList[] lists = privacyManager.getPrivacyLists();
正在客戶端可以顯示服務器的每一個PrivacyItem和每一個列表是不是活動的,默認或沒有。客戶端是一個隱私變化的監聽器。
2.要向服務器添加一個新列表,客戶端能夠像這樣執行:
// 設置列表的名稱 String listName = "newList"; // 建立PrivacyItem的列表,PrivacyItem將會容許或拒絕某些隱私方面。 String user = "tybalt@example.com"; String groupName = "enemies"; ArrayList privacyItems = new ArrayList(); PrivacyItem item = new PrivacyItem(PrivacyRule.JID, true, 1); item.setValue(user); privacyItems.add(item); item = new PrivacyItem(PrivacyRule.SUBSCRIPTION, true, 2); item.setValue(PrivacyRule.SUBSCRIPTION_BOTH); privacyItems.add(item); item = new PrivacyItem(PrivacyRule.GROUP, false, 3); item.setValue(groupName); item.setFilterMessage(true); privacyItems.add(item); // 得到當前鏈接的隱私管理器。 PrivacyListManager privacyManager = PrivacyListManager.getInstanceFor(myConnection); // 建立新列表。 privacyManager.createPrivacyList(listName, Arrays.asList(privacyItems));
3.修改一個已存的列表,客戶端代碼可能像這樣:
// 設置列表名稱 String listName = "existingList"; //得到當前鏈接的隱私管理器。 PrivacyListManager privacyManager = PrivacyListManager.getInstanceFor(myConnection); // 向服務器發送新列表。 privacyManager.updatePrivacyList(listName, items);
注意items在例2中定義而且必須包含列表中的全部元素(not the "delta")。
4.刪除一個已存在的列表,客戶端能夠像這樣執行:
// 設置列表名稱 String listName = "existingList"; // 得到當前鏈接的隱私管理器。 PrivacyListManager privacyManager = PrivacyListManager.getInstanceFor(myConnection); // 刪除列表。 privacyManager.deletePrivacyList(listName);
5.放棄活動列表的使用,客戶端能夠像這樣執行:
// 得到當前鏈接的隱私管理器。 PrivacyListManager privacyManager = PrivacyListManager.getInstanceFor(myConnection); // 放棄活動列表的使用。 privacyManager.declineActiveList();
6.放棄默認列表的使用,客戶端能夠像這樣執行:
// 得到當前鏈接的隱私管理器。 PrivacyListManager privacyManager = PrivacyListManager.getInstanceFor(myConnection); // 放棄默認列表的使用。 privacyManager.declineDefaultList();
爲了處理隱私變化,客戶端應該監聽管理器的更新。
當一個列表更改時管理器通知每一個已添加的監聽器。
監聽必須實現PrivacyListListener接口。當隱私列表被修改時客戶端可能須要做出反應。
PrivacyListManager讓您添加監聽器,它將在列表被改變時得知通知。監聽器應該實現PrivacyListListener接口
最重要的通知是updatedPrivacyList,它當隱私列表改變它的隱私項目時被執行。
當執行以下代碼監聽器能獲得通知:
// 得到當前鏈接的隱私管理器。 PrivacyListManager privacyManager = PrivacyListManager.getInstanceFor(myConnection); // 爲了獲得通知添加監聽器(this) privacyManager.addListener(this);