package org.docear.metadata; import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.BlockingQueue; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import java.util.concurrent.SynchronousQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import org.docear.metadata.data.MetaData; import org.docear.metadata.engines.SearchEngine; import org.docear.metadata.events.MetaDataEvent; import org.docear.metadata.events.MetaDataListener; import org.docear.metadata.extractors.ExtractorConfigKey; import org.docear.metadata.extractors.MalformedConfigException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class MetaDataSearchHub { protected final static Logger logger = LoggerFactory.getLogger(MetaDataSearchHub.class); public final static ThreadPoolExecutor executor = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS, new SynchronousQueue<Runnable>()); private Map<Class<?>, SearchEngine> engines = new HashMap<Class<?>, SearchEngine>(); public MetaDataSearchHub registerSearchEngine(SearchEngine engine){ this.engines.put(engine.getClass(), engine); return this; } public MetaDataSearchHub unregisterSearchEngine(SearchEngine engine){ this.engines.remove(engine.getClass()); return this; } public Set<Class<?>> getRegisteredEngines(){ return this.engines.keySet(); } public boolean isRegistered(Class<?> engineClass){ return this.engines.containsKey(engineClass); } public int getActiveTasks(){ return executor.getActiveCount(); } public BlockingQueue<Runnable> getTaskQueue(){ return executor.getQueue(); } public List<Runnable> shutdownNow(){ return executor.shutdownNow(); } public Collection<MetaData> search(String query, Set<Class<?>> useEngines, Map<ExtractorConfigKey, Object> options) throws MalformedConfigException, IOException{ Collection<MetaData> results = new ArrayList<MetaData>(); List<Callable<Collection<MetaData>>> extractors = getExtractors(query, useEngines, options, null); try { List<Future<Collection<MetaData>>> tasks = executor.invokeAll(extractors); for(Future<Collection<MetaData>> task : tasks){ results.addAll(task.get()); } } catch (InterruptedException e) { logger.warn("Exception occured in blockedSearchThread", e); } catch (ExecutionException e) { Throwable t = e.getCause(); if(t != null && t instanceof IOException){ throw (IOException)t; } logger.warn("Exception occured in blockedSearchThread", e); } return results; } public void asyncSearch(String query, Set<Class<?>> useEngines, Map<ExtractorConfigKey, Object> options, final MetaDataListener listener) throws MalformedConfigException{ MetaDataListener syncListenerWrapper = new MetaDataListener() { public synchronized void onFinishedRequest(MetaDataEvent event) { if(listener != null){ listener.onFinishedRequest(event); } } public synchronized void onCaptchaRequested(MetaDataEvent event) { if(listener != null){ listener.onCaptchaRequested(event); } } }; List<Callable<Collection<MetaData>>> extractors = getExtractors(query, useEngines, options, syncListenerWrapper); try{ for(Callable<Collection<MetaData>> extractor : extractors){ executor.submit(extractor); } }catch(Exception e){ logger.warn(e.getMessage()); } } private List<Callable<Collection<MetaData>>> getExtractors(String query, Set<Class<?>> useEngines, Map<ExtractorConfigKey, Object> options, MetaDataListener listener) throws MalformedConfigException { if(options == null) options = new HashMap<ExtractorConfigKey, Object>(); List<Callable<Collection<MetaData>>> extractors = new ArrayList<Callable<Collection<MetaData>>>(); for(Class<?> engine : useEngines){ SearchEngine searchEngine = engines.get(engine); if(searchEngine != null){ extractors.add(searchEngine.getExtractor(query, options, listener)); } } return extractors; } }