I am using the following code to get the contact list for a given user. I am not getting the list at all. The Iterator comes back empty. I used Exodus client for the same user, and I am getting the contact list correctly. What am I doing wrong?
XMPPConnection conn1 = new XMPPConnection(“localhost”);
I don’‘t think roster support is complete in beta 3. The release notes indicate that it is only partially implemented. I’'ll try to poke Matt on this to confirm/deny.
I guess the real solution is to add a simple listener so that you can know when to load the roster after changes. I’'ll try to get this done for the next beta.
Oh, I guess another option is that I could make Smack wait to get the roster back from the server before returning from the login method. Currently, the following method is called during login (from the Roster class)
/** * 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());
}
I could make another version of that method that waited for a reply instead. Anyone have an opinion on what would be better? I guess I’‘d lean towards making Smack load the roster synchronously during login since we’'ve already seen the confusion that the current behavior causes.
I would say that since the Roster is like the other high-level components of the library, I would make it act like the Message, Chat, GroupChat object with the same type of “PollMessage”/queue type arrangement. Or just add a “loadCompleted()” method call.
I don’‘t think the login method should block, but the conn.getRoster() probably should. Maybe even eliminate and roster stuff from the login method altogether though I guess it would speed things up if login went ahead and asked for it async but getRoster blocks until it’'s completed.
I agree with this approach. I have tried to make the getRoster() method blocking and made the GUI application that is loading the roster to execute in a separate thread. Here are some of my suggested codes:
private boolean isRosterReady = false;
public Iterator getGroups() {
while (!isRosterReady) {
try {
wait();
} catch (InterruptedException ie) {
}
}
synchronized (groups) {
List groupsList = Collections.unmodifiableList(new ArrayList(groups.values()));
return groupsList.iterator();
}
}
private class RosterListener implements PacketListener {
public void processPacket(Packet packet) {
isRosterReady = false;
// same as the rest of the code body
// Notify waiting threads that the roster groups are ready.
Just thought you’'d want to know that the latest build fixes the roster problem – it now waits up to two seconds for a reply from the server before returning the roster. Daily builds are at:
I noted a number of other potential problems with the roster.
The roster needs to have a blocking thread operation which fires an event when the roster is completely loaded. This can be done by implementing another static class (such as RosterSynchronizer) to handle roster synchronization. A statement such as “RosterSynchronizer.getRosterSynchronizer().setRosterReady();” can be set at the end of the method “processPacket(Packet packet)” in class RosterListener now.
Similarly, the call to roster.getGroups() should be blocked by a statement like “RosterSynchronizer.getRosterSynchronizer().waitRoster();”
Another problem is that there could be a race problem between Presence messages that are sent by the server even before the roster packet is sent or completely loaded. In this case, all Presence packets need to be pre-stored in an early-queue until the roster ready event is fired. Once the roster is ready, the early Presence packets will need to be processed. Else, the presence info will be lost!
Hope I intepret the potential problems correctly and got the message across correctly