/* See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* Esri Inc. licenses this file to You 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 com.esri.gpt.control.rest.search;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.esri.gpt.catalog.search.ASearchEngine;
import com.esri.gpt.catalog.search.SearchEngineFactory;
import com.esri.gpt.catalog.search.SearchResult;
import com.esri.gpt.framework.context.RequestContext;
/**
* The Class DistributedSearch.
*/
public class DistributedSearchDispatcher {
// class variables =============================================================
/** Class Logger *. */
private Logger LOG =
Logger.getLogger(DistributedSearchDispatcher.class.getCanonicalName());
// instance variables ==========================================================
/** The search context. */
private SearchContext searchContext;
/** The threads. */
private List<SearchThread> threads = new ArrayList<SearchThread>();
/** The listeners. */
private ArrayList<ISearchListener> listeners = new ArrayList<ISearchListener>();
// constructors ================================================================
/**
* Default constructor.
*/
public DistributedSearchDispatcher() {
}
/**
* Main unit test method.
*
* @param args
* startup arguments
*/
public static void main(String[] args) {
try {
DistributedSearchDispatcher self = new DistributedSearchDispatcher();
self.search();
} catch (Throwable t) {
t.printStackTrace(System.err);
}
}
// properties ==============================================================
/**
* Gets the search context.
*
* @return the search context
*/
public SearchContext getSearchContext() {
return this.searchContext;
}
/**
* Sets the search context.
*
* @param searchContext
* the search context
*/
public void setSearchContext(SearchContext searchContext) {
this.searchContext = searchContext;
}
/**
* Gets the listeners.
*
* @return the listeners (never null)
*/
private ArrayList<ISearchListener> getListeners() {
if(this.listeners == null) {
this.listeners = new ArrayList<ISearchListener>();
}
return this.listeners;
}
// methods =================================================================
/**
* Adds the action listener.
*
* @param listener the listener
*/
public void addActionListener(ISearchListener listener) {
if(this.listeners == null) {
listeners = new ArrayList<ISearchListener>();
}
listeners.add(listener);
}
/**
* Removes the action listener.
*
* @param listener the listener
*/
public void removeActionListener(ISearchListener listener) {
if(listeners == null || listeners.size() < 1) {
return;
}
listeners.remove(listener);
}
/**
* Searches the endpoints.
* @throws Exception the exception
*/
public void search() throws Exception {
// initialize listeners before search
if(listeners != null && listeners.size() > 0) {
for(ISearchListener listener : listeners) {
listener.initBeforeSearch();
}
}
SearchContext context = this.getSearchContext();
Map<String, Object> mapRid2Engine =
SearchEngineFactory.createSearchEngines(
context.getSearchCriteria(),
new SearchResult(),
this.searchContext.getRequestContext(),
context.getRIDs(),
context.getMessageBroker(),
null, null);
Set<String> setRids = mapRid2Engine.keySet();
// Extract the engines
Map<String, ASearchEngine> mapEngines = new HashMap<String, ASearchEngine>();
Map<String, String> mapRidErrors = new HashMap<String, String>();
for (String rid : setRids) {
Object obj = mapRid2Engine.get(rid);
if(!(obj instanceof ASearchEngine)) {
mapRidErrors.put(rid, obj.toString());
continue;
}
mapEngines.put(rid, (ASearchEngine) obj);
}
// Make the threads
CountDownLatch countDownLatch = new CountDownLatch(mapEngines.size());
for(String rid : mapEngines.keySet()) {
ASearchEngine engine = mapEngines.get(rid);
SearchThread searchThread = new SearchThread(this.getSearchContext(), rid,
engine, countDownLatch);
searchThread.setName(rid + System.currentTimeMillis());
if(listeners != null && listeners.size() > 0) {
for(ISearchListener listener : listeners) {
searchThread.addActionListener(listener);
}
}
this.threads.add(searchThread);
}
// start the threads
for (SearchThread thread : this.threads) {
if(LOG.isLoggable(Level.FINER)) {
LOG.finer("Starting thread id= " + thread.getId()
+ ", rid=" + thread.getRID());
}
thread.start();
}
// wait for all threads to finish or for certain time to pass
countDownLatch.await(this.getSearchContext().getMaxSearchTime(),
TimeUnit.MILLISECONDS);
LOG.finer("Countdown latch released");
// inform threads time is up
for (SearchThread thread : this.threads) {
thread.setTimeUp(true);
}
// tell listeners they are done
if(listeners != null && listeners.size() > 0) {
for(ISearchListener listener : listeners) {
for(String rid: mapRidErrors.keySet()) {
/*DistributedSearchEvent event = new DistributedSearchEvent(this, this
.getSearchStatus());*/
SearchStatus status = new SearchStatus();
status.setStatusType(SearchStatus.STATUSTYPE_FAILED);
status.setRid(rid);
status.setMessage(mapRidErrors.get(rid));
DistributedSearchEvent event = new DistributedSearchEvent(this,
status);
listener.searchEvent(event);
}
listener.searchDone();
}
}
/* for (SearchThread thread : this.threads) {
if (thread.getSearchStatus().getStatusType()
.equals(SearchStatus.STATUSTYPE_COMPLETED)) {
//
} else if(thread.isAlive()) {
thread.getSearchStatus().setStatusType(
SearchStatus.STATUSTYPE_SEARCH_TIMEOUT);
thread.fireSearchEvent();
thread.setStopThread(true);
LOG.warning("Thread found alive at the end distributed search " +
"rid =" + thread.getId());
}
}*/
}
}