/**
   * Permanently removes locally stored message history for the metacontact, remove any recent
   * contacts if any.
   */
  public void eraseLocallyStoredHistory(MetaContact contact) throws IOException {
    List<ComparableEvtObj> toRemove = null;
    synchronized (recentMessages) {
      toRemove = new ArrayList<ComparableEvtObj>();
      Iterator<Contact> iter = contact.getContacts();
      while (iter.hasNext()) {
        Contact item = iter.next();
        String id = item.getAddress();
        ProtocolProviderService provider = item.getProtocolProvider();

        for (ComparableEvtObj msc : recentMessages) {
          if (msc.getProtocolProviderService().equals(provider)
              && msc.getContactAddress().equals(id)) {
            toRemove.add(msc);
          }
        }
      }

      recentMessages.removeAll(toRemove);
    }
    if (recentQuery != null) {
      for (ComparableEvtObj msc : toRemove) {
        recentQuery.fireContactRemoved(msc);
      }
    }
  }
示例#2
0
  /**
   * Searches for additional phone numbers found in contact information
   *
   * @return additional phone numbers found in contact information;
   */
  private List<UIContactDetail> getAdditionalNumbers(boolean onlyMobile) {
    List<UIContactDetail> telephonyContacts = new ArrayList<UIContactDetail>();

    Iterator<Contact> contacts = getMetaContact().getContacts();

    while (contacts.hasNext()) {
      Contact contact = contacts.next();
      OperationSetServerStoredContactInfo infoOpSet =
          contact.getProtocolProvider().getOperationSet(OperationSetServerStoredContactInfo.class);
      Iterator<GenericDetail> details;
      ArrayList<String> phones = new ArrayList<String>();

      if (infoOpSet != null) {
        details = infoOpSet.getAllDetailsForContact(contact);

        while (details.hasNext()) {
          GenericDetail d = details.next();

          boolean process = false;

          if (onlyMobile) {
            if (d instanceof MobilePhoneDetail) process = true;
          } else if (d instanceof PhoneNumberDetail
              && !(d instanceof PagerDetail)
              && !(d instanceof FaxDetail)) {
            process = true;
          }

          if (process) {
            PhoneNumberDetail pnd = (PhoneNumberDetail) d;
            if (pnd.getNumber() != null && pnd.getNumber().length() > 0) {
              // skip phones which were already added
              if (phones.contains(pnd.getNumber())) continue;

              phones.add(pnd.getNumber());

              UIContactDetail cd =
                  new UIContactDetailImpl(
                      pnd.getNumber(),
                      pnd.getNumber() + " (" + getLocalizedPhoneNumber(d) + ")",
                      null,
                      new ArrayList<String>(),
                      GuiActivator.getResources().getImage("service.gui.icons.EXTERNAL_PHONE"),
                      null,
                      null,
                      pnd) {
                    @Override
                    public PresenceStatus getPresenceStatus() {
                      return null;
                    }
                  };
              telephonyContacts.add(cd);
            }
          }
        }
      }
    }

    return telephonyContacts;
  }
