/** * $RCSfile$ * $Revision$ * $Date$ * * Copyright (C) 2002-2003 Jive Software. All rights reserved. * ==================================================================== * The Jive Software License (based on Apache Software License, Version 1.1) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by * Jive Software (http://www.jivesoftware.com)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Smack" and "Jive Software" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact webmaster@jivesoftware.com. * * 5. Products derived from this software may not be called "Smack", * nor may "Smack" appear in their name, without prior written * permission of Jive Software. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL JIVE SOFTWARE OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== */ package org.jivesoftware.smack; import org.jivesoftware.smack.packet.*; import org.jivesoftware.smack.filter.*; import org.jivesoftware.smack.util.StringUtils; import java.util.*; /** * Represents a user's roster, which is the collection of users a person receives * presence updates for. Roster items are categorized into groups for easier management.
*
* All presence subscription requests are automatically approved to this client
* are automatically approved. This logic will be updated in the future to allow for
* pluggable behavior.
*
* @see XMPPConnection#getRoster()
* @author Matt Tucker
*/
public class Roster {
private XMPPConnection connection;
private Map groups;
private List unfiledEntries;
private List rosterListeners;
private Map presenceMap;
// The roster is marked as initialized when at least a single roster packet
// has been recieved and processed.
boolean rosterInitialized = false;
/**
* Creates a new roster.
*
* @param connection an XMPP connection.
*/
Roster(final XMPPConnection connection) {
this.connection = connection;
groups = new Hashtable();
unfiledEntries = new ArrayList();
rosterListeners = new ArrayList();
presenceMap = new HashMap();
// Listen for any roster packets.
PacketFilter rosterFilter = new PacketTypeFilter(RosterPacket.class);
connection.addPacketListener(new RosterPacketListener(), rosterFilter);
// Listen for any presence packets.
PacketFilter presenceFilter = new PacketTypeFilter(Presence.class);
connection.addPacketListener(new PresencePacketListener(), presenceFilter);
}
/**
* Reloads the entire roster from the server. This is an asynchronous operation,
* which means the method will return immediately, and the roster will be
* reloaded at a later point when the server responds to the reload request.
*/
public void reload() {
connection.sendPacket(new RosterPacket());
}
/**
* Adds a listener to this roster. The listener will be fired anytime one or more
* changes to the roster are pushed from the server.
*
* @param rosterListener a roster listener.
*/
public void addRosterListener(RosterListener rosterListener) {
synchronized (rosterListeners) {
if (!rosterListeners.contains(rosterListener)) {
rosterListeners.add(rosterListener);
}
}
}
/**
* Removes a listener from this roster. The listener will be fired anytime one or more
* changes to the roster are pushed from the server.
*
* @param rosterListener a roster listener.
*/
public void removeRosterListener(RosterListener rosterListener) {
synchronized (rosterListeners) {
rosterListeners.remove(rosterListener);
}
}
/**
* Creates a new group.
*
* @param name the name of the group.
* @return a new group.
*/
public RosterGroup createGroup(String name) {
synchronized (groups) {
if (groups.containsKey(name)) {
throw new IllegalArgumentException("Group with name " + name + " alread exists.");
}
RosterGroup group = new RosterGroup(name, connection);
groups.put(name, group);
return group;
}
}
/**
* Cretaes a new roster entry and prsence subscription. The server will asynchronously
* update the roster with the subscription status.
*
* @param user the user.
* @param name the nickname of the user.
* @param groups the list of groups entry will belong to, or null if the
* the roster entry won't belong to a group.
*/
public void createEntry(String user, String name, String [] groups) throws XMPPException {
// Create and send roster entry creation packet.
RosterPacket rosterPacket = new RosterPacket();
rosterPacket.setType(IQ.Type.SET);
RosterPacket.Item item = new RosterPacket.Item(user, name);
if (groups != null) {
for (int i=0; i