diff --git a/documentation/extensions/rosterexchange.html b/documentation/extensions/rosterexchange.html index 1751159c2..53d3ac94e 100644 --- a/documentation/extensions/rosterexchange.html +++ b/documentation/extensions/rosterexchange.html @@ -114,15 +114,18 @@ entries to his roster. RosterExchangeManager rosterExchangeManager2 = new RosterExchangeManager(conn2); // Create a RosterExchangeListener that will iterate over the received roster entries RosterExchangeListener rosterExchangeListener = new RosterExchangeListener() { - public void entriesReceived(String from, Iterator rosterEntries) { - for (Iterator it = rosterEntries; it.hasNext();) { + public void entriesReceived(String from, Iterator remoteRosterEntries) { + while (remoteRosterEntries.hasNext()) { try { // Get the received entry - RosterEntry entry = (RosterEntry) it.next(); - // Display the entry on the console - System.out.println(entry); + RemoteRosterEntry remoteRosterEntry = (RemoteRosterEntry) remoteRosterEntries.next(); + // Display the remote entry on the console + System.out.println(remoteRosterEntry); // Add the entry to the user2's roster - user2_roster.createEntry(entry); + user2_roster.createEntry( + remoteRosterEntry.getUser(), + remoteRosterEntry.getName(), + remoteRosterEntry.getGroupArrayNames()); } catch (XMPPException e) { e.printStackTrace(); diff --git a/source/org/jivesoftware/smackx/RosterExchangeListener.java b/source/org/jivesoftware/smackx/RosterExchangeListener.java index 543b995f4..8a913e9e3 100644 --- a/source/org/jivesoftware/smackx/RosterExchangeListener.java +++ b/source/org/jivesoftware/smackx/RosterExchangeListener.java @@ -66,8 +66,9 @@ public interface RosterExchangeListener { * Called when roster entries are received as part of a roster exchange. * * @param from the user that sent the entries. - * @param rosterEntries the entries sent by the user. These entries are local roster entries. + * @param rosterEntries the entries sent by the user. The entries are instances of + * RemoteRosterEntry. */ - public void entriesReceived(String from, Iterator rosterEntries); + public void entriesReceived(String from, Iterator remoteRosterEntries); } diff --git a/source/org/jivesoftware/smackx/RosterExchangeManager.java b/source/org/jivesoftware/smackx/RosterExchangeManager.java new file mode 100644 index 000000000..f6e991fab --- /dev/null +++ b/source/org/jivesoftware/smackx/RosterExchangeManager.java @@ -0,0 +1,209 @@ +/** + * $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.smackx; + +import java.util.*; + +import org.jivesoftware.smack.*; +import org.jivesoftware.smack.filter.*; +import org.jivesoftware.smack.packet.*; +import org.jivesoftware.smackx.packet.RosterExchange; + +/** + * + * Manages Roster exchanges. A RosterExchangeManager provides a high level access to send + * rosters, roster groups and roster entries to XMPP clients. It also provides an easy way + * to hook up custom logic when entries are received from another XMPP client through + * RosterExchangeListeners. + * + * @author Gaston Dombiak + */ +public class RosterExchangeManager { + + private List rosterExchangeListeners = new ArrayList(); + + private XMPPConnection con; + + private PacketFilter packetFilter = new PacketExtensionFilter("x", "jabber:x:roster"); + private PacketListener packetListener; + + /** + * Creates a new roster exchange manager. + * + * @param con an XMPPConnection. + */ + public RosterExchangeManager(XMPPConnection con) { + this.con = con; + init(); + } + + /** + * Adds a listener to roster exchanges. The listener will be fired anytime roster entries + * are received from remote XMPP clients. + * + * @param rosterExchangeListener a roster exchange listener. + */ + public void addRosterListener(RosterExchangeListener rosterExchangeListener) { + synchronized (rosterExchangeListeners) { + if (!rosterExchangeListeners.contains(rosterExchangeListener)) { + rosterExchangeListeners.add(rosterExchangeListener); + } + } + } + + /** + * Removes a listener from roster exchanges. The listener will be fired anytime roster + * entries are received from remote XMPP clients. + * + * @param rosterExchangeListener a roster exchange listener.. + */ + public void removeRosterListener(RosterExchangeListener rosterExchangeListener) { + synchronized (rosterExchangeListeners) { + rosterExchangeListeners.remove(rosterExchangeListener); + } + } + + /** + * Sends a roster to userID. All the entries of the roster will be sent to the + * target user. + * + * @param roster the roster to send + * @param targetUserID the user that will receive the roster entries + */ + public void send(Roster roster, String targetUserID) { + // Create a new message to send the roster + Message msg = new Message(targetUserID); + // Create a RosterExchange Package and add it to the message + RosterExchange rosterExchange = new RosterExchange(roster); + msg.addExtension(rosterExchange); + + // Send the message that contains the roster + con.sendPacket(msg); + } + + /** + * Sends a roster entry to userID. + * + * @param rosterEntry the roster entry to send + * @param targetUserID the user that will receive the roster entries + */ + public void send(RosterEntry rosterEntry, String targetUserID) { + // Create a new message to send the roster + Message msg = new Message(targetUserID); + // Create a RosterExchange Package and add it to the message + RosterExchange rosterExchange = new RosterExchange(); + rosterExchange.addRosterEntry(rosterEntry); + msg.addExtension(rosterExchange); + + // Send the message that contains the roster + con.sendPacket(msg); + } + + /** + * Sends a roster group to userID. All the entries of the group will be sent to the + * target user. + * + * @param rosterGroup the roster group to send + * @param targetUserID the user that will receive the roster entries + */ + public void send(RosterGroup rosterGroup, String targetUserID) { + // Create a new message to send the roster + Message msg = new Message(targetUserID); + // Create a RosterExchange Package and add it to the message + RosterExchange rosterExchange = new RosterExchange(); + for (Iterator it = rosterGroup.getEntries(); it.hasNext();) + rosterExchange.addRosterEntry((RosterEntry) it.next()); + msg.addExtension(rosterExchange); + + // Send the message that contains the roster + con.sendPacket(msg); + } + + /** + * Fires roster exchange listeners. + */ + private void fireRosterExchangeListeners(String from, Iterator rosterEntries) { + RosterExchangeListener[] listeners = null; + synchronized (rosterExchangeListeners) { + listeners = new RosterExchangeListener[rosterExchangeListeners.size()]; + rosterExchangeListeners.toArray(listeners); + } + for (int i = 0; i < listeners.length; i++) { + listeners[i].entriesReceived(from, rosterEntries); + } + } + + private void init() { + // Listens for all roster exchange packets and fire the roster exchange listeners. + packetListener = new PacketListener() { + public void processPacket(Packet packet) { + Message message = (Message) packet; + RosterExchange rosterExchange = + (RosterExchange) message.getExtension("x", "jabber:x:roster"); + // Fire event for roster exchange listeners + fireRosterExchangeListeners(message.getFrom(), rosterExchange.getRosterEntries()); + }; + + }; + con.addPacketListener(packetListener, packetFilter); + } + + public void destroy() { + if (con != null) + con.removePacketListener(packetListener); + + } + public void finalize() { + destroy(); + } +} \ No newline at end of file diff --git a/source/org/jivesoftware/smackx/packet/RemoteRosterEntry.java b/source/org/jivesoftware/smackx/packet/RemoteRosterEntry.java new file mode 100644 index 000000000..b6cc1a8a0 --- /dev/null +++ b/source/org/jivesoftware/smackx/packet/RemoteRosterEntry.java @@ -0,0 +1,179 @@ +/** + * $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.smackx.packet; + +import java.util.*; + +/** + * Represents a roster item, which consists of a JID and , their name and + * the groups the roster item belongs to. This roster item does not belong + * to the local roster. Therefore, it does not persist in the server.