示例#3
0
  /**
   * Create a <tt>SourceContact</tt> from a <tt>GoogleContactsEntry</tt>.
   *
   * @param entry <tt>GoogleContactsEntry</tt>
   */
  private void onGoogleContactsEntry(GoogleContactsEntry entry) {
    String displayName = entry.getFullName();
    if (displayName == null || displayName.length() == 0) {
      if ((entry.getGivenName() == null || entry.getGivenName().length() == 0)
          && (entry.getFamilyName() == null || entry.getFamilyName().length() == 0)) {
        return;
      }

      displayName = entry.getGivenName() + " " + entry.getFamilyName();
    }

    List<ContactDetail> contactDetails = getContactDetails(entry);

    if (!contactDetails.isEmpty()) {
      GenericSourceContact sourceContact =
          new GenericSourceContact(getContactSource(), displayName, contactDetails);

      try {
        byte img[] =
            GoogleContactsServiceImpl.downloadPhoto(
                ((GoogleContactsEntryImpl) entry).getPhotoLink(),
                getContactSource().getConnection().getGoogleService());
        sourceContact.setImage(img);
      } catch (OutOfMemoryError oome) {
        // Ignore it, the image is not vital.
      }

      addQueryResult(sourceContact);
    }
  }
  /**
   * Process list of event objects. Checks whether message source contact already exist for this
   * event object, if yes just update it with the new values (not sure whether we should do this, as
   * it may bring old messages) and if status of provider is changed, init its details, updates its
   * capabilities. It still adds the found messages source contact to the list of the new contacts,
   * as later we will detect this and fire update event. If nothing found a new contact is created.
   *
   * @param res list of event
   * @param cachedRecentMessages list of newly created source contacts or already existed but
   *     updated with corresponding event object
   * @param isStatusChanged whether provider status changed and we are processing
   */
  private void processEventObjects(
      Collection<EventObject> res,
      List<ComparableEvtObj> cachedRecentMessages,
      boolean isStatusChanged) {
    for (EventObject obj : res) {
      ComparableEvtObj oldMsg = findRecentMessage(obj, recentMessages);

      if (oldMsg != null) {
        oldMsg.update(obj); // update

        if (isStatusChanged && recentQuery != null) recentQuery.updateCapabilities(oldMsg, obj);

        // we still add it to cachedRecentMessages
        // later we will find it is duplicate and will fire
        // update event
        if (!cachedRecentMessages.contains(oldMsg)) cachedRecentMessages.add(oldMsg);

        continue;
      }

      oldMsg = findRecentMessage(obj, cachedRecentMessages);

      if (oldMsg == null) {
        oldMsg = new ComparableEvtObj(obj);

        if (isStatusChanged && recentQuery != null) recentQuery.updateCapabilities(oldMsg, obj);

        cachedRecentMessages.add(oldMsg);
      }
    }
  }
  /**
   * When a provider is added. As searching can be slow especially when handling special type of
   * messages (with subType) this need to be run in new Thread.
   *
   * @param provider ProtocolProviderService
   */
  private void handleProviderAddedInSeparateThread(
      ProtocolProviderService provider, boolean isStatusChanged) {
    // lets check if we have cached recent messages for this provider, and
    // fire events if found and are newer

    synchronized (recentMessages) {
      List<ComparableEvtObj> cachedRecentMessages =
          getCachedRecentMessages(provider, isStatusChanged);

      if (cachedRecentMessages.isEmpty()) {
        // maybe there is no cached history for this
        // let's check
        // load it not from cache, but do a local search
        Collection<EventObject> res =
            messageHistoryService.findRecentMessagesPerContact(
                numberOfMessages, provider.getAccountID().getAccountUniqueID(), null, isSMSEnabled);

        List<ComparableEvtObj> newMsc = new ArrayList<ComparableEvtObj>();

        processEventObjects(res, newMsc, isStatusChanged);

        addNewRecentMessages(newMsc);

        for (ComparableEvtObj msc : newMsc) {
          saveRecentMessageToHistory(msc);
        }
      } else addNewRecentMessages(cachedRecentMessages);
    }
  }
  /**
   * Returns the index of the source contact, in the list of recent messages.
   *
   * @param messageSourceContact
   * @return
   */
  int getIndex(MessageSourceContact messageSourceContact) {
    synchronized (recentMessages) {
      for (int i = 0; i < recentMessages.size(); i++)
        if (recentMessages.get(i).equals(messageSourceContact)) return i;

      return -1;
    }
  }
示例#7
0
  /**
   * Fires a <tt>StreamSoundLevelEvent</tt> and notifies all registered listeners.
   *
   * @param level the new sound level
   */
  void fireStreamSoundLevelEvent(int level) {
    SoundLevelListener[] listeners;

    synchronized (soundLevelListeners) {
      listeners = soundLevelListeners.toArray(new SoundLevelListener[soundLevelListeners.size()]);
    }

    for (SoundLevelListener listener : listeners) listener.soundLevelChanged(this, level);
  }
  /**
   * Process candidates received.
   *
   * @param sessionInitIQ The {@link SessionIQ} that created the session we are handling here
   */
  public void processCandidates(SessionIQ sessionInitIQ) {
    Collection<PacketExtension> extensions = sessionInitIQ.getExtensions();
    List<GTalkCandidatePacketExtension> candidates = new ArrayList<GTalkCandidatePacketExtension>();

    for (PacketExtension ext : extensions) {
      if (ext.getElementName().equalsIgnoreCase(GTalkCandidatePacketExtension.ELEMENT_NAME)) {
        GTalkCandidatePacketExtension cand = (GTalkCandidatePacketExtension) ext;
        candidates.add(cand);
      }
    }

    try {
      getMediaHandler().processCandidates(candidates);
    } catch (OperationFailedException ofe) {
      logger.warn("Failed to process an incoming candidates", ofe);

      // send an error response
      String reasonText = "Error: " + ofe.getMessage();
      SessionIQ errResp =
          GTalkPacketFactory.createSessionTerminate(
              sessionInitIQ.getTo(),
              sessionInitIQ.getFrom(),
              sessionInitIQ.getID(),
              Reason.GENERAL_ERROR,
              reasonText);

      getMediaHandler().getTransportManager().close();
      setState(CallPeerState.FAILED, reasonText);
      getProtocolProvider().getConnection().sendPacket(errResp);
      return;
    }

    // HACK for FreeSwitch that send accept message before sending
    // candidates
    if (sessAcceptedWithNoCands != null) {
      if (isInitiator()) {
        try {
          answer();
        } catch (OperationFailedException e) {
          logger.info("Failed to answer call (FreeSwitch hack)");
        }
      } else {
        final SessionIQ sess = sessAcceptedWithNoCands;
        sessAcceptedWithNoCands = null;

        // run in another thread to not block smack receive thread and
        // possibly delay others candidates messages.
        new Thread() {
          @Override
          public void run() {
            processSessionAccept(sess);
          }
        }.start();
      }
      sessAcceptedWithNoCands = null;
    }
  }
