KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > xmpp > packet > Roster


1 /**
2  * $RCSfile: Roster.java,v $
3  * $Revision: 1.7 $
4  * $Date: 2005/05/11 19:56:11 $
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  * @author 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 {@link 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      * @param 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      * @param type the IQ type.
62      * @param ID the packet ID of the IQ.
63      */

64     public Roster(Type type, String JavaDoc ID) {
65         super(type, ID);
66         element.addElement("query", "jabber:iq:roster");
67     }
68
69     /**
70      * Constructs a new Roster that is a copy of an existing Roster.
71      *
72      * @param roster the roster packet.
73      * @see #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     /**
82      * Constructs a new Roster using an existing Element. This is useful
83      * for parsing incoming roster Elements into Roster objects.
84      *
85      * @param 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@domain).
98      * Use the {@link JID#toBareJID() toBareJID()} method for a bare JID.
99      *
100      * @param jid the JID.
101      * @param subscription the subscription type.
102      * @return the newly created item.
103      */

104     public Item addItem(String JavaDoc jid, Subscription subscription) {
105         if (getType() == IQ.Type.get || getType() == IQ.Type.error) {
106             throw new IllegalStateException JavaDoc("IQ type must be 'result' or 'set'");
107         }
108         if (jid == null) {
109             throw new NullPointerException JavaDoc("JID cannot be null");
110         }
111         return addItem(new JID(jid), null, null, subscription, null);
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@domain).
121      * Use the {@link JID#toBareJID() toBareJID()} method for a bare JID.
122      *
123      * @param jid the JID.
124      * @param subscription the subscription type.
125      * @return the newly created item.
126      */

127     public Item addItem(JID jid, Subscription subscription) {
128         if (getType() != IQ.Type.result && getType() != IQ.Type.set) {
129             throw new IllegalStateException JavaDoc("IQ type must be 'result' or 'set'");
130         }
131         if (jid == null) {
132             throw new NullPointerException JavaDoc("JID cannot be null");
133         }
134         return addItem(jid, null, null, subscription, null);
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@domain).
144      * Use the {@link JID#toBareJID() toBareJID()} method for a bare JID.
145      *
146      * @param jid the JID.
147      * @param name the nickname.
148      * @param ask the ask type.
149      * @param subscription the subscription type.
150      * @param groups a Collection of groups.
151      * @return the newly created item.
152      */

153     public Item addItem(JID jid, String JavaDoc name, Ask ask, Subscription subscription,
154                         Collection<String JavaDoc> groups)
155     {
156         if (jid == null) {
157             throw new NullPointerException JavaDoc("JID cannot be null");
158         }
159         if (subscription == null) {
160             throw new NullPointerException JavaDoc("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         }
176         item.addAttribute("jid", jid.toBareJID());
177         item.addAttribute("name", name);
178         if (ask != null) {
179             item.addAttribute("ask", ask.toString());
180         }
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 JavaDoc group : groups) {
189                 item.addElement("group").setText(group);
190             }
191         }
192         return new Item(jid, name, ask, subscription, groups);
193     }
194
195     /**
196      * Removes an item from this roster.
197      *
198      * @param 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 {@link Item Items} in the roster packet.
215      *
216      * @return an unmodifable copy of the {@link 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 JavaDoc jid = item.attributeValue("jid");
225                 String JavaDoc name = item.attributeValue("name");
226                 String JavaDoc ask = item.attributeValue("ask");
227                 String JavaDoc subscription = item.attributeValue("subscription");
228                 Collection<String JavaDoc> groups = new ArrayList<String JavaDoc>();
229                 for (Iterator j=item.elementIterator("group"); j.hasNext(); ) {
230                     Element group = (Element)j.next();
231                     groups.add(group.getTextTrim());
232                 }
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));
237             }
238         }
239         return Collections.unmodifiableCollection(items);
240     }
241
242     /**
243      * Returns a deep copy of this Roster.
244      *
245      * @return a deep copy of this Roster.
246      */

247     public Roster createCopy() {
248         return new Roster(this);
249     }
250
251     /**
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 JavaDoc name;
260         private Ask ask;
261         private Subscription subscription;
262         private Collection<String JavaDoc> groups;
263
264         /**
265          * Constructs a new roster item.
266          *
267          * @param jid the JID.
268          * @param name the nickname.
269          * @param ask the ask state.
270          * @param subscription the subscription state.
271          * @param groups the item groups.
272          */

273         private Item(JID jid, String JavaDoc name, Ask ask, Subscription subscription,
274                      Collection<String JavaDoc> groups) {
275             this.jid = jid;
276             this.name = name;
277             this.ask = ask;
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          * @return 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          * @return the nickname, or <tt>null</tt> if it doesn't exist.
298          */

299         public String JavaDoc getName() {
300             return name;
301         }
302
303         /**
304          * Returns the ask state of this item.
305          *
306          * @return the ask state of this item.
307          */

308         public Ask getAsk() {
309             return ask;
310         }
311
312         /**
313          * Returns the subscription state of this item.
314          *
315          * @return 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          * @return the groups in this item.
326          */

327         public Collection<String JavaDoc> getGroups() {
328             if (groups == null) {
329                 return Collections.emptyList();
330             }
331             return groups;
332         }
333
334         public String JavaDoc toString() {
335             StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
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 JavaDoc 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>{@link #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>{@link #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>{@link #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.
369      * <li>{@link #both Roster.Subscription.both} -- both the user and the contact
370      * have subscriptions to each other's presence information.
371      * <li>{@link #remove Roster.Subscription.remove} -- the user is removing a
372      * contact from his or her roster.
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          */

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>{@link #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>{@link #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;
436     }
437 }
Popular Tags