RosterGroup.java

  1. /**
  2.  *
  3.  * Copyright 2003-2007 Jive Software.
  4.  *
  5.  * Licensed under the Apache License, Version 2.0 (the "License");
  6.  * you may not use this file except in compliance with the License.
  7.  * You may obtain a copy of the License at
  8.  *
  9.  *     http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */

  17. package org.jivesoftware.smack.roster;

  18. import java.util.ArrayList;
  19. import java.util.LinkedHashSet;
  20. import java.util.List;
  21. import java.util.Locale;
  22. import java.util.Set;

  23. import org.jivesoftware.smack.PacketCollector;
  24. import org.jivesoftware.smack.XMPPConnection;
  25. import org.jivesoftware.smack.SmackException.NoResponseException;
  26. import org.jivesoftware.smack.SmackException.NotConnectedException;
  27. import org.jivesoftware.smack.XMPPException.XMPPErrorException;
  28. import org.jivesoftware.smack.packet.IQ;
  29. import org.jivesoftware.smack.roster.packet.RosterPacket;
  30. import org.jxmpp.util.XmppStringUtils;

  31. /**
  32.  * A group of roster entries.
  33.  *
  34.  * @see Roster#getGroup(String)
  35.  * @author Matt Tucker
  36.  */
  37. public class RosterGroup {

  38.     private final String name;
  39.     private final XMPPConnection connection;
  40.     private final Set<RosterEntry> entries;

  41.     /**
  42.      * Creates a new roster group instance.
  43.      *
  44.      * @param name the name of the group.
  45.      * @param connection the connection the group belongs to.
  46.      */
  47.     RosterGroup(String name, XMPPConnection connection) {
  48.         this.name = name;
  49.         this.connection = connection;
  50.         entries = new LinkedHashSet<RosterEntry>();
  51.     }

  52.     /**
  53.      * Returns the name of the group.
  54.      *
  55.      * @return the name of the group.
  56.      */
  57.     public String getName() {
  58.         return name;
  59.     }

  60.     /**
  61.      * Sets the name of the group. Changing the group's name is like moving all the group entries
  62.      * of the group to a new group specified by the new name. Since this group won't have entries
  63.      * it will be removed from the roster. This means that all the references to this object will
  64.      * be invalid and will need to be updated to the new group specified by the new name.
  65.      *
  66.      * @param name the name of the group.
  67.      * @throws NotConnectedException
  68.      * @throws XMPPErrorException
  69.      * @throws NoResponseException
  70.      * @throws InterruptedException
  71.      */
  72.     public void setName(String name) throws NotConnectedException, NoResponseException, XMPPErrorException, InterruptedException {
  73.         synchronized (entries) {
  74.             for (RosterEntry entry : entries) {
  75.                 RosterPacket packet = new RosterPacket();
  76.                 packet.setType(IQ.Type.set);
  77.                 RosterPacket.Item item = RosterEntry.toRosterItem(entry);
  78.                 item.removeGroupName(this.name);
  79.                 item.addGroupName(name);
  80.                 packet.addRosterItem(item);
  81.                 connection.createPacketCollectorAndSend(packet).nextResultOrThrow();
  82.             }
  83.         }
  84.     }

  85.     /**
  86.      * Returns the number of entries in the group.
  87.      *
  88.      * @return the number of entries in the group.
  89.      */
  90.     public int getEntryCount() {
  91.         synchronized (entries) {
  92.             return entries.size();
  93.         }
  94.     }

  95.     /**
  96.      * Returns an copied list of all entries in the group.
  97.      *
  98.      * @return all entries in the group.
  99.      */
  100.     public List<RosterEntry> getEntries() {
  101.         synchronized (entries) {
  102.             return new ArrayList<RosterEntry>(entries);
  103.         }
  104.     }

  105.     /**
  106.      * Returns the roster entry associated with the given XMPP address or
  107.      * <tt>null</tt> if the user is not an entry in the group.
  108.      *
  109.      * @param user the XMPP address of the user (eg "jsmith@example.com").
  110.      * @return the roster entry or <tt>null</tt> if it does not exist in the group.
  111.      */
  112.     public RosterEntry getEntry(String user) {
  113.         if (user == null) {
  114.             return null;
  115.         }
  116.         // Roster entries never include a resource so remove the resource
  117.         // if it's a part of the XMPP address.
  118.         user = XmppStringUtils.parseBareJid(user);
  119.         String userLowerCase = user.toLowerCase(Locale.US);
  120.         synchronized (entries) {
  121.             for (RosterEntry entry : entries) {
  122.                 if (entry.getUser().equals(userLowerCase)) {
  123.                     return entry;
  124.                 }
  125.             }
  126.         }
  127.         return null;
  128.     }

  129.     /**
  130.      * Returns true if the specified entry is part of this group.
  131.      *
  132.      * @param entry a roster entry.
  133.      * @return true if the entry is part of this group.
  134.      */
  135.     public boolean contains(RosterEntry entry) {
  136.         synchronized (entries) {
  137.             return entries.contains(entry);
  138.         }
  139.     }

  140.     /**
  141.      * Returns true if the specified XMPP address is an entry in this group.
  142.      *
  143.      * @param user the XMPP address of the user.
  144.      * @return true if the XMPP address is an entry in this group.
  145.      */
  146.     public boolean contains(String user) {
  147.         return getEntry(user) != null;
  148.     }

  149.     /**
  150.      * Adds a roster entry to this group. If the entry was unfiled then it will be removed from
  151.      * the unfiled list and will be added to this group.
  152.      * Note that this is a synchronous call -- Smack must wait for the server
  153.      * to receive the updated roster.
  154.      *
  155.      * @param entry a roster entry.
  156.      * @throws XMPPErrorException if an error occured while trying to add the entry to the group.
  157.      * @throws NoResponseException if there was no response from the server.
  158.      * @throws NotConnectedException
  159.      * @throws InterruptedException
  160.      */
  161.     public void addEntry(RosterEntry entry) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
  162.         PacketCollector collector = null;
  163.         // Only add the entry if it isn't already in the list.
  164.         synchronized (entries) {
  165.             if (!entries.contains(entry)) {
  166.                 RosterPacket packet = new RosterPacket();
  167.                 packet.setType(IQ.Type.set);
  168.                 RosterPacket.Item item = RosterEntry.toRosterItem(entry);
  169.                 item.addGroupName(getName());
  170.                 packet.addRosterItem(item);
  171.                 // Wait up to a certain number of seconds for a reply from the server.
  172.                 collector = connection.createPacketCollectorAndSend(packet);
  173.             }
  174.         }
  175.         if (collector != null) {
  176.             collector.nextResultOrThrow();
  177.         }
  178.     }

  179.     /**
  180.      * Removes a roster entry from this group. If the entry does not belong to any other group
  181.      * then it will be considered as unfiled, therefore it will be added to the list of unfiled
  182.      * entries.
  183.      * Note that this is a synchronous call -- Smack must wait for the server
  184.      * to receive the updated roster.
  185.      *
  186.      * @param entry a roster entry.
  187.      * @throws XMPPErrorException if an error occurred while trying to remove the entry from the group.
  188.      * @throws NoResponseException if there was no response from the server.
  189.      * @throws NotConnectedException
  190.      * @throws InterruptedException
  191.      */
  192.     public void removeEntry(RosterEntry entry) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
  193.         PacketCollector collector = null;
  194.         // Only remove the entry if it's in the entry list.
  195.         // Remove the entry locally, if we wait for RosterPacketListenerprocess>>Packet(Packet)
  196.         // to take place the entry will exist in the group until a packet is received from the
  197.         // server.
  198.         synchronized (entries) {
  199.             if (entries.contains(entry)) {
  200.                 RosterPacket packet = new RosterPacket();
  201.                 packet.setType(IQ.Type.set);
  202.                 RosterPacket.Item item = RosterEntry.toRosterItem(entry);
  203.                 item.removeGroupName(this.getName());
  204.                 packet.addRosterItem(item);
  205.                 // Wait up to a certain number of seconds for a reply from the server.
  206.                 collector = connection.createPacketCollectorAndSend(packet);
  207.             }
  208.         }
  209.         if (collector != null) {
  210.             collector.nextResultOrThrow();
  211.         }
  212.     }

  213.     void addEntryLocal(RosterEntry entry) {
  214.         // Update the entry if it is already in the list
  215.         synchronized (entries) {
  216.             entries.remove(entry);
  217.             entries.add(entry);
  218.         }
  219.     }

  220.     void removeEntryLocal(RosterEntry entry) {
  221.          // Only remove the entry if it's in the entry list.
  222.         synchronized (entries) {
  223.             if (entries.contains(entry)) {
  224.                 entries.remove(entry);
  225.             }
  226.         }
  227.     }
  228. }