示例#9
0
  /**
   * Returns a list of all <tt>UIContactDetail</tt>s within this <tt>UIContact</tt>.
   *
   * @return a list of all <tt>UIContactDetail</tt>s within this <tt>UIContact</tt>
   */
  public List<UIContactDetail> getContactDetails() {
    List<UIContactDetail> resultList = new LinkedList<UIContactDetail>();

    Iterator<Contact> contacts = metaContact.getContacts();

    while (contacts.hasNext()) {
      resultList.add(new MetaContactDetail(contacts.next()));
    }
    return resultList;
  }
示例#10
0
  /**
   * Returns a list of <tt>UIContactDetail</tt>s supporting the given <tt>OperationSet</tt> class.
   *
   * @param opSetClass the <tt>OperationSet</tt> class we're interested in
   * @return a list of <tt>UIContactDetail</tt>s supporting the given <tt>OperationSet</tt> class
   */
  public List<UIContactDetail> getContactDetailsForOperationSet(
      Class<? extends OperationSet> opSetClass) {
    List<UIContactDetail> resultList = new LinkedList<UIContactDetail>();

    Iterator<Contact> contacts = metaContact.getContactsForOperationSet(opSetClass).iterator();

    while (contacts.hasNext()) {
      resultList.add(new MetaContactDetail(contacts.next()));
    }
    return resultList;
  }
示例#11
0
  /** Initializes all search strings for this <tt>MetaUIGroup</tt>. */
  private void initSearchStrings() {
    searchStrings.add(metaContact.getDisplayName());

    Iterator<Contact> contacts = metaContact.getContacts();
    while (contacts.hasNext()) {
      Contact contact = contacts.next();

      searchStrings.add(contact.getDisplayName());
      searchStrings.add(contact.getAddress());
    }
  }
  /**
   * Returns a list of all <tt>ContactDetail</tt>s corresponding to the given category.
   *
   * @param category the <tt>OperationSet</tt> class we're looking for
   * @return a list of all <tt>ContactDetail</tt>s corresponding to the given category
   */
  public List<ContactDetail> getContactDetails(ContactDetail.Category category) {
    List<ContactDetail> contactDetails = new LinkedList<ContactDetail>();

    for (ContactDetail contactDetail : getContactDetails()) {
      if (contactDetail != null) {
        ContactDetail.Category detailCategory = contactDetail.getCategory();
        if (detailCategory != null && detailCategory.equals(category))
          contactDetails.add(contactDetail);
      }
    }
    return contactDetails;
  }
  /**
   * Gets the <tt>ContactDetail</tt>s of this <tt>SourceContact</tt> which support a specific
   * <tt>OperationSet</tt>.
   *
   * @param operationSet the <tt>OperationSet</tt> the supporting <tt>ContactDetail</tt>s of which
   *     are to be returned
   * @return the <tt>ContactDetail</tt>s of this <tt>SourceContact</tt> which support the specified
   *     <tt>operationSet</tt>
   * @see SourceContact#getContactDetails(Class)
   */
  public List<ContactDetail> getContactDetails(Class<? extends OperationSet> operationSet) {
    List<ContactDetail> contactDetails = new LinkedList<ContactDetail>();

    for (ContactDetail contactDetail : getContactDetails()) {
      List<Class<? extends OperationSet>> supportedOperationSets =
          contactDetail.getSupportedOperationSets();

      if ((supportedOperationSets != null) && supportedOperationSets.contains(operationSet))
        contactDetails.add(contactDetail);
    }
    return contactDetails;
  }
  /**
   * Creates an instance of this operation set.
   *
   * @param provider a reference to the <tt>ProtocolProviderServiceImpl</tt> that created us and
   *     that we'll use for retrieving the underlying aim connection.
   */
  OperationSetBasicInstantMessagingJabberImpl(ProtocolProviderServiceJabberImpl provider) {
    this.jabberProvider = provider;

    packetFilters.add(new GroupMessagePacketFilter());
    packetFilters.add(new PacketTypeFilter(org.jivesoftware.smack.packet.Message.class));

    provider.addRegistrationStateChangeListener(new RegistrationStateListener());

    ProviderManager man = ProviderManager.getInstance();
    MessageCorrectionExtensionProvider extProvider = new MessageCorrectionExtensionProvider();
    man.addExtensionProvider(
        MessageCorrectionExtension.ELEMENT_NAME, MessageCorrectionExtension.NAMESPACE, extProvider);
  }
