package org.gcube.data.spd.utils; import static org.gcube.data.streams.dsl.Streams.convert; import java.net.URI; import java.rmi.RemoteException; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.concurrent.ExecutorService; import javax.ws.rs.Consumes; import javax.ws.rs.DELETE; import javax.ws.rs.GET; import javax.ws.rs.PUT; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; import javax.ws.rs.core.MediaType; import org.gcube.common.scope.api.ScopeProvider; import org.gcube.data.spd.Constants; import org.gcube.data.spd.exception.MaxRetriesReachedException; import org.gcube.data.spd.manager.AppInitializer; import org.gcube.data.spd.model.Condition; import org.gcube.data.spd.model.PluginDescription; import org.gcube.data.spd.model.binding.Bindings; import org.gcube.data.spd.model.exceptions.ExternalRepositoryException; import org.gcube.data.spd.model.exceptions.IdNotValidException; import org.gcube.data.spd.model.exceptions.StreamBlockingException; import org.gcube.data.spd.model.exceptions.StreamNonBlockingException; import org.gcube.data.spd.model.products.OccurrencePoint; import org.gcube.data.spd.model.products.ResultElement; import org.gcube.data.spd.model.products.ResultItem; import org.gcube.data.spd.model.products.TaxonomyItem; import org.gcube.data.spd.model.service.exceptions.InvalidIdentifierException; import org.gcube.data.spd.model.service.exceptions.UnsupportedCapabilityException; import org.gcube.data.spd.model.service.types.PluginDescriptions; import org.gcube.data.spd.model.service.types.SearchCondition; import org.gcube.data.spd.model.service.types.SearchRequest; import org.gcube.data.spd.plugin.fwk.AbstractPlugin; 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.Writer; import org.gcube.data.spd.plugin.fwk.writers.rswrapper.ResultWrapper; import org.gcube.data.streams.Stream; import org.gcube.smartgears.ApplicationManagerProvider; import org.gcube.smartgears.ContextProvider; import org.gcube.smartgears.context.application.ApplicationContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.thoughtworks.xstream.XStream; @Path("remote") public class RemoteDispatcher { private static Logger logger = LoggerFactory.getLogger(RemoteDispatcher.class); ApplicationContext ctx = ContextProvider.get(); AppInitializer initializer = (AppInitializer) ApplicationManagerProvider.get(AppInitializer.class); public RemoteDispatcher(){ super(); } //only for test public RemoteDispatcher(AbstractPlugin plugin, ExecutorService executor) { this.plugin = plugin; } //only for test is not null AbstractPlugin plugin=null; private AbstractPlugin getPlugin(String pluginName){ if (plugin==null) return initializer.getPluginManager().plugins().get(pluginName); else return plugin; } /* (non-Javadoc) * @see org.gcube.data.spd.remotedispatcher.RemoteDispatcher#search(org.gcube.data.spd.remotedispatcher.types.SearchRequest) */ /* @GET @Path("retrieve/search") @Consumes(MediaType.APPLICATION_XML) public String search(SearchRequest request) throws RemoteException { logger.trace("searchByScienficName called in scope "+ScopeProvider.instance.get()); AbstractPlugin localPlugin = getPlugin(request.getPluginName()); logger.trace("plugin "+request.getPluginName()+" have been retrieved, it is null?"+(localPlugin==null)); List properties = Collections.emptyList(); if (request.getProperties()!=null){ properties = new ArrayList(request.getProperties().size()); for (SearchCondition prop : request.getProperties()){ Object value = new XStream().fromXML(prop.getValue()); properties.add(new Condition(prop.getType(), value,prop.getOperator())); } } try{ if (request.getResultType().equals(Constants.TAXON_RETURN_TYPE)){ ResultWrapper wrapper = new ResultWrapper(); Writer writer = new Writer(wrapper); ExecutorsContainer.execSearch(new RemoteSearch(localPlugin.getClassificationInterface(), writer, request.getWord(), properties)); return wrapper.getLocator(); }else if (request.getResultType().equals(Constants.OCCURRENCE_RETURN_TYPE)){ ResultWrapper wrapper = new ResultWrapper(); Writer writer = new Writer(wrapper); ExecutorsContainer.execSearch(new RemoteSearch(localPlugin.getOccurrencesInterface(), writer, request.getWord(), properties)); return wrapper.getLocator(); }else { ResultWrapper wrapper = new ResultWrapper(); Writer writer = new Writer(wrapper); ExecutorsContainer.execSearch(new RemoteSearch(localPlugin, writer, request.getWord(), properties)); return wrapper.getLocator(); } }catch (Exception e) { logger.error("search error for remote plugin", e); throw new RemoteException(e.getMessage()); } } //TAXON functions (non-Javadoc) * @see org.gcube.data.spd.remotedispatcher.RemoteDispatcher#getSynonymsById(java.lang.String, java.lang.String) @GET @Path("taxon/synonyms") public String getSynonymsById(@QueryParam("id") final String id, @QueryParam("plugin") String pluginName) throws RemoteException, InvalidIdentifierException { final AbstractPlugin localPlugin = getPlugin(pluginName); try{ final ResultWrapper wrapper = new ResultWrapper(); ExecutorsContainer.execSearch(new Runnable() { @Override public void run() { final Writer writer = new Writer(wrapper); try { new JobRetryCall() { @Override protected VOID execute() throws ExternalRepositoryException, Exception { localPlugin.getClassificationInterface().getSynonymnsById(writer, id); return VOID.instance(); } }.call(); } catch (Exception e) { logger.error("getSynonymsById for remote plugin",e); writer.write(new StreamBlockingException(localPlugin.getRepositoryName(),id)); } finally{ writer.close(); } } }); return wrapper.getLocator(); } catch (Exception e) { logger.error("error getting locator ",e); throw new RemoteException(e.getMessage()); } } (non-Javadoc) * @see org.gcube.data.spd.remotedispatcher.RemoteDispatcher#retrieveTaxonChildrenByTaxonId(java.lang.String, java.lang.String) @GET @Path("taxon/children/{key}") public String retrieveTaxonChildrenByTaxonId( @PathParam("id") final String id, @QueryParam("plugin") final String pluginName) throws RemoteException, InvalidIdentifierException { final AbstractPlugin localPlugin = getPlugin(pluginName); try{ final ResultWrapper wrapper = new ResultWrapper(); ExecutorsContainer.execSearch(new Runnable() { @Override public void run() { Writer writer = new Writer(wrapper); try { List items = new JobRetryCall, IdNotValidException>() { @Override protected List execute() throws ExternalRepositoryException, IdNotValidException { return localPlugin.getClassificationInterface().retrieveTaxonChildrenByTaxonId(id); } }.call(); for (TaxonomyItem item :items) writer.write(item); } catch (Exception e) { logger.error("error retreiving children by id",e); writer.write(new StreamBlockingException(localPlugin.getRepositoryName(), id)); }finally{ writer.close(); } } }); return wrapper.getLocator(); } catch (Exception e) { logger.error("error getting locator ",e); throw new RemoteException(e.getMessage()); } } (non-Javadoc) * @see org.gcube.data.spd.remotedispatcher.RemoteDispatcher#retrieveTaxaByIds(java.lang.String, java.lang.String) @GET @Path("taxon/tree/{plugin}/{key}") public String retrieveTaxaByIds(@PathParam("key") final String idsLocator, @PathParam("plugin") String pluginName) throws RemoteException { final AbstractPlugin localPlugin = getPlugin(pluginName); try{ final ResultWrapper wrapper = new ResultWrapper(); ExecutorsContainer.execSearch(new Runnable() { @Override public void run() { final Stream idsStream = convert(URI.create(idsLocator)).ofStrings().withDefaults();; final Writer writer = new Writer(wrapper); new JobRetryCall() { @Override protected VOID execute() throws ExternalRepositoryException, Exception { localPlugin.getClassificationInterface().retrieveTaxonByIds(idsStream, writer); return VOID.instance(); } }; writer.close(); } }); return wrapper.getLocator(); } catch (Exception e) { logger.error("error getting locator ",e); throw new RemoteException(e.getMessage()); } } (non-Javadoc) * @see org.gcube.data.spd.remotedispatcher.RemoteDispatcher#getTaxonById(java.lang.String, java.lang.String) @GET @Path("taxon/ids/{idsLocator}") public String getTaxonById(@PathParam("idsLocator") final String id, @QueryParam("plugin") String pluginName) throws RemoteException, InvalidIdentifierException { AbstractPlugin plugin = getPlugin(pluginName); try { return Bindings.toXml(plugin.getClassificationInterface().retrieveTaxonById(id)); } catch (IdNotValidException e) { logger.error("error in getTaxonById",e); throw new InvalidIdentifierException(); } catch (Exception e) { logger.error("error in getTaxonById",e); throw new RemoteException(e.getMessage()); } } //END: TAXON functions //occurrence functions (non-Javadoc) * @see org.gcube.data.spd.remotedispatcher.RemoteDispatcher#getOccurrencesByProductKeys(java.lang.String, java.lang.String) @GET @Path("occurrence/keys/{productKeysLocator}") public String getOccurrencesByProductKeys( @PathParam("productKeysLocator") final String productKeysLocator, @QueryParam("plugin") String pluginName) throws RemoteException { final AbstractPlugin localPlugin = getPlugin(pluginName); try{ final ResultWrapper wrapper = new ResultWrapper(); ExecutorsContainer.execSearch(new Runnable() { @Override public void run() { logger.debug("searching remote occurrence for plugin "+localPlugin.getRepositoryName()); final Stream keysStream = convert(URI.create(productKeysLocator)).ofStrings().withDefaults(); final Writer writer = new Writer(wrapper); try { new JobRetryCall() { @Override protected VOID execute() throws ExternalRepositoryException, Exception { localPlugin.getOccurrencesInterface().getOccurrencesByProductKeys(writer, keysStream); return VOID.instance(); } }.call(); } catch (Exception e) { writer.write(new StreamBlockingException(localPlugin.getRepositoryName())); } writer.close(); } }); return wrapper.getLocator(); } catch (Exception e) { logger.error("error getting locator ",e); throw new RemoteException(e.getMessage()); } } (non-Javadoc) * @see org.gcube.data.spd.remotedispatcher.RemoteDispatcher#getOccurrencesByIds(java.lang.String, java.lang.String) @GET @Path("occurrence/ids/{IdsLocator}") public String getOccurrencesByIds(final String idsLocator, String pluginName) throws RemoteException { final AbstractPlugin localPlugin = getPlugin(pluginName); try{ final ResultWrapper wrapper = new ResultWrapper(); ExecutorsContainer.execSearch(new Runnable() { @Override public void run() { final Stream idsStream = convert(URI.create(idsLocator)).ofStrings().withDefaults(); final Writer writer = new Writer(wrapper); try { new JobRetryCall() { @Override protected VOID execute() throws ExternalRepositoryException, Exception { localPlugin.getOccurrencesInterface().getOccurrencesByIds(writer, idsStream); return VOID.instance(); } }.call(); } catch (Exception e) { writer.write(new StreamBlockingException(localPlugin.getRepositoryName())); } writer.close(); } }); return wrapper.getLocator(); } catch (Exception e) { logger.error("error getting locator ",e); throw new RemoteException(e.getMessage()); } } //END : occurrence functions //RESOLVE CAPABILITIES (non-Javadoc) * @see org.gcube.data.spd.remotedispatcher.RemoteDispatcher#namesMapping(java.lang.String, java.lang.String) @GET @Path("extensions/mapping/{commonName}") public String namesMapping(@PathParam("commonName") final String commonName, @QueryParam("name") String pluginName) throws RemoteException { logger.trace("requesting plugin "+pluginName); final AbstractPlugin localPlugin = getPlugin(pluginName); if (plugin==null) throw new RemoteException("error executing namesMapping on "+pluginName); try{ final ResultWrapper wrapper = new ResultWrapper(); ExecutorsContainer.execSearch(new Runnable() { @Override public void run() { final Writer writer = new Writer(wrapper); logger.trace("calling names mapping on "+localPlugin.getRepositoryName()); try{ new QueryRetryCall(){ @Override protected VOID execute() throws ExternalRepositoryException { localPlugin.getMappingInterface().getRelatedScientificNames(writer, commonName); return VOID.instance(); } }.call(); } catch (MaxRetriesReachedException e) { logger.error("error retreiving namesMapping on remote plugin",e); writer.write(new StreamBlockingException(localPlugin.getRepositoryName())); }finally{ writer.close(); } } }); return wrapper.getLocator(); } catch (Exception e) { logger.error("error getting locator ",e); throw new RemoteException(e.getMessage()); } } //END : RESOLVE CAPABILITIES //EXPAND CAPABILITIES (non-Javadoc) * @see org.gcube.data.spd.remotedispatcher.RemoteDispatcher#expandWithSynonyms(java.lang.String, java.lang.String) @GET @Path("extensions/expand/{scientificName}") public String expandWithSynonyms(@PathParam("scientificName") final String scientificName,@QueryParam("plugin") String pluginName) throws RemoteException { final AbstractPlugin localPlugin = getPlugin(pluginName); try{ final ResultWrapper wrapper = new ResultWrapper(); ExecutorsContainer.execSearch(new Runnable() { @Override public void run() { final Writer writer = new Writer(wrapper); try { //"synonyms expansion is not suported in "+plugin.getRepositoryName() if (localPlugin.getExpansionInterface()==null) throw new UnsupportedCapabilityException(); else{ new QueryRetryCall(){ @Override protected VOID execute() throws ExternalRepositoryException { localPlugin.getExpansionInterface().getSynonyms(writer, scientificName); return VOID.instance(); } }.call(); } } catch (Exception e) { logger.error("error getting synonyms for remote plugin",e); }finally{ writer.close(); } } }); return wrapper.getLocator(); } catch (Exception e) { logger.error("error getting locator ",e); throw new RemoteException(e.getMessage()); } } //END: EXPAND CAPABILITIES //UNFOLD CAPABILITIES (non-Javadoc) * @see org.gcube.data.spd.remotedispatcher.RemoteDispatcher#unfold(java.lang.String, java.lang.String) @GET @Path("extensions/unfold/{scientificName}") public String unfold(@PathParam("scientificName") final String scientificName,@QueryParam("plugin") String pluginName) throws RemoteException { final AbstractPlugin localPlugin = getPlugin(pluginName); try{ final ResultWrapper wrapper = new ResultWrapper(); ExecutorsContainer.execSearch(new Runnable() { @Override public void run() { final Writer writer = new Writer(wrapper); try { //"synonyms expansion is not suported in "+plugin.getRepositoryName() if (localPlugin.getUnfoldInterface()==null) throw new UnsupportedCapabilityException(); else{ new QueryRetryCall(){ @Override protected VOID execute() throws ExternalRepositoryException { localPlugin.getUnfoldInterface().unfold(writer, scientificName); return VOID.instance(); } }.call(); } } catch (Exception e) { logger.error("error getting synonyms for remote plugin",e); }finally{ writer.close(); } } }); return wrapper.getLocator(); } catch (Exception e) { logger.error("error getting locator ",e); throw new RemoteException(e.getMessage()); } } //END: UNFOLD CAPABILITIES class RemoteSearch implements Runnable { private final Searchable searchable; private final ClosableWriter writer; private final String word; private final Condition[] conditions; public RemoteSearch(Searchable searchable, ClosableWriter writer, String word, List conditions) { super(); this.searchable = searchable; this.writer = writer; this.word = word; this.conditions = new Condition[conditions.size()]; conditions.toArray(this.conditions); } public void run() { try{ new QueryRetryCall() { @Override protected VOID execute() throws ExternalRepositoryException { searchable.searchByScientificName(word, writer, conditions); return VOID.instance(); } }.call(); } catch (MaxRetriesReachedException e) { writer.write(new StreamNonBlockingException(word)); }finally{ writer.close(); } } } @PUT @Path("exchange") @Consumes(MediaType.APPLICATION_XML) @Produces(MediaType.APPLICATION_XML) public PluginDescriptions exchangePlugins(PluginDescriptions remotePlugins,@QueryParam("gCoreEndpointId") String gCoreEndpointId) throws RemoteException { initializer.getPluginManager().addRemotePlugins(remotePlugins.getDescriptions(), gCoreEndpointId); List descriptions = new ArrayList(); for (AbstractPlugin plugin :initializer.getPluginManager().plugins().values()) if(!plugin.isRemote()) descriptions.add(Utils.getPluginDescription(plugin)); return new PluginDescriptions(descriptions); } @DELETE @Path("remove/{gCoreEndpointId}") public void removeAll(@PathParam("gCoreEndpointId") String gCoreEndpointId) throws RemoteException { initializer.getPluginManager().removeRemotePlugin(gCoreEndpointId); } */ }