package org.gcube.data.spd.resources; import java.net.URI; import java.util.ArrayList; import java.util.Calendar; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import org.gcube.data.spd.caching.QueryCacheFactory; import org.gcube.data.spd.manager.AppInitializer; import org.gcube.data.spd.manager.OccurrenceWriterManager; import org.gcube.data.spd.manager.ResultItemWriterManager; import org.gcube.data.spd.manager.TaxonomyItemWriterManager; import org.gcube.data.spd.manager.search.Search; import org.gcube.data.spd.model.Condition; import org.gcube.data.spd.model.Condition.Operator; import org.gcube.data.spd.model.Conditions; import org.gcube.data.spd.model.Constants; import org.gcube.data.spd.model.Coordinate; import org.gcube.data.spd.model.PluginDescription; import org.gcube.data.spd.model.products.OccurrencePoint; import org.gcube.data.spd.model.products.ResultItem; import org.gcube.data.spd.model.products.TaxonomyItem; import org.gcube.data.spd.model.service.exceptions.QueryNotValidException; import org.gcube.data.spd.model.service.exceptions.UnsupportedCapabilityException; import org.gcube.data.spd.model.service.exceptions.UnsupportedPluginException; import org.gcube.data.spd.model.service.types.PluginDescriptions; import org.gcube.data.spd.model.util.Capabilities; import org.gcube.data.spd.plugin.PluginManager; import org.gcube.data.spd.plugin.PluginUtils; import org.gcube.data.spd.plugin.fwk.AbstractPlugin; import org.gcube.data.spd.plugin.fwk.Searchable; import org.gcube.data.spd.plugin.fwk.writers.rswrapper.ResultWrapper; import org.gcube.data.spd.utils.ResultWrapperMantainer; import org.gcube.data.spd.utils.Utils; import org.gcube.dataaccess.spql.ParserException; import org.gcube.dataaccess.spql.SPQLQueryParser; import org.gcube.dataaccess.spql.model.Query; import org.gcube.dataaccess.spql.model.ret.ReturnType; import org.gcube.dataaccess.spql.model.where.ParserCoordinate; import org.gcube.dataaccess.spql.model.where.ParserDate; import org.gcube.smartgears.ApplicationManagerProvider; import org.gcube.smartgears.ContextProvider; import org.gcube.smartgears.annotations.ManagedBy; import org.gcube.smartgears.context.application.ApplicationContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @ManagedBy(AppInitializer.class) @Path(Constants.MANAGER_PATH) public class Manager { Logger logger = LoggerFactory.getLogger(Manager.class); AppInitializer initializer = (AppInitializer)ApplicationManagerProvider.get(); private ApplicationContext ctx = ContextProvider.get(); /** * * @param query a SpQL query * @return * @throws GCUBEFault */ @GET @Path("search") public Response search(@QueryParam("query") String query) throws QueryNotValidException, UnsupportedPluginException, UnsupportedCapabilityException { Query result; logger.trace("submitted query is "+query); try{ result = SPQLQueryParser.parse(query); }catch (ParserException e) { StringBuilder builder = new StringBuilder(); builder.append("syntax error on query ("+query+") : "); for (String error : e.getErrors()) builder.append(error).append(" ; "); logger.error(builder.toString()); throw new QueryNotValidException(builder.toString()); } String locator; try{ boolean selectedAllSupportedPlugin = result.getDatasources().size()==0; Collection plugins=!selectedAllSupportedPlugin?PluginUtils.getPluginsSubList(result.getDatasources(), initializer.getPluginManager().plugins()): initializer.getPluginManager().plugins().values(); Condition[] conditions = new Condition[0]; if (result.getWhereExpression() != null) conditions= evaluateConditions(result.getWhereExpression().getConditions()); ReturnType returnType = result.getReturnType(); if (returnType == null) returnType = ReturnType.PRODUCT; logger.trace("RETUN TYPE IS {} ",returnType); switch (returnType) { case OCCURRENCE:{ Set pluginsPerCapability = initializer.getPluginManager().getPluginsPerCapability(Capabilities.Occurrence, plugins); logger.trace("searching in plugins {} ",pluginsPerCapability); if (pluginsPerCapability.size()==0) throw new UnsupportedCapabilityException(); Map> searchableMapping = new HashMap>(); for (AbstractPlugin plugin: pluginsPerCapability) searchableMapping.put(plugin.getRepositoryName(), plugin.getOccurrencesInterface()); ResultWrapper wrapper = ResultWrapperMantainer.getWrapper(OccurrencePoint.class); locator = wrapper.getLocator(); Search search =new Search(wrapper, initializer.getPluginManager().plugins(), OccurrenceWriterManager.class, new QueryCacheFactory(ctx.configuration().persistence().location())); search.search(searchableMapping, result, conditions); break; } case PRODUCT:{ logger.trace("searching in plugins {} ",plugins); Map> searchableMapping = new HashMap>(); for (AbstractPlugin plugin: plugins) searchableMapping.put(plugin.getRepositoryName(), plugin); ResultWrapper wrapper = ResultWrapperMantainer.getWrapper(ResultItem.class); locator = wrapper.getLocator(); Search search = new Search(wrapper, initializer.getPluginManager().plugins(), ResultItemWriterManager.class, new QueryCacheFactory(ctx.configuration().persistence().location())); search.search(searchableMapping, result, conditions); break; } case TAXON:{ Set pluginsPerCapability = initializer.getPluginManager().getPluginsPerCapability(Capabilities.Classification, plugins); logger.trace("searching in plugins {} ",pluginsPerCapability); if (pluginsPerCapability.size()==0) throw new UnsupportedCapabilityException(); Map> searchableMapping = new HashMap>(); for (AbstractPlugin plugin: pluginsPerCapability) searchableMapping.put(plugin.getRepositoryName(), plugin.getClassificationInterface()); ResultWrapper wrapper = ResultWrapperMantainer.getWrapper(TaxonomyItem.class); locator = wrapper.getLocator(); Search search = new Search(wrapper, initializer.getPluginManager().plugins(), TaxonomyItemWriterManager.class, new QueryCacheFactory(ctx.configuration().persistence().location())); search.search(searchableMapping, result, conditions); break; } default: throw new Exception("unexpected behaviour"); } }catch (UnsupportedCapabilityException e) { logger.error("unsupported capability error",e); throw e; }catch (UnsupportedPluginException e) { logger.error("unsupported plugin error",e); throw e; }catch (Exception e) { logger.error("error submitting search",e); throw new RuntimeException("error submitting search", e); } // the output will be probably returned even before // a first chunk is written by the new thread StringBuilder redirectUri = new StringBuilder(); redirectUri.append("http://").append(ctx.container().configuration().hostname()).append(":").append(ctx.container().configuration().port()); redirectUri.append(ctx.application().getContextPath()).append(Constants.APPLICATION_ROOT_PATH).append("/").append(Constants.RESULTSET_PATH).append("/").append(locator); logger.trace("redirect uri is {} ",redirectUri.toString()); try{ return Response.temporaryRedirect(new URI(redirectUri.toString())).build(); }catch(Exception e){ logger.error("invalid redirect uri created",e); return Response.serverError().build(); } } private Condition[] evaluateConditions(List conditions){ List props= new ArrayList(); for (org.gcube.dataaccess.spql.model.where.Condition condition :conditions){ switch (condition.getParameter()) { case EVENT_DATE: ParserDate parserDate = (ParserDate)condition.getValue(); Calendar value = parserDate.getValue(); props.add(new Condition(Conditions.DATE, value, Operator.valueOf(condition.getOperator().name()))); break; case COORDINATE: ParserCoordinate parserCoordinate = (ParserCoordinate)condition.getValue(); Coordinate coordinate = new Coordinate(parserCoordinate.getValue().getLatitude(), parserCoordinate.getValue().getLongitude()); props.add(new Condition(Conditions.COORDINATE, coordinate, Operator.valueOf(condition.getOperator().name()))); break; default: break; } } return props.toArray(new Condition[props.size()]); } @GET @Path("providers") @Produces(MediaType.APPLICATION_XML) public PluginDescriptions getSupportedPlugins(){ logger.trace("calling providers method"); PluginManager pluginManager = initializer.getPluginManager(); List descriptions = new ArrayList(); try{ for (AbstractPlugin plugin : pluginManager.plugins().values()) descriptions.add(Utils.getPluginDescription(plugin)); logger.trace("returning "+descriptions.size()+" descriptions"); }catch(Exception e){ logger.error("error producing descriptions", e); } return new PluginDescriptions(descriptions); } }