示例#15
0
  /**
   * Determines whether a specific format is supported by the <tt>Recorder</tt> represented by this
   * <tt>RecordButton</tt>.
   *
   * @param format the format which is to be checked whether it is supported by the
   *     <tt>Recorder</tt> represented by this <tt>RecordButton</tt>
   * @return <tt>true</tt> if the specified <tt>format</tt> is supported by the <tt>Recorder</tt>
   *     represented by this <tt>RecordButton</tt>; otherwise, <tt>false</tt>
   */
  private boolean isSupportedFormat(String format) {
    Recorder recorder;

    try {
      recorder = getRecorder();
    } catch (OperationFailedException ofex) {
      logger.error("Failed to get Recorder", ofex);
      return false;
    }

    List<String> supportedFormats = recorder.getSupportedFormats();

    return (supportedFormats != null) && supportedFormats.contains(format);
  }
示例#16
0
  /**
   * Fires a <tt>StreamSoundLevelEvent</tt> and notifies all registered listeners.
   *
   * @param levels the new sound levels
   */
  void fireConferenceMembersSoundLevelEvent(Map<ConferenceMember, Integer> levels) {
    ConferenceMembersSoundLevelEvent event = new ConferenceMembersSoundLevelEvent(this, levels);

    ConferenceMembersSoundLevelListener[] ls;

    synchronized (confMemebrSoundLevelListeners) {
      ls =
          confMemebrSoundLevelListeners.toArray(
              new ConferenceMembersSoundLevelListener[confMemebrSoundLevelListeners.size()]);
    }

    for (ConferenceMembersSoundLevelListener listener : ls) {
      listener.soundLevelChanged(event);
    }
  }
示例#17
0
  /**
   * Add a record telling what entity caps node a user has.
   *
   * @param user the user (Full JID)
   * @param node the node (of the caps packet extension)
   * @param hash the hashing algorithm used to calculate <tt>ver</tt>
   * @param ver the version (of the caps packet extension)
   * @param ext the ext (of the caps packet extension)
   * @param online indicates if the user is online
   */
  private void addUserCapsNode(
      String user, String node, String hash, String ver, String ext, boolean online) {
    if ((user != null) && (node != null) && (hash != null) && (ver != null)) {
      Caps caps = userCaps.get(user);

      if ((caps == null)
          || !caps.node.equals(node)
          || !caps.hash.equals(hash)
          || !caps.ver.equals(ver)) {
        caps = new Caps(node, hash, ver, ext);

        userCaps.put(user, caps);
      } else return;

      // Fire userCapsNodeAdded.
      UserCapsNodeListener[] listeners;

      synchronized (userCapsNodeListeners) {
        listeners = userCapsNodeListeners.toArray(NO_USER_CAPS_NODE_LISTENERS);
      }
      if (listeners.length != 0) {
        String nodeVer = caps.getNodeVer();

        for (UserCapsNodeListener listener : listeners)
          listener.userCapsNodeAdded(user, nodeVer, online);
      }
    }
  }
