Checking presence synchronously

Hey, folks,

I’'m building an application where I need to check the presence of a user synchronously. That is, given an XMPP address (user@server), I need to see if that user is online prior to doing what I need to do with that address.

The only way I can find to check presence is by getting a roster from XMPPConnection.getRoster, adding the user with roster.createEntry(…), and checking the presence using roster.getPresence(…). Unfortunately, createEntry is asynchronous, and the following code will therefore perform erratically:

Roster roster = con.getRoster();

roster.createEntry(address, “user”, null);

if (roster.getPresence(address)!=null){…}

So… what should I do? Is there a synchronous way to do this? If not, is there a way to call createEntry and block until it’'s finished? If not… how long should a pause should I insert between lines two and three of the above code? (Yes, the messiness of that solution would make me sad, but it would work.)

Thanks!

Shawn,

Is the set of users you’‘re checking presence for deterministic or dynamic? If it’‘s dynamic, you actually have to wait for the user to accept the subscription request – the user could accept within 5 seconds, or it it could take 5 days. If that’‘s the case, you’‘ll need to have a timeout anyway to protect agains the 5 day case so that would actually be a decent approach. Alternatively, if you’'re doing something a bit more custom (like the actual users are bots and they automatically accept presence subscriptions) then you have some other options.

-Matt

Thanks for the quick reply, Matt,

The user I’‘m adding to my roster is a bot who will automatically accept. What are these other options you’'re referring to?

Ok, that helps. The solution isn’‘t super easy still, but it should work. There’‘s a listener for roster changes. So, you should be able to make the roster add call, add a listener, and then wait for the listener to be triggered. After the listener is triggered, you’'ll probably want to wait up to 1 second for the server to send an actual presence packet for the new user in your roster.

Regards,

-Matt

OK, this is good, but I’'m still a bit confused. It seems like I should:

  1. add roster listener.

  2. update roster.

On listener trigger, I should 3) check presence

  1. do whatever I’'m going to do with the presence.

Between which actions is the extra 1 second wait, and why?

Okay, here’'s an update:

The following code synchronously checks presence, with the caveat that I didn’‘t fully understand Matt’‘s last post, and with one exception. If it is called from two different threads, it may behave erratically: rosterModified will be called for both threads’’ listeners when the first presence is added, and because rosterModified doesn’‘t have a parameter, there’‘s no way to tell which thread should not yet continue. (It’‘s not possible to use presenceChanged(…) because it isn’'t called if the user is offline.) How do I fix my problem?

if (!roster.contains(addr)){
         System.out.println(addr+" not in roster!");
         final boolean inRoster [] = {false};
         final Object lock = new Object();
         roster.addRosterListener(new RosterListener () {
              public void presenceChanged(String updatedAddr){    }
              public void rosterModified(){
               System.out.println("In rosterModified.");
               synchronized(lock){
                   inRoster[0] = true;
                   lock.notifyAll();
               }
              }
          });
         try{
          System.out.println("adding "+addr+"...");
          roster.createEntry(addr, addr, null);
         }
         catch(XMPPException e){
         }
         synchronized(lock){
          while (inRoster[0] == false) {
              try{
               lock.wait();
              }catch (Exception e){
              }
          }
         }
     }      return (roster.getPresence(addr) != null);

Thanks!

PS: I noticed while previewing that my formatting was removed. Sorry.

Message was edited by:

dombiak_gaston (Added code formatting)

I figured this all out, thanks. If anyone else is trying to check presence synchronously, the code above doesn’'t work for at least two reasons:

  1. You are not necessarily subscribed to the presence of a roster entry, so you can’‘t use roster.contains(…) to check if you’'re subscribed.

  2. When this function is called by multiple threads simultaneously, the presence packets from the first roster update will cause both threads to continue execution.

Both of these problems can be solved by checking the type of the roster entry; see the other recent thread on roster entries.