+ * + * The idea of a RemoteRosterEntry is to be used as part of a roster exchange. + * + * @author Gaston Dombiak + */ +public class RemoteRosterEntry { + + private String user; + private String name; + private List groupNames; + + /** + * Creates a new remote roster entry. + * + * @param user the user. + * @param name the user's name. + */ + public RemoteRosterEntry(String user, String name) { + this.user = user; + this.name = name; + groupNames = new ArrayList(); + } + + /** + * Returns the user. + * + * @return the user. + */ + public String getUser() { + return user; + } + + /** + * Returns the user's name. + * + * @return the user's name. + */ + public String getName() { + return name; + } + + /** + * Sets the user's name. + * + * @param name the user's name. + */ + public void setName(String name) { + this.name = name; + } + + /** + * Returns an Iterator for the group names (as Strings) that the roster entry + * belongs to. + * + * @return an Iterator for the group names. + */ + public Iterator getGroupNames() { + synchronized (groupNames) { + return Collections.unmodifiableList(groupNames).iterator(); + } + } + + /** + * Returns a String array for the group names that the roster entry + * belongs to. + * + * @return a String[] for the group names. + */ + public String[] getGroupArrayNames() { + synchronized (groupNames) { + return (String[]) + (Collections + .unmodifiableList(groupNames) + .toArray(new String[groupNames.size()])); + } + } + + /** + * Adds a group name. + * + * @param groupName the group name. + */ + public void addGroupName(String groupName) { + synchronized (groupNames) { + if (!groupNames.contains(groupName)) { + groupNames.add(groupName); + } + } + } + + /** + * Removes a group name. + * + * @param groupName the group name. + */ + public void removeGroupName(String groupName) { + synchronized (groupNames) { + groupNames.remove(groupName); + } + } + + public String toXML() { + StringBuffer buf = new StringBuffer(); + buf.append(""); + synchronized (groupNames) { + for (int i = 0; i < groupNames.size(); i++) { + String groupName = (String) groupNames.get(i); + buf.append("").append(groupName).append(""); + } + } + buf.append(""); + return buf.toString(); + } + +} diff --git a/source/org/jivesoftware/smackx/packet/RosterExchange.java b/source/org/jivesoftware/smackx/packet/RosterExchange.java index 3b5a31654..302ff26f3 100644 --- a/source/org/jivesoftware/smackx/packet/RosterExchange.java +++ b/source/org/jivesoftware/smackx/packet/RosterExchange.java @@ -1,6 +1,55 @@ -/* - * Created on 27/07/2003 +/** + * $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.smackx.packet; import java.util.*; @@ -9,80 +58,76 @@ import org.jivesoftware.smack.*; import org.jivesoftware.smack.packet.PacketExtension; /** - * Represents XMPP Roster Item Exchange packets. - * The 'jabber:x:roster' namespace (which is not to be confused with the 'jabber:iq:roster' namespace) is used to - * send roster items from one client to another. A roster item is sent by adding to the element an child - * scoped by the 'jabber:x:roster' namespace. This element may contain one or more children (one for each roster item to be sent). + * Represents XMPP Roster Item Exchange packets.

* - * Each element may possess the following attributes: + * The 'jabber:x:roster' namespace (which is not to be confused with the 'jabber:iq:roster' + * namespace) is used to send roster items from one client to another. A roster item is sent by + * adding to the <message/> element an <x/> child scoped by the 'jabber:x:roster' namespace. This + * <x/> element may contain one or more <item/> children (one for each roster item to be sent).

* - * -- The id of the contact being sent. This attribute is required. - * -- A natural-language nickname for the contact. This attribute is optional. + * Each <item/> element may possess the following attributes:

* - * Each element may also contain one or more children specifying the natural-language name - * of a user-specified group, for the purpose of categorizing this contact into one or more roster groups. + * <jid/> -- The id of the contact being sent. This attribute is required.
+ * <name/> -- A natural-language nickname for the contact. This attribute is optional.

+ * + * Each <item/> element may also contain one or more <group/> children specifying the + * natural-language name of a user-specified group, for the purpose of categorizing this contact + * into one or more roster groups. * * @author Gaston Dombiak */ public class RosterExchange implements PacketExtension { - private List rosterItems = new ArrayList(); + private List remoteRosterEntries = new ArrayList(); - /** - * Creates a new empty roster exchange package. - * - */ - public RosterExchange(){ + /** + * Creates a new empty roster exchange package. + * + */ + public RosterExchange() { super(); } - /** - * Creates a new roster exchange package with the entries specified in roster. - * - * @param roster the roster to send to other XMPP entity. - */ - public RosterExchange(Roster roster){ - RosterGroup rosterGroup = null; - // Loop through all roster groups and add their entries to the new RosterExchange - for (Iterator groups = roster.getGroups(); groups.hasNext(); ) { - rosterGroup = (RosterGroup) groups.next(); - for (Iterator entries = rosterGroup.getEntries(); entries.hasNext(); ) { - this.addRosterItem((RosterEntry) entries.next()); - } - } - // Add the roster unfiled entries to the new RosterExchange - for (Iterator unfiledEntries = roster.getUnfiledEntries(); unfiledEntries.hasNext();) { - this.addRosterItem((RosterEntry) unfiledEntries.next()); - } - } - /** - * Adds a roster entry to the packet. + * Creates a new roster exchange package with the entries specified in roster. * - * @param rosterEntry a roster item. + * @param roster the roster to send to other XMPP entity. */ - public void addRosterItem(RosterEntry rosterEntry) { - RosterGroup rosterGroup = null; - // Create a new Item based on the rosterEntry and add it to the packet - Item item = new Item(rosterEntry.getUser(), rosterEntry.getName()); - // Add the entry groups to the item - for (Iterator groups = rosterEntry.getGroups(); groups.hasNext(); ) { - rosterGroup = (RosterGroup) groups.next(); - item.addGroupName(rosterGroup.getName()); + public RosterExchange(Roster roster) { + // Add all the roster entries to the new RosterExchange + for (Iterator rosterEntries = roster.getEntries(); rosterEntries.hasNext();) { + this.addRosterEntry((RosterEntry) rosterEntries.next()); } - addRosterItem(item); } /** - * Adds a roster item to the packet. + * Adds a roster entry to the packet. * - * @param item a roster item. + * @param rosterEntry a roster entry to add. */ - public void addRosterItem(Item item) { - synchronized (rosterItems) { - rosterItems.add(item); + public void addRosterEntry(RosterEntry rosterEntry) { + RosterGroup rosterGroup = null; + // Create a new Entry based on the rosterEntry and add it to the packet + RemoteRosterEntry remoteRosterEntry = new RemoteRosterEntry(rosterEntry.getUser(), rosterEntry.getName()); + // Add the entry groups to the Entry + for (Iterator groups = rosterEntry.getGroups(); groups.hasNext();) { + rosterGroup = (RosterGroup) groups.next(); + remoteRosterEntry.addGroupName(rosterGroup.getName()); + } + addRosterEntry(remoteRosterEntry); + } + + /** + * Adds a remote roster entry to the packet. + * + * @param remoteRosterEntry a remote roster entry to add. + */ + public void addRosterEntry(RemoteRosterEntry remoteRosterEntry) { + synchronized (remoteRosterEntries) { + remoteRosterEntries.add(remoteRosterEntry); } } + /** * Returns the XML element name of the extension sub-packet root element. * Always returns "x" @@ -105,158 +150,54 @@ public class RosterExchange implements PacketExtension { } /** - * Returns an Iterator for the roster items in the packet. + * Returns an Iterator for the roster entries in the packet. * - * @return and Iterator for the roster items in the packet. + * @return an Iterator for the roster entries in the packet. */ - public Iterator getRosterItems() { - synchronized (rosterItems) { - List entries = - Collections.unmodifiableList(new ArrayList(rosterItems)); + public Iterator getRosterEntries() { + synchronized (remoteRosterEntries) { + List entries = Collections.unmodifiableList(new ArrayList(remoteRosterEntries)); return entries.iterator(); } } /** - * Returns the XML representation of a Roster Item Exchange according the specification. + * Returns a count of the entries in the roster exchange. * + * @return the number of entries in the roster exchange. + */ + public int getEntryCount() { + return remoteRosterEntries.size(); + } + + /** + * Returns the XML representation of a Roster Item Exchange according the specification. + * * Usually the XML representation will be inside of a Message XML representation like * in the following example: - * - * Any subject you want - * This message contains roster items. - * - * - * - * - * + *

+     * <message id="MlIpV-4" to="gato1@gato.home" from="gato3@gato.home/Smack">
+     *     <subject>Any subject you want</subject>
+     *     <body>This message contains roster items.</body>
+     *     <x xmlns="jabber:x:roster">
+     *         <item jid="gato1@gato.home"/>
+     *         <item jid="gato2@gato.home"/>
+     *     </x>
+     * </message>
+     * 
* */ public String toXML() { StringBuffer buf = new StringBuffer(); - buf.append("<").append(getElementName()).append(" xmlns=\"").append(getNamespace()).append("\">"); - // Loop through all roster items and append them to the string buffer - for (Iterator i = getRosterItems(); i.hasNext();) { - Item entry = (Item) i.next(); - buf.append(entry.toXML()); - } + buf.append("<").append(getElementName()).append(" xmlns=\"").append(getNamespace()).append( + "\">"); + // Loop through all roster entries and append them to the string buffer + for (Iterator i = getRosterEntries(); i.hasNext();) { + RemoteRosterEntry remoteRosterEntry = (RemoteRosterEntry) i.next(); + buf.append(remoteRosterEntry.toXML()); + } buf.append(""); return buf.toString(); } - - /** - * A roster item, which consists of a JID and , their name and - * the groups the roster item belongs to. - */ - public static class Item { - - private String user; - private String name; - private List groupNames; - - /** - * Creates a new roster item. - * - * @param user the user. - * @param name the user's name. - */ - public Item(String user, String name) { - this.user = user; - this.name = name; - groupNames = new ArrayList(); - } - - /** - * Returns the user. - * - * @return the user. - */ - public String getUser() { - return user; - } - - /** - * Returns the user's name. - * - * @return the user's name. - */ - public String getName() { - return name; - } - - /** - * Sets the user's name. - * - * @param name the user's name. - */ - public void setName(String name) { - this.name = name; - } - - /** - * Returns an Iterator for the group names (as Strings) that the roster item - * belongs to. - * - * @return an Iterator for the group names. - */ - public Iterator getGroupNames() { - synchronized (groupNames) { - return Collections.unmodifiableList(groupNames).iterator(); - } - } - - /** - * Returns a String array for the group names that the roster item - * belongs to. - * - * @return a String[] for the group names. - */ - public String[] getGroupArrayNames() { - synchronized (groupNames) { - return (String[])(Collections.unmodifiableList(groupNames).toArray(new String[groupNames.size()])); - } - } - - /** - * Adds a group name. - * - * @param groupName the group name. - */ - public void addGroupName(String groupName) { - synchronized (groupNames) { - if (!groupNames.contains(groupName)) { - groupNames.add(groupName); - } - } - } - - /** - * Removes a group name. - * - * @param groupName the group name. - */ - public void removeGroupName(String groupName) { - synchronized (groupNames) { - groupNames.remove(groupName); - } - } - - public String toXML() { - StringBuffer buf = new StringBuffer(); - buf.append(""); - synchronized (groupNames) { - for (int i = 0; i < groupNames.size(); i++) { - String groupName = (String) groupNames.get(i); - buf.append("").append(groupName).append(""); - } - } - buf.append(""); - return buf.toString(); - } - } } diff --git a/source/org/jivesoftware/smackx/provider/RosterExchangeProvider.java b/source/org/jivesoftware/smackx/provider/RosterExchangeProvider.java index 1b1b850ce..69ce09880 100644 --- a/source/org/jivesoftware/smackx/provider/RosterExchangeProvider.java +++ b/source/org/jivesoftware/smackx/provider/RosterExchangeProvider.java @@ -83,7 +83,7 @@ public class RosterExchangeProvider implements PacketExtensionProvider { RosterExchange rosterExchange = new RosterExchange(); boolean done = false; - RosterExchange.Item item = null; + RemoteRosterEntry remoteRosterEntry = null; while (!done) { int eventType = parser.next(); if (eventType == XmlPullParser.START_TAG) { @@ -91,15 +91,15 @@ public class RosterExchangeProvider implements PacketExtensionProvider { String jid = parser.getAttributeValue("", "jid"); String name = parser.getAttributeValue("", "name"); // Create packet. - item = new RosterExchange.Item(jid, name); + remoteRosterEntry = new RemoteRosterEntry(jid, name); } if (parser.getName().equals("group")) { String groupName = parser.nextText(); - item.addGroupName(groupName); + remoteRosterEntry.addGroupName(groupName); } } else if (eventType == XmlPullParser.END_TAG) { if (parser.getName().equals("item")) { - rosterExchange.addRosterItem(item); + rosterExchange.addRosterEntry(remoteRosterEntry); } if (parser.getName().equals("x")) { done = true; diff --git a/test/org/jivesoftware/smackx/RosterExchangeManagerTest.java b/test/org/jivesoftware/smackx/RosterExchangeManagerTest.java new file mode 100644 index 000000000..2c54de44f --- /dev/null +++ b/test/org/jivesoftware/smackx/RosterExchangeManagerTest.java @@ -0,0 +1,306 @@ +/** + * $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.smackx; + +import java.util.Iterator; + +import junit.framework.TestCase; + +import org.jivesoftware.smack.*; +import org.jivesoftware.smackx.packet.RemoteRosterEntry; + + +/** + * + * Test the Roster Exchange extension using the high level API + * + * @author Gaston Dombiak + */ +public class RosterExchangeManagerTest extends TestCase { + + private int entriesSent; + private int entriesReceived; + + /** + * Constructor for RosterExchangeManagerTest. + * @param name + */ + public RosterExchangeManagerTest(String name) { + super(name); + } + + /** + * High level API test. + * This is a simple test to use with a XMPP client and check if the client receives user1's roster + * 1. User_1 will send his/her roster to user_2 + */ + public void testSendRoster() { + String host = "localhost"; + String server_user1 = "gato3"; + String user1 = "gato3@localhost"; + String pass1 = "gato3"; + + String user2 = "gato4@localhost"; + + XMPPConnection conn1 = null; + + try { + // Connect to the server and log in the users + conn1 = new XMPPConnection(host); + conn1.login(server_user1, pass1); + + // Send user1's roster to user2 + try { + RosterExchangeManager rosterExchangeManager = new RosterExchangeManager(conn1); + rosterExchangeManager.send(conn1.getRoster(), user2); + // Wait half second so that the complete test can run + Thread.sleep(500); + } catch (Exception e) { + e.printStackTrace(); + fail("An error occured sending the roster"); + } + + } catch (Exception e) { + fail(e.toString()); + } finally { + if (conn1 != null) + conn1.close(); + } + + } + + /** + * High level API test. + * This is a simple test to use with a XMPP client and check if the client receives user1's roster groups + * 1. User_1 will send his/her RosterGroups to user_2 + */ + public void testSendRosterGroup() { + String host = "localhost"; + String server_user1 = "gato3"; + String user1 = "gato3@localhost"; + String pass1 = "gato3"; + + String user2 = "gato4@localhost"; + + XMPPConnection conn1 = null; + + try { + // Connect to the server and log in the users + conn1 = new XMPPConnection(host); + conn1.login(server_user1, pass1); + + // Send user1's RosterGroups to user2 + try { + RosterExchangeManager rosterExchangeManager = new RosterExchangeManager(conn1); + for (Iterator it = conn1.getRoster().getGroups(); it.hasNext(); ) + rosterExchangeManager.send((RosterGroup)it.next(), user2); + // Wait half second so that the complete test can run + Thread.sleep(500); + } catch (Exception e) { + e.printStackTrace(); + fail("An error occured sending the roster"); + } + + } catch (Exception e) { + fail(e.toString()); + } finally { + if (conn1 != null) + conn1.close(); + } + + } + + /** + * High level API test. + * 1. User_1 will send his/her roster to user_2 + * 2. User_2 will receive the entries and iterate over them to check if everything is fine + * 3. User_1 will wait several seconds for an ACK from user_2, if none is received then something is wrong + */ + public void testSendAndReceiveRoster() { + String host = "localhost"; + String server_user1 = "gato3"; + String user1 = "gato3@localhost"; + String pass1 = "gato3"; + + String server_user2 = "gato4"; + String user2 = "gato4@localhost"; + String pass2 = "gato4"; + + XMPPConnection conn1 = null; + XMPPConnection conn2 = null; + + try { + // Connect to the server and log in the users + conn1 = new XMPPConnection(host); + conn1.login(server_user1, pass1); + conn2 = new XMPPConnection(host); + conn2.login(server_user2, pass2); + + RosterExchangeManager rosterExchangeManager1 = new RosterExchangeManager(conn1); + RosterExchangeManager rosterExchangeManager2 = new RosterExchangeManager(conn2); + + // Create a RosterExchangeListener that will iterate over the received roster entries + RosterExchangeListener rosterExchangeListener = new RosterExchangeListener() { + public void entriesReceived(String from, Iterator remoteRosterEntries) { + int received = 0; + assertNotNull("From is null", from); + assertNotNull("rosterEntries is null",remoteRosterEntries); + assertTrue("Roster without entries",remoteRosterEntries.hasNext()); + while (remoteRosterEntries.hasNext()) { + received++; + RemoteRosterEntry remoteEntry = (RemoteRosterEntry) remoteRosterEntries.next(); + System.out.println(remoteEntry); + } + entriesReceived = received; + } + }; + rosterExchangeManager2.addRosterListener(rosterExchangeListener); + + // Send user1's roster to user2 + try { + entriesSent = conn1.getRoster().getEntryCount(); + entriesReceived = 0; + rosterExchangeManager1.send(conn1.getRoster(), user2); + } catch (Exception e) { + fail("An error occured sending the message with the roster"); + } + // Wait for 2 seconds + Thread.sleep(2000); + assertEquals("Number of sent and received entries does not match", entriesSent, entriesReceived); + } catch (Exception e) { + fail(e.toString()); + } finally { + if (conn1 != null) + conn1.close(); + if (conn2 != null) + conn2.close(); + } + } + + /** + * High level API test. + * 1. User_1 will send his/her roster to user_2 + * 2. User_2 will automatically add the entries that receives to his/her roster in the corresponding group + * 3. User_1 will wait several seconds for an ACK from user_2, if none is received then something is wrong + */ + public void testSendAndAcceptRoster() { + String host = "localhost"; + String server_user1 = "gato3"; + String user1 = "gato3@localhost"; + String pass1 = "gato3"; + + String server_user2 = "gato4"; + String user2 = "gato4@localhost"; + String pass2 = "gato4"; + + XMPPConnection conn1 = null; + XMPPConnection conn2 = null; + + try { + // Connect to the server and log in the users + conn1 = new XMPPConnection(host); + conn1.login(server_user1, pass1); + conn2 = new XMPPConnection(host); + conn2.login(server_user2, pass2); + final Roster user2_roster = conn2.getRoster(); + + RosterExchangeManager rosterExchangeManager1 = new RosterExchangeManager(conn1); + RosterExchangeManager rosterExchangeManager2 = new RosterExchangeManager(conn2); + + // Create a RosterExchangeListener that will accept all the received roster entries + RosterExchangeListener rosterExchangeListener = new RosterExchangeListener() { + public void entriesReceived(String from, Iterator remoteRosterEntries) { + int received = 0; + assertNotNull("From is null", from); + assertNotNull("remoteRosterEntries is null",remoteRosterEntries); + assertTrue("Roster without entries",remoteRosterEntries.hasNext()); + while (remoteRosterEntries.hasNext()) { + received++; + try { + RemoteRosterEntry remoteRosterEntry = (RemoteRosterEntry) remoteRosterEntries.next(); + user2_roster.createEntry( + remoteRosterEntry.getUser(), + remoteRosterEntry.getName(), + remoteRosterEntry.getGroupArrayNames()); + } + catch (XMPPException e) { + fail(e.toString()); + } + } + entriesReceived = received; + } + }; + rosterExchangeManager2.addRosterListener(rosterExchangeListener); + + // Send user1's roster to user2 + try { + entriesSent = conn1.getRoster().getEntryCount(); + entriesReceived = 0; + rosterExchangeManager1.send(conn1.getRoster(), user2); + } catch (Exception e) { + fail("An error occured sending the message with the roster"); + } + // Wait for 2 seconds + Thread.sleep(2000); + assertEquals("Number of sent and received entries does not match", entriesSent, entriesReceived); + } catch (Exception e) { + fail(e.toString()); + } finally { + if (conn1 != null) + conn1.close(); + if (conn2 != null) + conn2.close(); + } + } + +} diff --git a/test/org/jivesoftware/smackx/RosterExchangeTests.java b/test/org/jivesoftware/smackx/RosterExchangeTests.java new file mode 100644 index 000000000..a324c6d20 --- /dev/null +++ b/test/org/jivesoftware/smackx/RosterExchangeTests.java @@ -0,0 +1,76 @@ +/** + * $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.smackx; + +import org.jivesoftware.smackx.packet.RosterExchangeTest; + +import junit.framework.Test; +import junit.framework.TestSuite; + +/** + * + * Test suite that runs all the Roster Exchange extension tests + * + * @author Gaston Dombiak + */ +public class RosterExchangeTests { + + public static Test suite() { + TestSuite suite = new TestSuite("High and low level API tests for roster exchange extension"); + //$JUnit-BEGIN$ + suite.addTest(new TestSuite(RosterExchangeManagerTest.class)); + suite.addTest(new TestSuite(RosterExchangeTest.class)); + //$JUnit-END$ + return suite; + } +} diff --git a/test/org/jivesoftware/smackx/packet/RosterExchangeTest.java b/test/org/jivesoftware/smackx/packet/RosterExchangeTest.java index 981db2c93..03b720fb2 100644 --- a/test/org/jivesoftware/smackx/packet/RosterExchangeTest.java +++ b/test/org/jivesoftware/smackx/packet/RosterExchangeTest.java @@ -9,13 +9,12 @@ import java.util.Iterator; import org.jivesoftware.smack.*; import org.jivesoftware.smack.filter.*; import org.jivesoftware.smack.packet.*; -import org.jivesoftware.smackx.packet.RosterExchange; import junit.framework.TestCase; /** * - * Test the Roster Exchange extension + * Test the Roster Exchange extension using the low level API * * @author Gaston Dombiak */ @@ -29,20 +28,68 @@ public class RosterExchangeTest extends TestCase { super(arg0); } - /** - * 1. User_1 will send his/her roster entries to user_2 - * 2. User_2 will receives the entries and iterate over them to check if everything is fine - * 3. User_1 will wait several seconds for an ACK from user_2, if none is received then something is wrong - */ + /** + * Low level API test. + * This is a simple test to use with a XMPP client and check if the client receives the message + * 1. User_1 will send his/her roster entries to user_2 + */ + public void testSendRosterEntries() { + String host = "localhost"; + String server_user1 = "gato3"; + String user1 = "gato3@localhost"; + String pass1 = "gato3"; + + String user2 = "gato4@localhost"; + + XMPPConnection conn1 = null; + + try { + // Connect to the server and log in the users + conn1 = new XMPPConnection(host); + conn1.login(server_user1, pass1); + + // Create a chat for each connection + Chat chat1 = conn1.createChat(user2); + + // Create the message to send with the roster + Message msg = chat1.createMessage(); + msg.setSubject("Any subject you want"); + msg.setBody("This message contains roster items."); + // Create a RosterExchange Package and add it to the message + assertTrue("Roster has no entries", conn1.getRoster().getEntryCount() > 0); + RosterExchange rosterExchange = new RosterExchange(conn1.getRoster()); + msg.addExtension(rosterExchange); + + // Send the message that contains the roster + try { + chat1.sendMessage(msg); + } catch (Exception e) { + fail("An error occured sending the message with the roster"); + } + } catch (Exception e) { + fail(e.toString()); + } finally { + if (conn1 != null) + conn1.close(); + } + + } + + /** + * Low level API test. + * 1. User_1 will send his/her roster entries to user_2 + * 2. User_2 will receive the entries and iterate over them to check if everything is fine + * 3. User_1 will wait several seconds for an ACK from user_2, if none is received then something is wrong + */ public void testSendAndReceiveRosterEntries() { String host = "localhost"; String server_user1 = "gato3"; - String user1 = "gato3@gato.home"; + String user1 = "gato3@localhost"; String pass1 = "gato3"; - String server_user2 = "gato1"; - String user2 = "gato1@gato.home"; - String pass2 = "gato1"; + String server_user2 = "gato4"; + String user2 = "gato4@localhost"; + String pass2 = "gato4"; XMPPConnection conn1 = null; XMPPConnection conn2 = null; @@ -66,14 +113,18 @@ public class RosterExchangeTest extends TestCase { Message message = (Message) packet; assertNotNull("Body is null", message.getBody()); try { - RosterExchange rosterExchange = (RosterExchange) message.getExtension("x","jabber:x:roster"); - assertNotNull("Message without extension \"jabber:x:roster\"", rosterExchange); - assertTrue("Roster without entries", rosterExchange.getRosterItems().hasNext()); - for (Iterator it = rosterExchange.getRosterItems(); it.hasNext();) { - RosterExchange.Item item = (RosterExchange.Item) it.next(); + RosterExchange rosterExchange = + (RosterExchange) message.getExtension("x", "jabber:x:roster"); + assertNotNull( + "Message without extension \"jabber:x:roster\"", + rosterExchange); + assertTrue( + "Roster without entries", + rosterExchange.getRosterEntries().hasNext()); + for (Iterator it = rosterExchange.getRosterEntries(); it.hasNext();) { + RemoteRosterEntry remoteRosterEntry = (RemoteRosterEntry) it.next(); } - } - catch (ClassCastException e){ + } catch (ClassCastException e) { fail("ClassCastException - Most probable cause is that smack providers is misconfigured"); } try { @@ -86,10 +137,11 @@ public class RosterExchangeTest extends TestCase { conn2.addPacketListener(packetListener, packetFilter); // Create the message to send with the roster - Message msg = new Message(user2); + Message msg = chat1.createMessage(); msg.setSubject("Any subject you want"); msg.setBody("This message contains roster items."); // Create a RosterExchange Package and add it to the message + assertTrue("Roster has no entries", conn1.getRoster().getEntryCount() > 0); RosterExchange rosterExchange = new RosterExchange(conn1.getRoster()); msg.addExtension(rosterExchange); @@ -102,11 +154,9 @@ public class RosterExchangeTest extends TestCase { // Wait for 2 seconds for a reply msg = chat1.nextMessage(2000); assertNotNull("No reply received", msg); - } - catch (Exception e) { + } catch (Exception e) { fail(e.toString()); - } - finally { + } finally { if (conn1 != null) conn1.close(); if (conn2 != null) @@ -115,19 +165,20 @@ public class RosterExchangeTest extends TestCase { } - /** - * 1. User_1 will send his/her roster entries to user_2 - * 2. User_2 will automatically add the entries that receives to his/her roster in the corresponding group - * 3. User_1 will wait several seconds for an ACK from user_2, if none is received then something is wrong - */ + /** + * Low level API test. + * 1. User_1 will send his/her roster entries to user_2 + * 2. User_2 will automatically add the entries that receives to his/her roster in the corresponding group + * 3. User_1 will wait several seconds for an ACK from user_2, if none is received then something is wrong + */ public void testSendAndAcceptRosterEntries() { String host = "localhost"; String server_user1 = "gato3"; - String user1 = "gato3@gato.home"; + String user1 = "gato3@localhost"; String pass1 = "gato3"; String server_user2 = "gato4"; - String user2 = "gato4@gato.home"; + String user2 = "gato4@localhost"; String pass2 = "gato4"; XMPPConnection conn1 = null; @@ -153,20 +204,26 @@ public class RosterExchangeTest extends TestCase { Message message = (Message) packet; assertNotNull("Body is null", message.getBody()); try { - RosterExchange rosterExchange = (RosterExchange) message.getExtension("x","jabber:x:roster"); - assertNotNull("Message without extension \"jabber:x:roster\"", rosterExchange); - assertTrue("Roster without entries", rosterExchange.getRosterItems().hasNext()); + RosterExchange rosterExchange = + (RosterExchange) message.getExtension("x", "jabber:x:roster"); + assertNotNull( + "Message without extension \"jabber:x:roster\"", + rosterExchange); + assertTrue( + "Roster without entries", + rosterExchange.getRosterEntries().hasNext()); // Add the roster entries to user2's roster - for (Iterator it = rosterExchange.getRosterItems(); it.hasNext();) { - RosterExchange.Item item = (RosterExchange.Item) it.next(); - user2_roster.createEntry(item.getUser(), item.getName(), item.getGroupArrayNames()); + for (Iterator it = rosterExchange.getRosterEntries(); it.hasNext();) { + RemoteRosterEntry remoteRosterEntry = (RemoteRosterEntry) it.next(); + user2_roster.createEntry( + remoteRosterEntry.getUser(), + remoteRosterEntry.getName(), + remoteRosterEntry.getGroupArrayNames()); } - } - catch (ClassCastException e){ + } catch (ClassCastException e) { fail("ClassCastException - Most probable cause is that smack providers is misconfigured"); - } - catch (Exception e) { - fail(e.toString()); + } catch (Exception e) { + fail(e.toString()); } try { chat2.sendMessage("ok"); @@ -178,10 +235,11 @@ public class RosterExchangeTest extends TestCase { conn2.addPacketListener(packetListener, packetFilter); // Create the message to send with the roster - Message msg = new Message(user2); + Message msg = chat1.createMessage(); msg.setSubject("Any subject you want"); msg.setBody("This message contains roster items."); // Create a RosterExchange Package and add it to the message + assertTrue("Roster has no entries", conn1.getRoster().getEntryCount() > 0); RosterExchange rosterExchange = new RosterExchange(conn1.getRoster()); msg.addExtension(rosterExchange); @@ -194,11 +252,9 @@ public class RosterExchangeTest extends TestCase { // Wait for 10 seconds for a reply msg = chat1.nextMessage(5000); assertNotNull("No reply received", msg); - } - catch (Exception e) { + } catch (Exception e) { fail(e.toString()); - } - finally { + } finally { if (conn1 != null) conn1.close(); if (conn2 != null)