/* * Copyright (c) 2006 Genome Research Limited. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as published * by the Free Software Foundation; either version 2 of the License or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this program; see the file COPYING.LIB. If not, write to * the Free Software Foundation Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307 USA */ package org.genedb.web.mvc.controller.download; import org.genedb.querying.core.QueryException; import org.genedb.querying.history.HistoryItem; import org.genedb.querying.history.HistoryManager; import org.genedb.web.mvc.controller.HistoryController; import org.genedb.web.mvc.controller.HistoryManagerFactory; import org.apache.log4j.Logger; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.servlet.ModelAndView; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.Writer; import java.util.Hashtable; import java.util.LinkedHashMap; import java.util.List; import java.io.BufferedInputStream; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.google.common.collect.Lists; import com.google.gson.Gson; /** * List Download * * @author Giles Velarde (gv1) * @author Chinmay Patel (cp2) * @author Adrian Tivey (art) * */ @Controller @RequestMapping("/Download") public class DownloadController { private Logger logger = Logger.getLogger(this.getClass()); private final boolean deleteFiles = true; private DownloadProcessUtil util; public void setUtil(DownloadProcessUtil util) { this.util = util; } private HistoryManagerFactory historyManagerFactory; public void setHistoryManagerFactory(HistoryManagerFactory historyManagerFactory) { this.historyManagerFactory = historyManagerFactory; } @RequestMapping(method=RequestMethod.GET, value="/{historyItem}") public ModelAndView displayForm( @PathVariable("historyItem") int historyItem) { logger.error("displayForm called"); ModelAndView mav = new ModelAndView("history/historyForm", "historyItem", historyItem); return mav; } final private static int maxResultsInWebRequest = 1000; @RequestMapping(method=RequestMethod.POST, value="/{historyItem}") public ModelAndView onSubmit( @PathVariable("historyItem") int historyItem, @RequestParam("cust_format") OutputFormat outputFormat, @RequestParam("cust_field") String[] custFields, @RequestParam("output_dest") OutputDestination outputDestination, @RequestParam(value="sequenceType", required=false) SequenceType sequenceType, @RequestParam("cust_header") boolean includeHeader, @RequestParam("field_sep") String fieldSeparator, @RequestParam("field_blank") String blankField, @RequestParam("field_intsep") String fieldInternalSeparator, @RequestParam("prime3") int prime3, @RequestParam("prime5") int prime5, @RequestParam("email") String email, HttpServletRequest request, HttpServletResponse response ) throws IOException, QueryException { String downloadLinkUrl = request.getScheme() + "://" + request.getServerName() + "/Download/batch"; logger.info("URL:: " + downloadLinkUrl); HistoryManager historyManager = historyManagerFactory.getHistoryManager(request.getSession()); LinkedHashMap<String, HistoryItem> historyItems = historyManager.getHistoryItems(); if (historyItem > historyItems.size()) { response.sendError(511); return null; } List<OutputOption> outputOptions = Lists.newArrayList(); for (String custField : custFields) { outputOptions.add(OutputOption.valueOf(custField)); } HistoryItem hItem = historyManager.getHistoryItemByID(historyItem-1); if (hItem == null) { logger.error("Could not find the history item " + historyItem); response.sendError(511); return null; } String description = HistoryController.getFormattedParameterMap(hItem); String historyItemName = hItem.getName(); List<String> uniqueNames = hItem.getIds(); if (blankField.equals("blank")) { blankField = ""; } File downloadTmpFolder = util.gettDownloadTmpFolder(); String fileName = historyItemName + "." + util.getTime() + "." + outputFormat.name().toLowerCase(); if (outputDestination == OutputDestination.TO_EMAIL) { if (email != null && email.length() > 0) { saveDownloadDetailsToJsonFile( fileName, downloadTmpFolder, outputFormat, outputOptions, outputDestination, sequenceType, includeHeader, fieldSeparator, blankField, fieldInternalSeparator, prime3, prime5, email, uniqueNames, historyItemName, description, downloadLinkUrl); response.getWriter().append("The results will be mailed back to " + email + " once processed."); return null; } else { response.getWriter().append("Please supply an email address."); return null; } } if (uniqueNames.size() > maxResultsInWebRequest) { response.getWriter().append("The number of results exceeds the maximum the web server will download in a single request (" + maxResultsInWebRequest + ")." + "\nPlease supply your email on the previous page and the results will be mailed back to you."); return null; } // if we got this far, it means we're going to try a download inside the web request. DownloadProcess process = new DownloadProcess(outputFormat, custFields, outputDestination, sequenceType, includeHeader, fieldSeparator, blankField, fieldInternalSeparator, prime3, prime5, email, uniqueNames, historyItemName, description, util, downloadLinkUrl); String filePath = downloadTmpFolder + "/" + fileName; if (outputFormat == OutputFormat.XLS) { OutputStream outStream = null; File outFile = null; if (outputDestination == OutputDestination.TO_BROWSER) { outStream = response.getOutputStream(); } else if (outputDestination == OutputDestination.TO_FILE) { outFile = new File( filePath ); outStream = new FileOutputStream(outFile); } response.setContentType("application/vnd.ms-excel"); process.generateXLS(outStream); /* * As this is a binary file, whether or not a TO_FILE is chosen, a file will be downloaded by the user. */ if (outputDestination == OutputDestination.TO_FILE) { response.setHeader("Content-Disposition", "attachment; filename=" + outFile.getName()); OutputStream os = response.getOutputStream(); returnFile(outFile, os); } else { response.setHeader("Content-Disposition", "attachment; filename=" + fileName); } if ((outFile != null) && (deleteFiles)) { outFile.delete(); } } else { Writer out = null; File tabOutFile = null; if (outputDestination == OutputDestination.TO_BROWSER) { out = response.getWriter(); } else if (outputDestination == OutputDestination.TO_FILE) { tabOutFile = new File( filePath ); out = new FileWriter(tabOutFile); } switch (outputFormat) { case CSV: response.setContentType("text/plain"); process.generateCSV(out); break; case HTML: response.setContentType("text/html"); process.generateHTML(out); break; case FASTA: response.setContentType("text/plain"); process.generateFASTA(out); break; } /* * Post formatting for different output destinations. */ if (outputDestination == OutputDestination.TO_FILE) { response.setContentType("application/x-download"); response.setHeader("Content-Disposition", "attachment; filename="+tabOutFile.getName()); OutputStream os = response.getOutputStream(); returnFile(tabOutFile, os); if ((tabOutFile != null) && (deleteFiles)) { tabOutFile.delete(); } } } logger.info(fileName + " complete"); return null; } @RequestMapping(method=RequestMethod.GET, value="/batch") public ModelAndView batch (HttpServletResponse response, @RequestParam("file") final String suppliedFileName) throws FileNotFoundException, IOException { final File baseFileFolder = util.gettDownloadTmpFolder(); File suppliedFile = new File(baseFileFolder, suppliedFileName); logger.info(String.format("Trying to return %s link for file %s.", suppliedFileName, suppliedFile.getAbsolutePath())); if ((! suppliedFile.isFile()) || (suppliedFile.isDirectory() || (! suppliedFile.getName().endsWith("zip")))) { logger.error("Could not find file"); response.getWriter().append("Could not find file " + suppliedFileName); return null; } response.setContentType("application/x-download"); response.setHeader("Content-Disposition", "attachment; filename="+suppliedFile.getName()); returnFile(suppliedFile, response.getOutputStream()); return null; } /** * Lifted from genedb classic. * * @param file * @param out * @throws FileNotFoundException * @throws IOException */ private void returnFile(File file, OutputStream out) throws FileNotFoundException, IOException { InputStream in = null; try { in = new BufferedInputStream(new FileInputStream(file)); byte[ ] buf = new byte[4 * 1024]; // 4K buffer int bytesRead; while ((bytesRead = in.read(buf)) != -1) { out.write(buf, 0, bytesRead); } } finally { if (in != null) in.close( ); } } /** * Save the query details to a JSON file, for batch processing. * * @param scriptFileNamePrefix * @param downloadTmpFolder * @param outputFormat * @param outputOptions * @param outputDestination * @param sequenceType * @param includeHeader * @param fieldSeparator * @param blankField * @param fieldInternalSeparator * @param prime3 * @param prime5 * @param email * @param uniqueNames * @param historyItemName * @param description * @throws IOException */ public void saveDownloadDetailsToJsonFile( String scriptFileNamePrefix, File downloadTmpFolder, OutputFormat outputFormat, List<OutputOption> outputOptions, OutputDestination outputDestination, SequenceType sequenceType, boolean includeHeader, String fieldSeparator, String blankField, String fieldInternalSeparator, int prime3, int prime5, String email, List<String> uniqueNames, String historyItemName, String description, String downloadLinkUrl) throws IOException { Hashtable<String, Object> ht = new Hashtable<String, Object>(); ht.put("custFields", outputOptions); ht.put("outputFormat", outputFormat); ht.put("outputDestination", outputDestination); ht.put("sequenceType", sequenceType); ht.put("includeHeader", includeHeader); ht.put("fieldSeparator", fieldSeparator); ht.put("blankField", blankField); ht.put("fieldInternalSeparator", fieldInternalSeparator); ht.put("prime3", prime3); ht.put("prime5", prime5); ht.put("email", email); ht.put("historyItemName", historyItemName); ht.put("description", description); ht.put("uniqueNames", uniqueNames); ht.put("url", downloadLinkUrl); String filePath = downloadTmpFolder + "/" + scriptFileNamePrefix + ".json"; FileWriter out = new FileWriter(filePath); Gson gson = new Gson(); gson.toJson(ht, out); out.close(); logger.info("Wrote to JSON file: " + filePath); } }