/** | |||
matt | 1.2 | 2 | * $RCSfile: Roster.java,v $ |
matt | 1.6 | 3 | * $Revision: 1.6 $ |
4 | * $Date: 2005/03/10 22:35:03 $ | ||
matt | 1.1 | 5 | * |
6 | * Copyright 2004 Jive Software. | ||
7 | * | ||
8 | * All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); | ||
9 | * you may not use this file except in compliance with the License. | ||
10 | * You may obtain a copy of the License at | ||
11 | * | ||
12 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
13 | * | ||
14 | * Unless required by applicable law or agreed to in writing, software | ||
15 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
17 | * See the License for the specific language governing permissions and | ||
18 | * limitations under the License. | ||
19 | */ | ||
20 | |||
21 | package org.xmpp.packet; | ||
22 | |||
23 | import org.dom4j.*; | ||
24 | |||
25 | import java.util.*; | ||
26 | |||
27 | |||
28 | /** | ||
29 | * Roster packet. The roster is a list of JIDs (typically other users) that | ||
30 | * the user wishes to track the presence of. Each roster item is keyed by | ||
31 | * JID and contains a nickname (optional), subscription type, and list of | ||
32 | * groups (optional). | ||
33 | * | ||
34 | * Matt Tucker | ||
35 | */ | ||
36 | public class Roster extends IQ { | ||
37 | |||
38 | /** | ||
39 | * Constructs a new Roster with an automatically generated ID and a type | ||
40 | * of { Type#get IQ.Type.get}. | ||
41 | */ | ||
42 | public Roster() { | ||
43 | super(); | ||
44 | element.addElement("query", "jabber:iq:roster"); | ||
45 | } | ||
46 | |||
47 | /** | ||
48 | * Constructs a new Roster using the specified type. A packet ID will | ||
49 | * be automatically generated. | ||
50 | * | ||
51 | * type the IQ type. | ||
52 | */ | ||
53 | public Roster(Type type) { | ||
54 | super(type); | ||
55 | element.addElement("query", "jabber:iq:roster"); | ||
56 | } | ||
57 | |||
58 | /** | ||
59 | * Constructs a new Roster using the specified type and ID. | ||
60 | * | ||
61 | * type the IQ type. | ||
62 | * ID the packet ID of the IQ. | ||
63 | */ | ||
64 | public Roster(Type type, String ID) { | ||
65 | super(type, ID); | ||
66 | element.addElement("query", "jabber:iq:roster"); | ||
67 | } | ||
68 | |||
69 | /** | ||
matt | 1.6 | 70 | * Constructs a new Roster that is a copy of an existing Roster. |
71 | * | ||
72 | * roster the roster packet. | ||
73 | * #createCopy() | ||
74 | */ | ||
75 | private Roster(Roster roster) { | ||
76 | Element elementCopy = roster.element.createCopy(); | ||
77 | docFactory.createDocument().add(elementCopy); | ||
78 | this.element = elementCopy; | ||
79 | } | ||
80 | |||
81 | /** | ||
matt | 1.1 | 82 | * Constructs a new Roster using an existing Element. This is useful |
83 | * for parsing incoming roster Elements into Roster objects. | ||
84 | * | ||
85 | * element the Roster Element. | ||
86 | */ | ||
87 | public Roster(Element element) { | ||
88 | super(element); | ||
89 | } | ||
90 | |||
91 | /** | ||
92 | * Adds a new item to the roster. The name and groups are set to <tt>null</tt> | ||
93 | * If the roster packet already contains an item using the same JID, the | ||
94 | * information in the existing item will be overwritten with the new information.<p> | ||
95 | * | ||
96 | * The XMPP specification recommends that if the roster item is associated with another | ||
97 | * instant messaging user (human), that the JID be in bare form (e.g. user ). | ||
98 | * Use the { JID#toBareJID() toBareJID()} method for a bare JID. | ||
99 | * | ||
100 | * jid the JID. | ||
101 | * subscription the subscription type. | ||
gaston | 1.3 | 102 | * the newly created item. |
matt | 1.1 | 103 | */ |
gaston | 1.3 | 104 | public Item addItem(String jid, Subscription subscription) { |
matt | 1.1 | 105 | if (getType() == IQ.Type.get || getType() == IQ.Type.error) { |
106 | throw new IllegalStateException("IQ type must be 'result' or 'set'"); | ||
107 | } | ||
108 | if (jid == null) { | ||
109 | throw new NullPointerException("JID cannot be null"); | ||
110 | } | ||
gaston | 1.3 | 111 | return addItem(new JID(jid), null, null, subscription, null); |
matt | 1.1 | 112 | } |
113 | |||
114 | /** | ||
115 | * Adds a new item to the roster. The name and groups are set to <tt>null</tt> | ||
116 | * If the roster packet already contains an item using the same JID, the | ||
117 | * information in the existing item will be overwritten with the new information.<p> | ||
118 | * | ||
119 | * The XMPP specification recommends that if the roster item is associated with another | ||
120 | * instant messaging user (human), that the JID be in bare form (e.g. user ). | ||
121 | * Use the { JID#toBareJID() toBareJID()} method for a bare JID. | ||
122 | * | ||
123 | * jid the JID. | ||
124 | * subscription the subscription type. | ||
gaston | 1.3 | 125 | * the newly created item. |
matt | 1.1 | 126 | */ |
gaston | 1.3 | 127 | public Item addItem(JID jid, Subscription subscription) { |
gaston | 1.5 | 128 | if (getType() != IQ.Type.result && getType() != IQ.Type.set) { |
matt | 1.1 | 129 | throw new IllegalStateException("IQ type must be 'result' or 'set'"); |
130 | } | ||
131 | if (jid == null) { | ||
132 | throw new NullPointerException("JID cannot be null"); | ||
133 | } | ||
gaston | 1.3 | 134 | return addItem(jid, null, null, subscription, null); |
matt | 1.1 | 135 | } |
136 | |||
137 | /** | ||
138 | * Adds a new item to the roster. If the roster packet already contains an item | ||
139 | * using the same JID, the information in the existing item will be overwritten | ||
140 | * with the new information.<p> | ||
141 | * | ||
142 | * The XMPP specification recommends that if the roster item is associated with another | ||
143 | * instant messaging user (human), that the JID be in bare form (e.g. user ). | ||
144 | * Use the { JID#toBareJID() toBareJID()} method for a bare JID. | ||
145 | * | ||
146 | * jid the JID. | ||
147 | * name the nickname. | ||
gaston | 1.3 | 148 | * ask the ask type. |
matt | 1.1 | 149 | * subscription the subscription type. |
150 | * groups a Collection of groups. | ||
gaston | 1.3 | 151 | * the newly created item. |
matt | 1.1 | 152 | */ |
gaston | 1.3 | 153 | public Item addItem(JID jid, String name, Ask ask, Subscription subscription, |
154 | Collection<String> groups) | ||
matt | 1.1 | 155 | { |
156 | if (jid == null) { | ||
157 | throw new NullPointerException("JID cannot be null"); | ||
158 | } | ||
159 | if (subscription == null) { | ||
160 | throw new NullPointerException("Subscription cannot be null"); | ||
161 | } | ||
162 | Element query = element.element(new QName("query", Namespace.get("jabber:iq:roster"))); | ||
163 | if (query == null) { | ||
164 | query = element.addElement("query", "jabber:iq:roster"); | ||
165 | } | ||
166 | Element item = null; | ||
167 | for (Iterator i=query.elementIterator("item"); i.hasNext(); ) { | ||
168 | Element el = (Element)i.next(); | ||
169 | if (el.attributeValue("jid").equals(jid.toString())) { | ||
170 | item = el; | ||
171 | } | ||
172 | } | ||
173 | if (item == null) { | ||
174 | item = query.addElement("item"); | ||
175 | } | ||
gaston | 1.5 | 176 | item.addAttribute("jid", jid.toBareJID()); |
matt | 1.1 | 177 | item.addAttribute("name", name); |
gaston | 1.3 | 178 | if (ask != null) { |
179 | item.addAttribute("ask", ask.toString()); | ||
180 | } | ||
matt | 1.1 | 181 | item.addAttribute("subscription", subscription.toString()); |
182 | // Erase existing groups in case the item previously existed. | ||
183 | for (Iterator i=item.elementIterator("group"); i.hasNext(); ) { | ||
184 | item.remove((Element)i.next()); | ||
185 | } | ||
186 | // Add in groups. | ||
187 | if (groups != null) { | ||
188 | for (String group : groups) { | ||
189 | item.addElement("group").setText(group); | ||
190 | } | ||
191 | } | ||
gaston | 1.3 | 192 | return new Item(jid, name, ask, subscription, groups); |
matt | 1.1 | 193 | } |
194 | |||
195 | /** | ||
196 | * Removes an item from this roster. | ||
197 | * | ||
198 | * jid the JID of the item to remove. | ||
199 | */ | ||
200 | public void removeItem(JID jid) { | ||
201 | Element query = element.element(new QName("query", Namespace.get("jabber:iq:roster"))); | ||
202 | if (query != null) { | ||
203 | for (Iterator i=query.elementIterator("item"); i.hasNext(); ) { | ||
204 | Element item = (Element)i.next(); | ||
205 | if (item.attributeValue("jid").equals(jid.toString())) { | ||
206 | query.remove(item); | ||
207 | return; | ||
208 | } | ||
209 | } | ||
210 | } | ||
211 | } | ||
212 | |||
213 | /** | ||
214 | * Returns an unmodifiable copy of the { Item Items} in the roster packet. | ||
215 | * | ||
216 | * an unmodifable copy of the { Item Items} in the roster packet. | ||
217 | */ | ||
218 | public Collection<Item> getItems() { | ||
219 | Collection<Item> items = new ArrayList<Item>(); | ||
220 | Element query = element.element(new QName("query", Namespace.get("jabber:iq:roster"))); | ||
221 | if (query != null) { | ||
222 | for (Iterator i=query.elementIterator("item"); i.hasNext(); ) { | ||
223 | Element item = (Element)i.next(); | ||
224 | String jid = item.attributeValue("jid"); | ||
225 | String name = item.attributeValue("name"); | ||
gaston | 1.3 | 226 | String ask = item.attributeValue("ask"); |
matt | 1.1 | 227 | String subscription = item.attributeValue("subscription"); |
228 | Collection<String> groups = new ArrayList<String>(); | ||
229 | for (Iterator j=item.elementIterator("group"); j.hasNext(); ) { | ||
230 | Element group = (Element)j.next(); | ||
231 | groups.add(group.getTextTrim()); | ||
232 | } | ||
gaston | 1.4 | 233 | Ask askStatus = ask == null ? null : Ask.valueOf(ask); |
234 | Subscription subStatus = subscription == null ? | ||
235 | null : Subscription.valueOf(subscription); | ||
236 | items.add(new Item(new JID(jid), name, askStatus, subStatus, groups)); | ||
matt | 1.1 | 237 | } |
238 | } | ||
239 | return Collections.unmodifiableCollection(items); | ||
240 | } | ||
241 | |||
242 | /** | ||
matt | 1.2 | 243 | * Returns a deep copy of this Roster. |
244 | * | ||
245 | * a deep copy of this Roster. | ||
246 | */ | ||
247 | public Roster createCopy() { | ||
matt | 1.6 | 248 | return new Roster(this); |
matt | 1.2 | 249 | } |
250 | |||
251 | /** | ||
matt | 1.1 | 252 | * Item in a roster, which represents an individual contact. Each contact |
253 | * has a JID, an optional nickname, a subscription type, and can belong to | ||
254 | * one ore more groups. | ||
255 | */ | ||
256 | public static class Item { | ||
257 | |||
258 | private JID jid; | ||
259 | private String name; | ||
gaston | 1.3 | 260 | private Ask ask; |
matt | 1.1 | 261 | private Subscription subscription; |
262 | private Collection<String> groups; | ||
263 | |||
264 | /** | ||
265 | * Constructs a new roster item. | ||
266 | * | ||
267 | * jid the JID. | ||
268 | * name the nickname. | ||
gaston | 1.3 | 269 | * ask the ask state. |
matt | 1.1 | 270 | * subscription the subscription state. |
271 | * groups the item groups. | ||
272 | */ | ||
gaston | 1.3 | 273 | private Item(JID jid, String name, Ask ask, Subscription subscription, |
274 | Collection<String> groups) { | ||
matt | 1.1 | 275 | this.jid = jid; |
276 | this.name = name; | ||
gaston | 1.3 | 277 | this.ask = ask; |
matt | 1.1 | 278 | this.subscription = subscription; |
279 | this.groups = groups; | ||
280 | } | ||
281 | |||
282 | /** | ||
283 | * Returns the JID associated with this item. The JID is the "key" in the | ||
284 | * list of items that make up a roster. There can only be a single item per | ||
285 | * JID in a roster. | ||
286 | * | ||
287 | * the JID associated with this item. | ||
288 | */ | ||
289 | public JID getJID() { | ||
290 | return jid; | ||
291 | } | ||
292 | |||
293 | /** | ||
294 | * Returns the nickname associated with this item. If no nickname exists, | ||
295 | * <tt>null</tt> is returned. | ||
296 | * | ||
297 | * the nickname, or <tt>null</tt> if it doesn't exist. | ||
298 | */ | ||
299 | public String getName() { | ||
300 | return name; | ||
301 | } | ||
302 | |||
303 | /** | ||
gaston | 1.3 | 304 | * Returns the ask state of this item. |
305 | * | ||
306 | * the ask state of this item. | ||
307 | */ | ||
308 | public Ask getAsk() { | ||
309 | return ask; | ||
310 | } | ||
311 | |||
312 | /** | ||
matt | 1.1 | 313 | * Returns the subscription state of this item. |
314 | * | ||
315 | * the subscription state of this item. | ||
316 | */ | ||
317 | public Subscription getSubscription() { | ||
318 | return subscription; | ||
319 | } | ||
320 | |||
321 | /** | ||
322 | * Returns a Collection of the groups defined in this item. If | ||
323 | * no groups are defined, an empty Collection is returned. | ||
324 | * | ||
325 | * the groups in this item. | ||
326 | */ | ||
327 | public Collection<String> getGroups() { | ||
328 | if (groups == null) { | ||
329 | return Collections.emptyList(); | ||
330 | } | ||
331 | return groups; | ||
332 | } | ||
333 | |||
334 | public String toString() { | ||
335 | StringBuffer buf = new StringBuffer(); | ||
336 | buf.append("<item "); | ||
337 | buf.append("jid=/"").append(jid).append("/""); | ||
338 | if (name != null) { | ||
339 | buf.append(" name=/"").append(name).append("/""); | ||
340 | } | ||
341 | buf.append(" subscrption=/"").append(subscription).append("/""); | ||
342 | if (groups == null || groups.isEmpty()) { | ||
343 | buf.append("/>"); | ||
344 | } | ||
345 | else { | ||
346 | buf.append(">/n"); | ||
347 | for (String group : groups) { | ||
348 | buf.append(" <group>").append(group).append("</group>/n"); | ||
349 | } | ||
350 | buf.append("</item>"); | ||
351 | } | ||
352 | return buf.toString(); | ||
353 | } | ||
354 | } | ||
355 | |||
356 | /** | ||
357 | * Type-safe enumeration for the roster subscription type. Valid subcription types: | ||
358 | * | ||
359 | * <ul> | ||
360 | * <li>{ #none Roster.Subscription.none} -- the user does not have a | ||
361 | * subscription to the contact's presence information, and the contact | ||
362 | * does not have a subscription to the user's presence information. | ||
363 | * <li>{ #to Roster.Subscription.to} -- the user has a subscription to | ||
364 | * the contact's presence information, but the contact does not have a | ||
365 | * subscription to the user's presence information. | ||
366 | * <li>{ #from Roster.Subscription.from} -- the contact has a subscription | ||
367 | * to the user's presence information, but the user does not have a | ||
368 | * subscription to the contact's presence information. | ||
gaston | 1.3 | 369 | * <li>{ #both Roster.Subscription.both} -- both the user and the contact |
matt | 1.1 | 370 | * have subscriptions to each other's presence information. |
gaston | 1.3 | 371 | * <li>{ #remove Roster.Subscription.remove} -- the user is removing a |
372 | * contact from his or her roster. | ||
matt | 1.1 | 373 | * </ul> |
374 | */ | ||
375 | public enum Subscription { | ||
376 | |||
377 | /** | ||
378 | * The user does not have a subscription to the contact's presence information, | ||
379 | * and the contact does not have a subscription to the user's presence information. | ||
380 | */ | ||
381 | none, | ||
382 | |||
383 | /** | ||
384 | * The user has a subscription to the contact's presence information, but the | ||
385 | * contact does not have a subscription to the user's presence information. | ||
386 | */ | ||
387 | to, | ||
388 | |||
389 | /** | ||
390 | * The contact has a subscription to the user's presence information, but the | ||
391 | * user does not have a subscription to the contact's presence information. | ||
392 | */ | ||
393 | from, | ||
394 | |||
395 | /** | ||
396 | * Both the user and the contact have subscriptions to each other's presence | ||
397 | * information. | ||
398 | */ | ||
gaston | 1.3 | 399 | both, |
400 | |||
401 | /** | ||
402 | * The user is removing a contact from his or her roster. The user's server will | ||
403 | * 1) automatically cancel any existing presence subscription between the user and the | ||
404 | * contact, 2) remove the roster item from the user's roster and inform all of the user's | ||
405 | * available resources that have requested the roster of the roster item removal, 3) inform | ||
406 | * the resource that initiated the removal of success and 4) send unavailable presence from | ||
407 | * all of the user's available resources to the contact. | ||
408 | */ | ||
409 | remove; | ||
410 | } | ||
411 | |||
412 | /** | ||
413 | * Type-safe enumeration for the roster ask type. Valid ask types: | ||
414 | * | ||
415 | * <ul> | ||
416 | * <li>{ #subscribe Roster.Ask.subscribe} -- the roster item has been asked | ||
417 | * for permission to subscribe to their presence but no response has been received. | ||
418 | * <li>{ #unsubscribe Roster.Ask.unsubscribe} -- the roster owner has asked | ||
419 | * to the roster item to unsubscribe from it's presence but has not received | ||
420 | * confirmation. | ||
421 | * </ul> | ||
422 | */ | ||
423 | public enum Ask { | ||
424 | |||
425 | /** | ||
426 | * The roster item has been asked for permission to subscribe to their presence | ||
427 | * but no response has been received. | ||
428 | */ | ||
429 | subscribe, | ||
430 | |||
431 | /** | ||
432 | * The roster owner has asked to the roster item to unsubscribe from it's | ||
433 | * presence but has not received confirmation. | ||
434 | */ | ||
435 | unsubscribe; | ||
matt | 1.1 | 436 | } |
项目中应用Java5.0
最新推荐文章于 2024-07-30 08:45:00 发布