package org.nextprot.api.web.controller; import org.jsondoc.core.annotation.ApiMethod; import org.jsondoc.core.annotation.ApiQueryParam; import org.jsondoc.core.pojo.ApiVerb; import org.nextprot.api.commons.exception.NextProtException; import org.nextprot.api.commons.service.MasterIdentifierService; import org.nextprot.api.commons.utils.StringUtils; import org.nextprot.api.core.service.export.format.EntryBlock; import org.nextprot.api.core.service.export.format.FileFormat; import org.nextprot.api.solr.QueryRequest; import org.nextprot.api.user.domain.UserProteinList; import org.nextprot.api.user.service.UserProteinListService; import org.nextprot.api.web.service.ExportService; import org.nextprot.api.web.service.SearchService; import org.nextprot.api.web.service.impl.writer.EntryStreamWriter; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.*; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.*; import static org.nextprot.api.web.service.impl.writer.EntryStreamWriter.newAutoCloseableWriter; /** * Controller class responsible to extract in streaming * * @author dteixeira */ @Lazy @Controller // @Api(name = "Export", description = // "Export multiple entries based on a chromosome or a user list. A template can also be given in order to export only subparts of the entries.") public class ExportController { @Autowired private ExportService exportService; @Autowired private SearchService searchService; @Autowired private UserProteinListService proteinListService; @Autowired private MasterIdentifierService masterIdentifierService; @RequestMapping(value = "/export/entries/all", method = {RequestMethod.GET}) public void streamAllEntries(HttpServletRequest request, HttpServletResponse response, Model model) { FileFormat format = FileFormat.valueOf(request); streamAllEntries(format, response, "entry"); } @RequestMapping(value = "/export/entries/{view}", method = {RequestMethod.GET}) public void streamEntriesSubPart(@PathVariable("view") String view, HttpServletRequest request, HttpServletResponse response, @RequestParam(value = "query", required = false) String query, @RequestParam(value = "listId", required = false) String listId, @RequestParam(value = "queryId", required = false) String queryId, @RequestParam(value = "sparql", required = false) String sparql, @RequestParam(value = "chromosome", required = false) String chromosome, @RequestParam(value = "filter", required = false) String filter, @RequestParam(value = "sort", required = false) String sort, @RequestParam(value = "order", required = false) String order, @RequestParam(value = "quality", required = false) String quality, Model model) { QueryRequest qr = getQueryRequest(query, listId, queryId, sparql, chromosome, filter, quality, sort, order); FileFormat format = FileFormat.valueOf(request); streamEntries(format, response, view, qr); } @RequestMapping(value = "/export/entries", method = {RequestMethod.GET}) public void streamEntries(HttpServletRequest request, HttpServletResponse response, @RequestParam(value = "query", required = false) String query, @RequestParam(value = "chromosome", required = false) String chromosome, @RequestParam(value = "listId", required = false) String listId, @RequestParam(value = "queryId", required = false) String queryId, @RequestParam(value = "sparql", required = false) String sparql, @RequestParam(value = "filter", required = false) String filter, @RequestParam(value = "sort", required = false) String sort, @RequestParam(value = "order", required = false) String order, @RequestParam(value = "quality", required = false) String quality, Model model) { QueryRequest qr = getQueryRequest(query, listId, queryId, sparql, chromosome, filter, quality, sort, order); FileFormat format = FileFormat.valueOf(request); streamEntries(format, response, "entry", qr); } @RequestMapping(value = "/export/templates", method = {RequestMethod.GET}) @ResponseBody public Map<String, Set<String>> getXMLTemplates() { return EntryBlock.getFormatViews(); } @ApiMethod(path = "/export/lists/{listId}", verb = ApiVerb.GET, description = "Exports entries accessions from a list") @RequestMapping("/export/lists/{listId}") public void exportList(HttpServletResponse response, HttpServletRequest request, @ApiQueryParam(name = "listname", description = "The list id") @PathVariable("listId") String listId) { UserProteinList pl = this.proteinListService.getUserProteinListByPublicId(listId); String fileName = pl.getName() + ".txt"; response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\""); // 2 ways of doing it: either add the token in the header or generate a // secret value for each list that is created // http://alpha-api.nextprot.org/export/lists/3C5KYA1M try { if (pl.getDescription() != null) { response.getWriter().write("#" + pl.getDescription() + StringUtils.CR_LF); } if (pl.getAccessionNumbers() != null) { for (String s : pl.getAccessionNumbers()) { response.getWriter().write(s); response.getWriter().write(StringUtils.CR_LF); } } } catch (Exception e) { throw new NextProtException(e.getMessage(), e); } } private List<String> getAccessions(QueryRequest queryRequest) { Set<String> accessionsSet = searchService.getAccessions(queryRequest); List<String> accessions; if (queryRequest.getSort() != null || queryRequest.getOrder() != null) { //TODO This is very slow and is highly memory intensive please review the way of sorting this using only the asking for ids. See the SearchServiceTest accessions = searchService.sortAccessions(queryRequest, accessionsSet); } else { accessions = new ArrayList<>(accessionsSet); Collections.sort(accessions); } return accessions; } private void streamEntries(FileFormat format, HttpServletResponse response, String viewName, QueryRequest queryRequest) { setResponseHeader(format, viewName, queryRequest, response); List<String> entries = getAccessions(queryRequest); try (EntryStreamWriter writer = newAutoCloseableWriter(format, viewName, response.getOutputStream())) { exportService.streamResults(writer, viewName, entries); } catch (IOException e) { throw new NextProtException(format.getExtension()+" streaming failed: cannot export "+entries.size()+" entries (query="+queryRequest.getQuery()+")", e); } } private void streamAllEntries(FileFormat format, HttpServletResponse response, String viewName) { setResponseHeader(format, response); List<String> entries = new ArrayList<>(masterIdentifierService.findUniqueNames()); try (EntryStreamWriter writer = newAutoCloseableWriter(format, viewName, response.getOutputStream())) { exportService.streamResults(writer, viewName, entries); } catch (IOException e) { throw new NextProtException(format.getExtension()+" streaming failed: cannot export "+entries.size()+" entries (all)", e); } } private void setResponseHeader(FileFormat format, String viewName, QueryRequest queryRequest, HttpServletResponse response) { String filename = getFilename(queryRequest, viewName, format); if (!format.equals(FileFormat.JSON)) { response.setHeader("Content-Disposition", "attachment; filename=\"" + filename + "\""); } } private void setResponseHeader(FileFormat format, HttpServletResponse response) { String filename = "nextprot-entries-all" + "." + format.getExtension(); if (!format.equals(FileFormat.JSON)) { response.setHeader("Content-Disposition", "attachment; filename=\"" + filename + "\""); } } private String getFilename(QueryRequest queryRequest, String viewName, FileFormat format) { if (queryRequest.hasNextProtQuery()) { return "nextprot-query-" + queryRequest.getQueryId() + "-" + viewName + "." + format.getExtension(); } else if (queryRequest.hasList()) { return "nextprot-list-" + queryRequest.getListId() + "-" + viewName + "." + format.getExtension(); } else if (queryRequest.getQuery() != null) { // search and add filters return "nextprot-search-" + queryRequest.getQuery() + "-" + viewName + "." + format.getExtension(); } else if (queryRequest.getSparql() != null) { // search and add filters return "nextprot-sparql-" + queryRequest.getSparql() + "-" + viewName + "." + format.getExtension(); } else if (queryRequest.getChromosome() != null) { // search and add filters return "nextprot-chromosome-" + queryRequest.getChromosome() + "-" + viewName + "." + format.getExtension(); } else { throw new NextProtException("Not implemented yet."); } } private static QueryRequest getQueryRequest(String query, String listId, String queryId, String sparql, String chromosome, String filter, String quality, String sort, String order) { QueryRequest qr = new QueryRequest(); qr.setQuery(query); if (listId != null) { qr.setListId(listId); } if (sparql != null) { qr.setSparql(sparql); } if (chromosome != null) { qr.setChromosome(chromosome); } qr.setQueryId(queryId); qr.setRows("50"); qr.setFilter(filter); qr.setSort(sort); qr.setOrder(order); qr.setQuality(quality); return qr; } }