org.xmpp.packet.Roster Maven / Gradle / Ivy
Show all versions of tinder Show documentation
/**
* Copyright (C) 2004-2008 Jive Software. All rights reserved.
*
* This software is published under the terms of the GNU Public License (GPL),
* a copy of which is included in this distribution, or a commercial license
* agreement with Jive.
*/
package org.xmpp.packet;
import org.dom4j.Element;
import org.dom4j.Namespace;
import org.dom4j.QName;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
/**
* Roster packet. The roster is a list of JIDs (typically other users) that
* the user wishes to track the presence of. Each roster item is keyed by
* JID and contains a nickname (optional), subscription type, and list of
* groups (optional).
*
* @author Matt Tucker
*/
public class Roster extends IQ {
/**
* Constructs a new Roster with an automatically generated ID and a type
* of {@link IQ.Type#get}.
*/
public Roster() {
super();
element.addElement("query", "jabber:iq:roster");
}
/**
* Constructs a new Roster using the specified type. A packet ID will
* be automatically generated.
*
* @param type the IQ type.
*/
public Roster(Type type) {
super(type);
element.addElement("query", "jabber:iq:roster");
}
/**
* Constructs a new Roster using the specified type and ID.
*
* @param type the IQ type.
* @param ID the packet ID of the IQ.
*/
public Roster(Type type, String ID) {
super(type, ID);
element.addElement("query", "jabber:iq:roster");
}
/**
* Constructs a new Roster that is a copy of an existing Roster.
*
* @param roster the roster packet.
* @see #createCopy()
*/
private Roster(Roster roster) {
Element elementCopy = roster.element.createCopy();
docFactory.createDocument().add(elementCopy);
this.element = elementCopy;
}
/**
* Constructs a new Roster using an existing Element. This is useful
* for parsing incoming roster Elements into Roster objects.
*
* @param element the Roster Element.
*/
public Roster(Element element) {
super(element);
}
/**
* Adds a new item to the roster. The name and groups are set to null
* If the roster packet already contains an item using the same JID, the
* information in the existing item will be overwritten with the new information.
*
* The XMPP specification recommends that if the roster item is associated with another
* instant messaging user (human), that the JID be in bare form (e.g. user@domain).
* Use the {@link JID#toBareJID() toBareJID()} method for a bare JID.
*
* @param jid the JID.
* @param subscription the subscription type.
* @return the newly created item.
*/
public Item addItem(String jid, Subscription subscription) {
if (getType() == IQ.Type.get || getType() == IQ.Type.error) {
throw new IllegalStateException("IQ type must be 'result' or 'set'");
}
if (jid == null) {
throw new NullPointerException("JID cannot be null");
}
return addItem(new JID(jid), null, null, subscription, null);
}
/**
* Adds a new item to the roster. The name and groups are set to null
* If the roster packet already contains an item using the same JID, the
* information in the existing item will be overwritten with the new information.
*
* The XMPP specification recommends that if the roster item is associated with another
* instant messaging user (human), that the JID be in bare form (e.g. user@domain).
* Use the {@link JID#toBareJID() toBareJID()} method for a bare JID.
*
* @param jid the JID.
* @param subscription the subscription type.
* @return the newly created item.
*/
public Item addItem(JID jid, Subscription subscription) {
if (getType() != IQ.Type.result && getType() != IQ.Type.set) {
throw new IllegalStateException("IQ type must be 'result' or 'set'");
}
if (jid == null) {
throw new NullPointerException("JID cannot be null");
}
return addItem(jid, null, null, subscription, null);
}
/**
* Adds a new item to the roster. If the roster packet already contains an item
* using the same JID, the information in the existing item will be overwritten
* with the new information.
*
* The XMPP specification recommends that if the roster item is associated with another
* instant messaging user (human), that the JID be in bare form (e.g. user@domain).
* Use the {@link JID#toBareJID() toBareJID()} method for a bare JID.
*
* @param jid the JID.
* @param name the nickname.
* @param ask the ask type.
* @param subscription the subscription type.
* @param groups a Collection of groups.
* @return the newly created item.
*/
@SuppressWarnings("unchecked")
public Item addItem(JID jid, String name, Ask ask, Subscription subscription,
Collection groups)
{
if (jid == null) {
throw new NullPointerException("JID cannot be null");
}
if (subscription == null) {
throw new NullPointerException("Subscription cannot be null");
}
Element query = element.element(new QName("query", Namespace.get("jabber:iq:roster")));
if (query == null) {
query = element.addElement("query", "jabber:iq:roster");
}
Element item = null;
for (Iterator i=query.elementIterator("item"); i.hasNext(); ) {
Element el = i.next();
if (el.attributeValue("jid").equals(jid.toString())) {
item = el;
}
}
if (item == null) {
item = query.addElement("item");
}
item.addAttribute("jid", jid.toBareJID());
item.addAttribute("name", name);
if (ask != null) {
item.addAttribute("ask", ask.toString());
}
item.addAttribute("subscription", subscription.toString());
// Erase existing groups in case the item previously existed.
for (Iterator i=item.elementIterator("group"); i.hasNext(); ) {
item.remove(i.next());
}
// Add in groups.
if (groups != null) {
for (String group : groups) {
item.addElement("group").setText(group);
}
}
return new Item(jid, name, ask, subscription, groups);
}
/**
* Removes an item from this roster.
*
* @param jid the JID of the item to remove.
*/
@SuppressWarnings("unchecked")
public void removeItem(JID jid) {
Element query = element.element(new QName("query", Namespace.get("jabber:iq:roster")));
if (query != null) {
for (Iterator i=query.elementIterator("item"); i.hasNext(); ) {
Element item = i.next();
if (item.attributeValue("jid").equals(jid.toString())) {
query.remove(item);
return;
}
}
}
}
/**
* Returns an unmodifiable copy of the {@link Item Items} in the roster packet.
*
* @return an unmodifable copy of the {@link Item Items} in the roster packet.
*/
@SuppressWarnings("unchecked")
public Collection- getItems() {
Collection
- items = new ArrayList
- ();
Element query = element.element(new QName("query", Namespace.get("jabber:iq:roster")));
if (query != null) {
for (Iterator
i=query.elementIterator("item"); i.hasNext(); ) {
Element item = i.next();
String jid = item.attributeValue("jid");
String name = item.attributeValue("name");
String ask = item.attributeValue("ask");
String subscription = item.attributeValue("subscription");
Collection groups = new ArrayList();
for (Iterator j=item.elementIterator("group"); j.hasNext(); ) {
Element group = j.next();
groups.add(group.getText().trim());
}
Ask askStatus = ask == null ? null : Ask.valueOf(ask);
Subscription subStatus = subscription == null ?
null : Subscription.valueOf(subscription);
items.add(new Item(new JID(jid), name, askStatus, subStatus, groups));
}
}
return Collections.unmodifiableCollection(items);
}
/**
* Returns a deep copy of this Roster.
*
* @return a deep copy of this Roster.
*/
public Roster createCopy() {
return new Roster(this);
}
/**
* Item in a roster, which represents an individual contact. Each contact
* has a JID, an optional nickname, a subscription type, and can belong to
* one ore more groups.
*/
public static class Item {
private JID jid;
private String name;
private Ask ask;
private Subscription subscription;
private Collection groups;
/**
* Constructs a new roster item.
*
* @param jid the JID.
* @param name the nickname.
* @param ask the ask state.
* @param subscription the subscription state.
* @param groups the item groups.
*/
private Item(JID jid, String name, Ask ask, Subscription subscription,
Collection groups) {
this.jid = jid;
this.name = name;
this.ask = ask;
this.subscription = subscription;
this.groups = groups;
}
/**
* Returns the JID associated with this item. The JID is the "key" in the
* list of items that make up a roster. There can only be a single item per
* JID in a roster.
*
* @return the JID associated with this item.
*/
public JID getJID() {
return jid;
}
/**
* Returns the nickname associated with this item. If no nickname exists,
* null is returned.
*
* @return the nickname, or null if it doesn't exist.
*/
public String getName() {
return name;
}
/**
* Returns the ask state of this item.
*
* @return the ask state of this item.
*/
public Ask getAsk() {
return ask;
}
/**
* Returns the subscription state of this item.
*
* @return the subscription state of this item.
*/
public Subscription getSubscription() {
return subscription;
}
/**
* Returns a Collection of the groups defined in this item. If
* no groups are defined, an empty Collection is returned.
*
* @return the groups in this item.
*/
public Collection getGroups() {
if (groups == null) {
return Collections.emptyList();
}
return groups;
}
public String toString() {
StringBuffer buf = new StringBuffer();
buf.append(" ");
}
else {
buf.append(">\n");
for (String group : groups) {
buf.append(" ").append(group).append(" \n");
}
buf.append(" ");
}
return buf.toString();
}
}
/**
* Type-safe enumeration for the roster subscription type. Valid subcription types:
*
*
* - {@link #none Roster.Subscription.none} -- the user does not have a
* subscription to the contact's presence information, and the contact
* does not have a subscription to the user's presence information.
*
- {@link #to Roster.Subscription.to} -- the user has a subscription to
* the contact's presence information, but the contact does not have a
* subscription to the user's presence information.
*
- {@link #from Roster.Subscription.from} -- the contact has a subscription
* to the user's presence information, but the user does not have a
* subscription to the contact's presence information.
*
- {@link #both Roster.Subscription.both} -- both the user and the contact
* have subscriptions to each other's presence information.
*
- {@link #remove Roster.Subscription.remove} -- the user is removing a
* contact from his or her roster.
*
*/
public enum Subscription {
/**
* The user does not have a subscription to the contact's presence information,
* and the contact does not have a subscription to the user's presence information.
*/
none,
/**
* The user has a subscription to the contact's presence information, but the
* contact does not have a subscription to the user's presence information.
*/
to,
/**
* The contact has a subscription to the user's presence information, but the
* user does not have a subscription to the contact's presence information.
*/
from,
/**
* Both the user and the contact have subscriptions to each other's presence
* information.
*/
both,
/**
* The user is removing a contact from his or her roster. The user's server will
* 1) automatically cancel any existing presence subscription between the user and the
* contact, 2) remove the roster item from the user's roster and inform all of the user's
* available resources that have requested the roster of the roster item removal, 3) inform
* the resource that initiated the removal of success and 4) send unavailable presence from
* all of the user's available resources to the contact.
*/
remove;
}
/**
* Type-safe enumeration for the roster ask type. Valid ask types:
*
*
* - {@link #subscribe Roster.Ask.subscribe} -- the roster item has been asked
* for permission to subscribe to their presence but no response has been received.
*
- {@link #unsubscribe Roster.Ask.unsubscribe} -- the roster owner has asked
* to the roster item to unsubscribe from it's presence but has not received
* confirmation.
*
*/
public enum Ask {
/**
* The roster item has been asked for permission to subscribe to their presence
* but no response has been received.
*/
subscribe,
/**
* The roster owner has asked to the roster item to unsubscribe from it's
* presence but has not received confirmation.
*/
unsubscribe;
}
}