powered by Jive Software

Presence always returns unavailable

I have some fairly simple code where I connect to our OpenFire server and return the user’s roster. When I iterate over the roster and check for presence, I always see “unavailable” despite certain users being logged in. I have verified that certain users are logged via the OpenFire session admin page. That admin page shows correct presence and status information, neither of which is returned in my example application.

    // Login to XMPP server
    ConnectionConfiguration config = new ConnectionConfiguration(SERVER, PORT);
    XMPPConnection conn = new XMPPConnection(config);
    conn.connect();
    conn.login(USERNAME, PASSWORD, RESOURCE);
   
     // Return the user roster
    Roster roster = conn.getRoster();
    Collection<RosterEntry> entries = roster.getEntries();
    for (RosterEntry entry : entries)
    {
        Presence presence = roster.getPresence(entry.getUser());
        System.out.println(entry + "\t" + presence.isAvailable() + "\t" + presence.getStatus());
    }
   
     // Disconnect from XMPP server
    conn.disconnect();

Running the above always produces output of the form: User Name: User ID [Group] false null

for every user regardless of their actual presence. Does anyone know why this is happening? TIA,

Mike

I have figured out a work-around for the problem, but the solution isn’t satisfying, so I am going to let this remain an open question and hopefully someone will be able to provide the proper way to handle this issue. I can solve the presence problem by simply pausing the current thread by a second after calling connection.getRoster().

The original code reports everyone being unavailable despite their state

// Get the roster
Roster roster = conn.getRoster();

// Get presence information

Collection entries = roster.getEntries();

for (RosterEntry entry : entries) {
Presence presence = roster.getPresence(entry.getUser());
System.out.println(entry);

System.out.println(presence.isAvailable()

System.out.println(presence.getStatus());

}

All that is in the new code is a one second pause after the call to get the roster.

// Get the roster
Roster roster = conn.getRoster();

// Sleep for a second

try { Thread.sleep(1000); } catch (InterruptedException e) { }

// Get presence information

Collection entries = roster.getEntries();

for (RosterEntry entry : entries) {
Presence presence = roster.getPresence(entry.getUser());
System.out.println(entry);

System.out.println(presence.isAvailable()

System.out.println(presence.getStatus());

}

From this it appears that the Roster object is being created and returned immediately while the population of the object is happening asynchronously. I haven’t yet written code to use RosterListener, but would using that class prevent this race condition? That is, rather than get presence directly from the Roster as in the code above, use a RosterListener and only get presence information only when notified. I’ll have to write some code and try it out later this evening. Hopefully I have just solved my own problem. We’ll see.

You’ve hit the nail on the head, after you successfully login you can grab a copy of your roster, however the information about your various contacts may not have been received.

You can simply add a roster listener and have that update your contact list as you recieve the new information.

You’ll also probably notice most IM clients have a loading/splash screen, I’d imagine this is done so that a more up-to-date roster can finally be displayed

Jon

Using RosterListener is the proper solution to this problem. There is no reason that code should have a Thread.sleep() in order to make it work properly. I am only following up to this thread to let folks know that the documentation for Roster and Presence needs to be updated. If there is another environment where I should post this request, please let me know.

Being new to SMACK, I was following the simple examples here: http://www.igniterealtime.org/builds/smack/docs/latest/documentation/roster.html. While RosterListener is discussed along with the other roster methods, there isn’t any discussion of the pitfall I’ve discovered. Nor is there anything saying that RosterListener is preferred. RosterListener would most likely be employeed in a lot of use cases, so it’s not really a big deal from that aspect. However, someone very new to the API could be confused as I was when taking the sample code presented on the page and trying to work with it. I thought that I would write a very simple test app before moving on to RosterListener, but as it turns out that simple code did not want to work. I spent quite a bit of time trying to figure out what was going on and a short note in the Presence section about this behavior would have been extremely useful.

1 Like