/* * 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.impl.muc; import java.util.*; import java.util.regex.*; import net.java.sip.communicator.service.contactsource.*; import net.java.sip.communicator.service.muc.*; import net.java.sip.communicator.service.protocol.*; /** * The ServerChatRoomQuery is a query over the * ServerChatRoomContactSourceService. * * @author Hristo Terezov */ public class ServerChatRoomQuery extends AsyncContactQuery implements ChatRoomProviderWrapperListener { /** * The query string. */ private String queryString; /** * List with the current results for the query. */ private Set contactResults = new TreeSet(); /** * MUC service. */ private MUCServiceImpl mucService; /** * The number of contact query listeners. */ private int contactQueryListenersCount = 0; /** * The provider associated with the query. */ private ChatRoomProviderWrapper provider = null; /** * Creates an instance of ChatRoomQuery by specifying * the parent contact source, the query string to match and the maximum * result contacts to return. * * @param contactSource the parent contact source * @param queryString the query string to match * @param provider the provider associated with the query */ public ServerChatRoomQuery(String queryString, ServerChatRoomContactSourceService contactSource, ChatRoomProviderWrapper provider) { super(contactSource, Pattern.compile(queryString, Pattern.CASE_INSENSITIVE | Pattern.LITERAL), true); this.queryString = queryString; mucService = MUCActivator.getMUCService(); this.provider = provider; } /** * Adds listeners for the query */ private void initListeners() { mucService.addChatRoomProviderWrapperListener(this); } @Override protected void run() { if(provider == null) { Iterator chatRoomProviders = mucService.getChatRoomProviders(); while (chatRoomProviders.hasNext()) { ChatRoomProviderWrapper provider = chatRoomProviders.next(); providerAdded(provider, true); } } else { providerAdded(provider, true); } if (getStatus() != QUERY_CANCELED) setStatus(QUERY_COMPLETED); } /** * Handles adding a chat room provider. * @param provider the provider. * @param addQueryResult indicates whether we should add the chat room to * the query results or fire an event without adding it to the results. */ private void providerAdded(final ChatRoomProviderWrapper provider, final boolean addQueryResult) { final ProtocolProviderService pps = provider.getProtocolProvider(); List chatRoomNames = MUCActivator.getMUCService().getExistingChatRooms(provider); if (chatRoomNames == null) { return; } // Already create all the BaseChatRoomSourceContact instances since all // the data is already available. final Set chatRooms = new HashSet(chatRoomNames.size()); for (final String name : chatRoomNames) { chatRooms.add(new BaseChatRoomSourceContact(name, name, this, pps)); } addChatRooms(pps, chatRooms, addQueryResult); } /** * Adds found result to the query results. * * @param pps the protocol provider associated with the found chat room. * @param chatRoomName the name of the chat room. * @param chatRoomID the id of the chat room. * @param addQueryResult indicates whether we should add the chat room to * the query results or fire an event without adding it to the results. */ private void addChatRoom(ProtocolProviderService pps, String chatRoomName, String chatRoomID, boolean addQueryResult) { if((queryString == null || ((chatRoomName.contains( queryString) || chatRoomID.contains(queryString) ))) && isMatching(chatRoomID, pps)) { BaseChatRoomSourceContact contact = new BaseChatRoomSourceContact(chatRoomName, chatRoomID, this, pps); synchronized (contactResults) { contactResults.add(contact); } if(addQueryResult) { addQueryResult(contact, false); } else { fireContactReceived(contact, false); } } } /** * Adds found results to the query results. * * @param pps the protocol provider associated with the found chat room. * @param chatRooms The set of chat rooms based on * BaseChatRoomSourceContact. This is the full set and it will be * filtered according to demands of the queryString. * @param addQueryResult indicates whether we should add the chat room to * the query results or fire an event without adding it to the * results. */ private void addChatRooms(final ProtocolProviderService pps, final Set chatRooms, final boolean addQueryResult) { BaseChatRoomSourceContact room; Iterator iterator = chatRooms.iterator(); while (iterator.hasNext()) { room = iterator.next(); // Notice the NOT operator at the start ... if (!((queryString == null || (room.getChatRoomName().contains( queryString) || room.getChatRoomID().contains(queryString))) && isMatching(room.getChatRoomID(), pps))) { iterator.remove(); } } synchronized (contactResults) { contactResults.addAll(chatRooms); } if (addQueryResult) { addQueryResults(chatRooms); } else { // TODO Need something to fire one event for multiple contacts. for (SourceContact contact : chatRooms) { fireContactReceived(contact, false); } } } @Override public void chatRoomProviderWrapperAdded(ChatRoomProviderWrapper provider) { providerAdded(provider, false); } @Override public void chatRoomProviderWrapperRemoved(ChatRoomProviderWrapper provider) { LinkedList tmpContactResults; synchronized (contactResults) { tmpContactResults = new LinkedList(contactResults); for(BaseChatRoomSourceContact contact : tmpContactResults) { if(contact.getProvider().equals(provider.getProtocolProvider())) { contactResults.remove(contact); fireContactRemoved(contact); } } } } /** * Clears any listener we used. */ private void clearListeners() { mucService.removeChatRoomProviderWrapperListener(this); } /** * Cancels this ContactQuery. * * @see ContactQuery#cancel() */ public void cancel() { clearListeners(); 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) clearListeners(); super.setStatus(status); } @Override public void addContactQueryListener(ContactQueryListener l) { super.addContactQueryListener(l); contactQueryListenersCount++; if(contactQueryListenersCount == 1) { initListeners(); } } @Override public void removeContactQueryListener(ContactQueryListener l) { super.removeContactQueryListener(l); contactQueryListenersCount--; if(contactQueryListenersCount == 0) { clearListeners(); } } /** * Checks if the contact should be added to results or not. * @param chatRoomID the chat room id associated with the contact. * @param pps the provider of the chat room contact. * @return true if the result should be added to the results and * false if not. */ public boolean isMatching(String chatRoomID, ProtocolProviderService pps) { return (MUCActivator.getMUCService().findChatRoomWrapperFromChatRoomID( chatRoomID, pps) == null); } /** * Returns the index of the contact in the contact results list. * @param contact the contact. * @return the index of the contact in the contact results list. */ public int indexOf(BaseChatRoomSourceContact contact) { Iterator it = contactResults.iterator(); int i = 0; while(it.hasNext()) { if(contact.equals(it.next())) { return i; } i++; } return -1; } }