public Roster getRoster() {
    // synchronize against login()
    synchronized (this) {
      // if connection is authenticated the roster is already set by login()
      // or a previous call to getRoster()
      if (!isAuthenticated() || isAnonymous()) {
        if (roster == null) {
          roster = new Roster(this);
        }
        return roster;
      }
    }

    if (!config.isRosterLoadedAtLogin()) {
      if (roster == null) {
        roster = new Roster(this);
      }
      roster.reload();
    }
    // If this is the first time the user has asked for the roster after calling
    // 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.
    if (!roster.rosterInitialized) {
      try {
        synchronized (roster) {
          long waitTime = SmackConfiguration.getPacketReplyTimeout();
          long start = System.currentTimeMillis();
          while (!roster.rosterInitialized) {
            if (waitTime <= 0) {
              break;
            }
            roster.wait(waitTime);
            long now = System.currentTimeMillis();
            waitTime -= now - start;
            start = now;
          }
        }
      } catch (InterruptedException ie) {
        // Ignore.
      }
    }
    return roster;
  }