package org.gcube.data.spd.manager.search.workers; import java.util.Collections; import java.util.HashSet; import java.util.Set; import net.sf.ehcache.Cache; import net.sf.ehcache.CacheManager; import net.sf.ehcache.Element; import org.gcube.common.scope.api.ScopeProvider; import org.gcube.data.spd.caching.CacheKey; import org.gcube.data.spd.caching.CacheWriter; import org.gcube.data.spd.caching.QueryCache; import org.gcube.data.spd.caching.QueryCacheFactory; import org.gcube.data.spd.exception.MaxRetriesReachedException; import org.gcube.data.spd.manager.search.Worker; import org.gcube.data.spd.model.Condition; import org.gcube.data.spd.model.exceptions.ExternalRepositoryException; import org.gcube.data.spd.model.exceptions.StreamNonBlockingException; import org.gcube.data.spd.model.products.ResultElement; import org.gcube.data.spd.plugin.fwk.Searchable; import org.gcube.data.spd.plugin.fwk.writers.ClosableWriter; import org.gcube.data.spd.plugin.fwk.writers.ObjectWriter; import org.gcube.data.spd.utils.QueryRetryCall; import org.gcube.data.spd.utils.Utils; import org.gcube.data.spd.utils.VOID; public class SearchWorker extends Worker { private Searchable searchable; private String pluginName; private String propertiesAsString; private Condition[] properties; boolean cachable = false; private CacheManager cacheManager; private QueryCacheFactory queryCacheFactory; Set searchDone; public SearchWorker(ClosableWriter writer, String pluginName, boolean cachable, Searchable searchable, CacheManager cacheManager, QueryCacheFactory queryCacheFactory, Condition ...properties) { super(writer); this.pluginName = pluginName; this.propertiesAsString = Utils.getPropsAsString(properties); this.properties = properties; this.searchable = searchable; this.cachable = cachable; this.cacheManager = cacheManager; searchDone = Collections.synchronizedSet(new HashSet()); this.queryCacheFactory = queryCacheFactory; } @Override protected void execute(final String input, final ObjectWriter writer) { logger.debug("("+pluginName+") searching for "+input+" with outputWriter alive? "+writer.isAlive()); logger.trace("("+pluginName+") searchDone.contains(input)?"+(searchDone.contains(input))); if (searchDone.contains(input)) return; else searchDone.add(input); try { new QueryRetryCall(){ @Override protected VOID execute() throws ExternalRepositoryException { search(input, writer); return VOID.instance(); } }.call(); } catch (MaxRetriesReachedException e) { logger.error("max retries reached for "+pluginName,e); writer.write(new StreamNonBlockingException(pluginName, input)); } } private void search(String input, ObjectWriter writer) throws ExternalRepositoryException{ //add cache search using pluginName logger.trace("("+pluginName+") scope in search worker is set as "+ScopeProvider.instance.get()); if (cachable){ logger.debug("("+pluginName+") using cache"); CacheKey key = new CacheKey(input, propertiesAsString, searchable.getHandledClass()); Cache cache = cacheManager.getCache(pluginName); //logger.trace("lock is null? "+(QueryCache.lock==null )); QueryCache.lock.lock(); if((cache.isKeyInCache(key) && cache.get(key)!=null && ((QueryCache)cache.get(key).getValue()).isError()) || !cache.isKeyInCache(key)){ if (cache.isKeyInCache(key)){ logger.trace("removing invalid entry in cache ..."); try{ logger.trace("acquiring write lock "+pluginName); cache.acquireWriteLockOnKey(key); logger.trace("acquired write lock "+pluginName); cache.remove(key); }catch (Exception e) { logger.warn("problem removing cache ",e); }finally{ logger.trace("releasing write lock "+pluginName); cache.releaseWriteLockOnKey(key); logger.trace("released write lock "+pluginName); } logger.trace("cache removed ..."); } QueryCache queryCache = this.queryCacheFactory.create(pluginName); cache.put(new Element(key, queryCache)); QueryCache.lock.unlock(); CacheWriter cacheWriter = new CacheWriter(writer, queryCache); searchable.searchByScientificName(input, cacheWriter, properties); cacheWriter.close(); cache.put(new Element(key, queryCache)); }else{ //execute normal query (in case someone else is filling this cache) QueryCache.lock.unlock(); logger.debug("("+pluginName+") executing normal query in cachable plugin"); searchable.searchByScientificName(input, writer, properties); } } else{ //execute normal query logger.debug("("+this.pluginName+") executing normal query for "+input); searchable.searchByScientificName(input, writer, properties); } logger.debug("("+pluginName+") finished search for "+input); } @Override public String descriptor() { return super.descriptor()+" - "+pluginName; } }