示例#18
0
  /**
   * Remove records telling what entity caps node a contact has.
   *
   * @param contact the contact
   */
  public void removeContactCapsNode(Contact contact) {
    Caps caps = null;
    String lastRemovedJid = null;

    Iterator<String> iter = userCaps.keySet().iterator();
    while (iter.hasNext()) {
      String jid = iter.next();

      if (StringUtils.parseBareAddress(jid).equals(contact.getAddress())) {
        caps = userCaps.get(jid);
        lastRemovedJid = jid;
        iter.remove();
      }
    }

    // fire only for the last one, at the end the event out
    // of the protocol will be one and for the contact
    if (caps != null) {
      UserCapsNodeListener[] listeners;
      synchronized (userCapsNodeListeners) {
        listeners = userCapsNodeListeners.toArray(NO_USER_CAPS_NODE_LISTENERS);
      }
      if (listeners.length != 0) {
        String nodeVer = caps.getNodeVer();

        for (UserCapsNodeListener listener : listeners)
          listener.userCapsNodeRemoved(lastRemovedJid, nodeVer, false);
      }
    }
  }
示例#19
0
 /**
  * Removes a specific <tt>UserCapsNodeListener</tt> from the list of
  * <tt>UserCapsNodeListener</tt>s interested in events notifying about changes in the list of user
  * caps nodes of this <tt>EntityCapsManager</tt>.
  *
  * @param listener the <tt>UserCapsNodeListener</tt> which is no longer interested in events
  *     notifying about changes in the list of user caps nodes of this <tt>EntityCapsManager</tt>
  */
 public void removeUserCapsNodeListener(UserCapsNodeListener listener) {
   if (listener != null) {
     synchronized (userCapsNodeListeners) {
       userCapsNodeListeners.remove(listener);
     }
   }
 }
示例#20
0
  @Override
  public void joinAs(String nickname, byte[] password) throws OperationFailedException {
    if (isJoined) throw new OperationFailedException("Alread joined the room", 0);

    isJoined = true;

    MockRoomMember member = new MockRoomMember(createAddressForName(nickname), this);

    // FIXME: for mock purposes we are always the owner on join()
    boolean isOwner = true; // = members.size() == 0;

    synchronized (members) {
      members.add(member);

      me = member;

      fireMemberPresenceEvent(me, me, ChatRoomMemberPresenceChangeEvent.MEMBER_JOINED, null);
    }

    ChatRoomMemberRole oldRole = me.getRole();
    if (isOwner) {
      me.setRole(ChatRoomMemberRole.OWNER);
    }

    fireLocalUserRoleEvent(me, oldRole, true);
  }
示例#21
0
 /**
  * Gets and formats the names of the peers in the call.
  *
  * @param maxLength maximum length of the filename
  * @return the name of the peer in the call formated
  */
 private String getCallPeerName(int maxLength) {
   List<CallPeer> callPeers = call.getConference().getCallPeers();
   CallPeer callPeer = null;
   String peerName = "";
   if (!callPeers.isEmpty()) {
     callPeer = callPeers.get(0);
     if (callPeer != null) {
       peerName = callPeer.getDisplayName();
       peerName = peerName.replaceAll("[^\\da-zA-Z\\_\\-@\\.]", "");
       if (peerName.length() > maxLength) {
         peerName = peerName.substring(0, maxLength);
       }
     }
   }
   return peerName;
 }
    /**
     * Adds <tt>minfo</tt> into the list of collected messages.
     *
     * @param c Conversation
     * @param minfo MessageInfo
     */
    public void gotMessage(Conversation c, MessageInfo minfo) {

      logger.debug("Message: [" + minfo.getMessage() + "] received from: " + c.getBuddy());
      synchronized (this) {
        collectedMessageInfo.add(minfo);
        notifyAll();
      }
    }
    /**
     * Called when the underlying implementation has received an indication that a message, sent
     * earlier has been successfully received by the destination.
     *
     * @param evt the MessageDeliveredEvent containing the id of the message that has caused the
     *     event.
     */
    public void messageDelivered(MessageDeliveredEvent evt) {
      logger.debug("Received a MessageDeliveredEvent: " + evt);

      synchronized (this) {
        collectedEvents.add(evt);
        notifyAll();
      }
    }
  /**
   * Generate the display of the results of the Match command
   *
   * @param data the result of the Match command
   * @param word the queried word
   * @return the formatted result
   */
  private String retrieveMatch(List<MatchWord> data, String word) {
    StringBuffer result = new StringBuffer();
    boolean isStart = true;

    result.append(
        DictActivator.getResources()
            .getI18NString("plugin.dictaccregwizz.MATCH_RESULT", new String[] {word}));

    for (int i = 0; i < data.size(); i++) {
      if (isStart) isStart = false;
      else result.append(", ");

      result.append(data.get(i).getWord());
    }

    return result.toString();
  }
 static {
   supportedStatusSet.add(OFFLINE);
   supportedStatusSet.add(OCCUPIED);
   supportedStatusSet.add(DO_NOT_DISTURB);
   supportedStatusSet.add(NOT_AVAILABLE);
   supportedStatusSet.add(AWAY);
   supportedStatusSet.add(INVISIBLE);
   supportedStatusSet.add(ONLINE);
   supportedStatusSet.add(FREE_FOR_CHAT);
 }
