/*
* Jitsi, the OpenSource Java VoIP and Instant Messaging client.
*
* Copyright @ 2015 Atlassian Pty Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.java.sip.communicator.plugin.usersearch;
import java.util.*;
import java.util.regex.*;
import net.java.sip.communicator.service.contactsource.*;
import net.java.sip.communicator.service.protocol.*;
/**
* The <tt>UserSearchQuery</tt> is a query over
* <tt>UserSearchContactSource</tt>.
*/
public class UserSearchQuery
extends AsyncContactQuery<ContactSourceService>
implements UserSearchSupportedProviderListener
{
/**
* The query string.
*/
private String queryString;
/**
* A list with the found contacts.
*/
private List<UserSearchContact> contacts
= new LinkedList<UserSearchContact>();
/**
* A list of providers that are already displayed.
*/
private List<ProtocolProviderService> displayedProviders
= new LinkedList<ProtocolProviderService>();
/**
* The number of the listeners added to the query.
*/
private int contactQueryListenersCount = 0;
/**
* Creates an instance of <tt>ChatRoomQuery</tt> by specifying
* the parent contact source, the query string to match and the maximum
* result contacts to return.
*
* @param queryString the query string to match
* @param contactSource the parent contact source
*/
public UserSearchQuery(String queryString,
UserSearchContactSource contactSource)
{
super(contactSource,
Pattern.compile(queryString, Pattern.CASE_INSENSITIVE
| Pattern.LITERAL), true);
this.queryString = queryString;
}
@Override
protected void run()
{
try
{
Thread.sleep(UserSearchContactSource.QUERY_DELAY);
}
catch (InterruptedException e)
{ }
if(getStatus() == QUERY_CANCELED)
return;
for(ProtocolProviderService provider :
UserSearchActivator.getSupportedProviders())
{
providerAdded(provider);
}
}
/**
* Handles provider addition.
*
* @param provider the provider that was added.
*/
public void providerAdded(ProtocolProviderService provider)
{
synchronized (displayedProviders)
{
if(displayedProviders.contains(provider))
return;
displayedProviders.add(provider);
}
OperationSetUserSearch opSetUserSearch
= provider.getOperationSet(
OperationSetUserSearch.class);
if(opSetUserSearch == null)
{
return;
}
opSetUserSearch.createSearchManager();
List<String> jidList = opSetUserSearch.search(queryString);
if(jidList == null || jidList.isEmpty())
return;
List<Class<? extends OperationSet>> supportedOpSets
= new ArrayList<Class<? extends OperationSet>>(2);
supportedOpSets.add(OperationSetPersistentPresence.class);
supportedOpSets.add(OperationSetBasicInstantMessaging.class);
ContactDetail detail = new ContactDetail(queryString);
for(String jid : jidList)
{
List<ContactDetail> contactDetails
= new LinkedList<ContactDetail>();
ContactDetail jidDetail = new ContactDetail(jid);
jidDetail.setSupportedOpSets(supportedOpSets);
contactDetails.add(jidDetail);
contactDetails.add(detail);
UserSearchContact contact
= new UserSearchContact(
this,
getContactSource(),
jid,
contactDetails,
provider);
contact.setContactAddress(jid);
synchronized (contacts)
{
contacts.add(contact);
}
fireContactReceived(contact);
}
}
/**
* Handles provider removal.
*
* @param provider the provider that was removed.
*/
public void providerRemoved(ProtocolProviderService provider)
{
synchronized (displayedProviders)
{
displayedProviders.remove(provider);
}
OperationSetUserSearch opSetUserSearch
= provider.getOperationSet(
OperationSetUserSearch.class);
if(opSetUserSearch == null)
return;
opSetUserSearch.removeSearchManager();
List<UserSearchContact> tmpContacts;
synchronized (contacts)
{
tmpContacts = new LinkedList<UserSearchContact>(contacts);
}
for(UserSearchContact contact : tmpContacts)
{
if(contact.getProvider().equals(provider))
{
synchronized (contacts)
{
contacts.remove(contact);
}
fireContactRemoved(contact);
}
}
}
/**
* Releases the resources of the query.
*/
private void dispose()
{
UserSearchActivator.removeUserSearchSupportedProviderListener(this);
synchronized (contacts)
{
contacts.clear();
}
synchronized (displayedProviders)
{
displayedProviders.clear();
}
}
/**
* Cancels this <tt>ContactQuery</tt>.
*
* @see ContactQuery#cancel()
*/
public void cancel()
{
dispose();
super.cancel();
}
/**
* If query has status changed to cancel, let's clear listeners.
* @param status {@link ContactQuery#QUERY_CANCELED},
* {@link ContactQuery#QUERY_COMPLETED}
*/
public void setStatus(int status)
{
if(status == QUERY_CANCELED)
dispose();
super.setStatus(status);
}
@Override
public void addContactQueryListener(ContactQueryListener l)
{
super.addContactQueryListener(l);
contactQueryListenersCount++;
if(contactQueryListenersCount == 1)
{
UserSearchActivator.addUserSearchSupportedProviderListener(this);
}
}
@Override
public void removeContactQueryListener(ContactQueryListener l)
{
super.removeContactQueryListener(l);
contactQueryListenersCount--;
if(contactQueryListenersCount == 0)
{
dispose();
}
}
/**
* A specific user search source contact.
*/
private class UserSearchContact
extends SortedGenericSourceContact
{
/**
* The provider associated with the contact.
*/
private ProtocolProviderService provider;
public UserSearchContact(ContactQuery parentQuery,
ContactSourceService cSourceService, String displayName,
List<ContactDetail> contactDetails,
ProtocolProviderService provider)
{
super(parentQuery, cSourceService, displayName, contactDetails);
this.provider = provider;
}
/**
* Returns the provider associated with the contact.
* @return the provider associated with the contact.
*/
public ProtocolProviderService getProvider()
{
return provider;
}
}
@Override
public List<SourceContact> getQueryResults()
{
List<SourceContact> queryResults;
synchronized (contacts)
{
queryResults = new LinkedList<SourceContact>(contacts);
}
return queryResults;
}
@Override
public int getQueryResultCount()
{
synchronized (contacts)
{
return contacts.size();
}
}
}