diff --git a/source/org/jivesoftware/smack/Roster.java b/source/org/jivesoftware/smack/Roster.java index aeee8a3f2..eb81024c2 100644 --- a/source/org/jivesoftware/smack/Roster.java +++ b/source/org/jivesoftware/smack/Roster.java @@ -36,10 +36,6 @@ import java.util.*; *
  • SUBSCRIPTION_REJECT_ALL -- reject all subscription requests. *
  • SUBSCRIPTION_MANUAL -- manually process all subscription requests. * - * 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 */ @@ -244,6 +240,7 @@ public class Roster { new PacketIDFilter(rosterPacket.getPacketID())); connection.sendPacket(rosterPacket); IQ response = (IQ)collector.nextResult(SmackConfiguration.getPacketReplyTimeout()); + collector.cancel(); if (response == null) { throw new XMPPException("No response from the server."); } @@ -251,7 +248,6 @@ public class Roster { else if (response.getType() == IQ.Type.ERROR) { throw new XMPPException(response.getError()); } - collector.cancel(); // Create a presence subscription packet and send. Presence presencePacket = new Presence(Presence.Type.SUBSCRIBE); @@ -262,24 +258,40 @@ public class Roster { /** * Removes a roster entry from the roster. The roster entry will also be removed from the * unfiled entries or from any roster group where it could belong and will no longer be part - * of the roster. + * of the roster. Note that this is an asynchronous call -- Smack must wait for the server + * to send an updated subscription status. * * @param entry a roster entry. */ - public void removeEntry(RosterEntry entry) { + public void removeEntry(RosterEntry entry) throws XMPPException { // Only remove the entry if it's in the entry list. // The actual removal logic takes place in RosterPacketListenerprocess>>Packet(Packet) synchronized (entries) { - if (entries.contains(entry)) { - RosterPacket packet = new RosterPacket(); - packet.setType(IQ.Type.SET); - RosterPacket.Item item = RosterEntry.toRosterItem(entry); - // Set the item type as REMOVE so that the server will delete the entry - item.setItemType(RosterPacket.ItemType.REMOVE); - packet.addRosterItem(item); - connection.sendPacket(packet); + if (!entries.contains(entry)) { + return; } } + RosterPacket packet = new RosterPacket(); + packet.setType(IQ.Type.SET); + RosterPacket.Item item = RosterEntry.toRosterItem(entry); + // Set the item type as REMOVE so that the server will delete the entry + item.setItemType(RosterPacket.ItemType.REMOVE); + packet.addRosterItem(item); + PacketCollector collector = connection.createPacketCollector( + new PacketIDFilter(packet.getPacketID())); + connection.sendPacket(packet); + IQ response = (IQ)collector.nextResult(SmackConfiguration.getPacketReplyTimeout()); + collector.cancel(); + if (response == null) { + throw new XMPPException("No response from the server."); + } + // If the server replied with an error, throw an exception. + else if (response.getType() == IQ.Type.ERROR) { + throw new XMPPException(response.getError()); + } + else { + + } } /** @@ -756,7 +768,10 @@ public class Roster { } // Mark the roster as initialized. - rosterInitialized = true; + synchronized (this) { + rosterInitialized = true; + notifyAll(); + } // Fire event for roster listeners. fireRosterChangedEvent(); diff --git a/source/org/jivesoftware/smack/XMPPConnection.java b/source/org/jivesoftware/smack/XMPPConnection.java index bec91a0d1..4b36e6aeb 100644 --- a/source/org/jivesoftware/smack/XMPPConnection.java +++ b/source/org/jivesoftware/smack/XMPPConnection.java @@ -418,20 +418,27 @@ public class XMPPConnection { return null; } // If this is the first time the user has asked for the roster after calling - // login, we want to wait up to 2 seconds for the server to send back the - // user's roster. This behavior shields API users from having to worry about the - // fact that roster operations are asynchronous, although they'll still have to - // listen for changes to the roster. Note: because of this waiting logic, internal + // login, we want to wait for the server to send back the user's roster. This + // behavior shields API users from having to worry about the fact that roster + // operations are asynchronous, although they'll still have to listen for + // changes to the roster. Note: because of this waiting logic, internal // Smack code should be wary about calling the getRoster method, and may need to // access the roster object directly. - int elapsed = 0; - while (!roster.rosterInitialized && elapsed <= 2000) { + if (!roster.rosterInitialized) { try { - Thread.sleep(500); + synchronized (roster) { + long waitTime = SmackConfiguration.getPacketReplyTimeout(); + long start = System.currentTimeMillis(); + while (!roster.rosterInitialized) { + if (waitTime <= 0) { + break; + } + roster.wait(waitTime); + waitTime -= System.currentTimeMillis() - start; + } + } } - catch (Exception e) { - } - elapsed += 500; + catch (InterruptedException ie) { } } return roster; } @@ -724,7 +731,12 @@ public class XMPPConnection { Class.forName("org.jivesoftware.smackx.debugger.EnhancedDebugger"); } catch (Exception ex) { - debuggerClass = LiteDebugger.class; + try { + debuggerClass = Class.forName("org.jivesoftware.smack.debugger.LiteDebugger"); + } + catch (Exception ex2) { + ex2.printStackTrace(); + } } } // Create a new debugger instance. If an exception occurs then disable the debugging