示例#26
0
  private void mockLeave(MockRoomMember member) {
    synchronized (members) {
      if (!members.remove(member)) {
        throw new RuntimeException("Member is not in the room " + member);
      }

      fireMemberPresenceEvent(member, member, ChatRoomMemberPresenceChangeEvent.MEMBER_LEFT, null);
    }
  }
示例#27
0
  /**
   * Searches for contact ids in history of recent messages.
   *
   * @param provider
   * @param after
   * @return
   */
  List<String> getRecentContactIDs(String provider, Date after) {
    List<String> res = new ArrayList<String>();

    try {
      History history = getHistory();

      if (history != null) {
        Iterator<HistoryRecord> recs = history.getReader().findLast(NUMBER_OF_MSGS_IN_HISTORY);
        SimpleDateFormat sdf = new SimpleDateFormat(HistoryService.DATE_FORMAT);

        while (recs.hasNext()) {
          HistoryRecord hr = recs.next();

          String contact = null;
          String recordProvider = null;
          Date timestamp = null;

          for (int i = 0; i < hr.getPropertyNames().length; i++) {
            String propName = hr.getPropertyNames()[i];

            if (propName.equals(STRUCTURE_NAMES[0])) recordProvider = hr.getPropertyValues()[i];
            else if (propName.equals(STRUCTURE_NAMES[1])) contact = hr.getPropertyValues()[i];
            else if (propName.equals(STRUCTURE_NAMES[2])) {
              try {
                timestamp = sdf.parse(hr.getPropertyValues()[i]);
              } catch (ParseException e) {
                timestamp = new Date(Long.parseLong(hr.getPropertyValues()[i]));
              }
            }
          }

          if (recordProvider == null || contact == null) continue;

          if (after != null && timestamp != null && timestamp.before(after)) continue;

          if (recordProvider.equals(provider)) res.add(contact);
        }
      }
    } catch (IOException ex) {
      logger.error("cannot create recent_messages history", ex);
    }

    return res;
  }
示例#28
0
  public MockRoomMember mockJoin(MockRoomMember member) {
    synchronized (members) {
      members.add(member);

      fireMemberPresenceEvent(
          member, member, ChatRoomMemberPresenceChangeEvent.MEMBER_JOINED, null);

      return member;
    }
  }
示例#29
0
  /**
   * Updates the contact sources in the recent query if any. Done here in order to sync with
   * recentMessages instance, and to check for already existing instances of contact sources.
   * Normally called from the query.
   */
  public void updateRecentMessages() {
    if (recentQuery == null) return;

    synchronized (recentMessages) {
      List<SourceContact> currentContactsInQuery = recentQuery.getQueryResults();

      for (ComparableEvtObj evtObj : recentMessages) {
        // the contains will use the correct equals method of
        // the object evtObj
        if (!currentContactsInQuery.contains(evtObj)) {
          MessageSourceContact newSourceContact =
              new MessageSourceContact(evtObj.getEventObject(), MessageSourceService.this);
          newSourceContact.initDetails(evtObj.getEventObject());

          recentQuery.addQueryResult(newSourceContact);
        }
      }
    }
  }
    /**
     * Blocks until at least one event is received or until waitFor miliseconds pass (whichever
     * happens first).
     *
     * @param waitFor the number of miliseconds that we should be waiting for an event before simply
     *     bailing out.
     */
    public void waitForEvent(long waitFor) {
      synchronized (this) {
        if (collectedEvents.size() > 0) return;

        try {
          wait(waitFor);
        } catch (InterruptedException ex) {
          logger.debug("Interrupted while waiting for a message evt", ex);
        }
      }
    }