/** * */ package org.gcube.portlets.user.workspaceexplorerapp.server; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.StringReader; import java.util.ArrayList; import java.util.List; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.io.IOUtils; import org.apache.log4j.Logger; import org.gcube.common.storagehubwrapper.server.tohl.Workspace; import org.gcube.common.storagehubwrapper.shared.tohl.WorkspaceFolder; import org.gcube.common.storagehubwrapper.shared.tohl.WorkspaceItem; import org.gcube.common.storagehubwrapper.shared.tohl.exceptions.ItemNotFoundException; import org.gcube.common.storagehubwrapper.shared.tohl.items.FileItem; import org.gcube.common.storagehubwrapper.shared.tohl.items.ImageFileItem; import org.gcube.common.storagehubwrapper.shared.tohl.items.ItemStreamDescriptor; import org.gcube.common.storagehubwrapper.shared.tohl.items.PDFFileItem; import org.gcube.common.storagehubwrapper.shared.tohl.items.URLFileItem; import org.gcube.common.storagehubwrapper.shared.tohl.items.URLItem; import org.gcube.portlets.user.workspaceexplorerapp.client.WorkspaceExplorerAppConstants; import org.gcube.portlets.user.workspaceexplorerapp.server.workspace.AllowedMimeTypeToInline; import org.gcube.portlets.user.workspaceexplorerapp.server.workspace.MimeTypeUtility; import org.gcube.portlets.user.workspaceexplorerapp.server.workspace.WsInstanceUtil; import org.gcube.portlets.user.workspaceexplorerapp.shared.HandlerResultMessage; /** * The Class DownloadServlet. * * @author Francesco Mangiacrapa francesco.mangiacrapa@isti.cnr.it */ public class DownloadWorkspaceExplorerServlet extends HttpServlet{ /** * */ private static final String ERROR404_HTML = "error404.html"; private static final long serialVersionUID = -8423345575690165644L; protected static Logger logger = Logger.getLogger(DownloadWorkspaceExplorerServlet.class); public static final String ERROR_ITEM_DOES_NOT_EXIST = "Item does not exist. It may have been deleted by another user"; public static final String REDIRECTONERROR = "redirectonerror"; private final String VALIDATEITEM = WorkspaceExplorerAppConstants.VALIDATEITEM; private final String IDS = WorkspaceExplorerAppConstants.IDS; private final String IDS_SEPARATOR = WorkspaceExplorerAppConstants.IDS_SEPARATOR; /** * {@inheritDoc} */ @Override public void init() throws ServletException { super.init(); logger.trace("Workspace DownloadServlet ready."); } /* (non-Javadoc) * @see javax.servlet.http.HttpServlet#doGet(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) */ public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException { String itemIds = req.getParameter(IDS); boolean viewContent = req.getParameter("viewContent")==null?false:req.getParameter("viewContent").equals("true"); boolean isValidItem = req.getParameter(VALIDATEITEM)==null?false:req.getParameter(VALIDATEITEM).equals("true"); boolean urlRedirectOnError = req.getParameter(REDIRECTONERROR)==null?false:req.getParameter(REDIRECTONERROR).equals("true"); logger.trace("Input Params [ids: "+itemIds + ", viewContent: "+viewContent+", "+VALIDATEITEM +": " +isValidItem+", urlRedirectOnError:" +urlRedirectOnError+"]"); if(itemIds==null || itemIds.isEmpty()){ sendError(resp,HttpServletResponse.SC_INTERNAL_SERVER_ERROR +": Item id is null"); return; } logger.trace("FILE DOWNLOAD REQUEST "+itemIds); List ids = toList(itemIds, IDS_SEPARATOR); Workspace wa = null; try { wa = WsInstanceUtil.getWorkspace(req.getSession()); } catch (Exception e) { /*if (e instanceof SessionExpiredException){ sendErrorForStatus(resp, HttpServletResponse.SC_UNAUTHORIZED +": Session expired", HttpServletResponse.SC_UNAUTHORIZED); return; }*/ handleError(urlRedirectOnError, req, resp, itemIds, HttpServletResponse.SC_INTERNAL_SERVER_ERROR +": Error during workspace retrieving"); return; } if (wa == null) { handleError(urlRedirectOnError, req, resp, itemIds, HttpServletResponse.SC_INTERNAL_SERVER_ERROR +": Error, no workspace in session"); return; } WorkspaceItem item; try { //MULTIPLE DOWNLOAD - CREATE A ZIP FOR SUCH WORKSPACE IDs AND RETURN // if(ids.size()>1){ // List listWI = toWorkspaceItems(wa, ids); // try { // //TODO MUST BE IMPLEMENTED //// File tmpZip = ZipUtil.zipWorkspaceItems(listWI, null); //// resp.setHeader( "Content-Disposition", "attachment; filename=\"gCube Workspace Files - " + new Date() +".zip\"" ); //// resp.setContentType("application/zip"); //// resp = setContentLength(resp, tmpZip.length()); //// OutputStream out = resp.getOutputStream(); //// //// FileInputStream fileTmpZip = new FileInputStream(tmpZip); //// IOUtils.copy(fileTmpZip, resp.getOutputStream()); //// fileTmpZip.close(); //// //// out.close(); //// tmpZip.delete(); // return; // } // catch (Exception e) { // logger.error("Error during folder compression "+itemIds,e); // handleError(urlRedirectOnError, req, resp, itemIds, HttpServletResponse.SC_INTERNAL_SERVER_ERROR +": Error during folder compression: "+e.getMessage()); // return; // } // // } //SINGLE DONWLOAD - DOWNLOAD WORKSPACE ITEM item = wa.getItemForExplorer(ids.get(0), false, false, false); if(isValidItem){ //ADDED 25/06/2013 - THIS CODE RETURN A SC_ACCEPT IS ITEM EXIST String message = HttpServletResponse.SC_ACCEPTED+ ": The resource is available"; sendMessageResourceAvailable(resp, message); logger.trace("response return: "+message); return; } } catch (ItemNotFoundException e) { logger.error("Requested item "+itemIds+" not found",e); handleError(urlRedirectOnError, req, resp, itemIds, HttpServletResponse.SC_INTERNAL_SERVER_ERROR +": The file has been deleted by another user."); return; } catch (Exception e) { logger.error("Error during item retrieving "+itemIds,e); handleError(urlRedirectOnError, req, resp, itemIds, HttpServletResponse.SC_INTERNAL_SERVER_ERROR +": Error during data retrieving: "+e.getMessage()); return; } String itemId = item.getId(); String versionID = null; switch (item.getType()) { case URL_ITEM: { try{ logger.info("Downloading "+item.getType()); String urlValue = "URL not found"; if(item instanceof URLItem) { URLItem theURL = (URLItem) item; urlValue = theURL.getValue()==null?"URL not found":theURL.getValue().toString(); } StringBuilder build = new StringBuilder(); build.append("#URL downloaded from D4Science, source filename: "+item.getName()); build.append("\n"); build.append(urlValue); String fileContent = build.toString(); logger.info("Writing file content: \n"+fileContent); ByteArrayInputStream is = new ByteArrayInputStream(fileContent.getBytes()); String contentDisposition = viewContent?"inline":"attachment"; String urlMimeType = "text/uri-list"; String itemName = MimeTypeUtility.getNameWithExtension(item.getName(), urlMimeType); resp.setHeader("Content-Disposition", contentDisposition+"; filename=\"" + itemName + "\"" ); resp.setContentType(urlMimeType); OutputStream out = resp.getOutputStream(); IOUtils.copy(is, out); is.close(); out.close(); return; }catch (Exception e) { logger.error("Error during downloading the item "+itemId,e); handleError(urlRedirectOnError, req, resp, itemId, HttpServletResponse.SC_INTERNAL_SERVER_ERROR +": Error during data downloading: "+e.getMessage()); return; } } case FOLDER: case SHARED_FOLDER: case VRE_FOLDER: case SMART_FOLDER: { WorkspaceFolder workspaceFolder = (WorkspaceFolder) item; ItemStreamDescriptor descr; try { descr = wa.downloadFolder(workspaceFolder.getId(), workspaceFolder.getName(), null); } catch (Exception e) { logger.error("Error on downloading the folder with id "+itemId, e); String error = e.getMessage()!=null?e.getMessage():"The folder is not available for downloading"; handleError(urlRedirectOnError, req, resp, itemId, HttpServletResponse.SC_INTERNAL_SERVER_ERROR +": "+error); return; } try{ logger.info("Downloading the folder: "+workspaceFolder); String contentDisposition = viewContent?"inline":"attachment"; String mimeType = "application/zip"; String itemName = MimeTypeUtility.getNameWithExtension(item.getName(), mimeType); resp.setHeader("Content-Disposition", contentDisposition+"; filename=\"" + itemName + "\"" ); resp.setContentType(mimeType); OutputStream out = resp.getOutputStream(); InputStream is = descr.getStream(); IOUtils.copy(is, out); is.close(); out.close(); return; } catch (Exception e) { logger.error("Error during item downloading "+itemId,e); handleError(urlRedirectOnError, req, resp, itemId, HttpServletResponse.SC_INTERNAL_SERVER_ERROR +": Error during folder data retrieving: "+e.getMessage()); return; } } case FILE_ITEM:{ FileItem workspaceFileItem = (FileItem) item; ItemStreamDescriptor descr; try { logger.info("Downloading the file id: "+workspaceFileItem.getId()+" with name: "+workspaceFileItem.getName()+" and versionID: "+versionID); descr = wa.downloadFile(workspaceFileItem.getId(), workspaceFileItem.getName(), versionID, null); } catch (Exception e1) { logger.error("Error on downloading the file with id "+itemId, e1); String error = e1.getMessage()!=null?e1.getMessage():"The file is not available for downloading"; handleError(urlRedirectOnError, req, resp, itemId, HttpServletResponse.SC_INTERNAL_SERVER_ERROR +": "+error); return; } switch (workspaceFileItem.getFileItemType()) { case PDF_DOCUMENT:{ try{ PDFFileItem pdfFile = (PDFFileItem) workspaceFileItem; logger.info("Downloading: "+pdfFile); String mimeType = pdfFile.getMimeType(); logger.trace("EXTERNAL_FILE DOWNLOAD FOR "+pdfFile.getId()); String contentDisposition = viewContent?"inline":"attachment"; String itemName = MimeTypeUtility.getNameWithExtension(descr.getItemName(), mimeType); resp.setHeader("Content-Disposition", contentDisposition+"; filename=\"" + itemName + "\"" ); resp.setContentType(mimeType); //Fixing Incident: 18926, replacing pdfFile.getSize() with ItemStreamDescriptor.getSize() if(descr.getSize()!=null && descr.getSize()>0) { resp = setContentLength(resp, descr.getSize()); } logger.info("The "+workspaceFileItem.getFileItemType()+" size is: "+descr.getSize()); //resp = setContentLength(resp, pdfFile.getSize()); InputStream is = descr.getStream(); OutputStream out = resp.getOutputStream(); IOUtils.copy(is, out); is.close(); out.close(); } catch (Exception e) { logger.error("Error during external item retrieving "+itemId,e); handleError(urlRedirectOnError, req, resp, itemId, HttpServletResponse.SC_INTERNAL_SERVER_ERROR +": Error during data retrieving: "+e.getMessage()); return; } return; } case IMAGE_DOCUMENT:{ try{ ImageFileItem imageFile = (ImageFileItem) workspaceFileItem; logger.info("Downloading: "+imageFile); String mimeType = imageFile.getMimeType(); String itemName = MimeTypeUtility.getNameWithExtension(descr.getItemName(), mimeType); String contentDisposition = viewContent?"inline":"attachment"; resp.setHeader("Content-Disposition", contentDisposition+"; filename=\"" + itemName + "\"" ); resp.setContentType(mimeType); //Fixing Incident: 18926, replacing imageFile.getSize() with ItemStreamDescriptor.getSize() if(descr.getSize()!=null && descr.getSize()>0) { resp = setContentLength(resp, descr.getSize()); } logger.info("The "+workspaceFileItem.getFileItemType()+" size is: "+descr.getSize()); //resp = setContentLength(resp, imageFile.getSize()); InputStream is = descr.getStream(); OutputStream out = resp.getOutputStream(); IOUtils.copy(is, out); is.close(); out.close(); return; } catch (Exception e) { logger.error("Error during item retrieving "+itemId,e); handleError(urlRedirectOnError, req, resp, itemId, HttpServletResponse.SC_INTERNAL_SERVER_ERROR +": Error during data retrieving: "+e.getMessage()); return; } } case URL_DOCUMENT:{ try{ URLFileItem externalUrl = (URLFileItem) workspaceFileItem; logger.info("Downloading: "+externalUrl); String urlMimeType = "text/uri-list"; String itemName = MimeTypeUtility.getNameWithExtension(descr.getItemName(), urlMimeType); String contentDisposition = viewContent?"inline":"attachment"; resp.setHeader("Content-Disposition", contentDisposition+"; filename=\"" + itemName + "\"" ); resp.setContentType(urlMimeType); //resp = setContentLength(resp, externalUrl.getSize()); //MODIFIED 22-05-2013 CLOSE STREAM OutputStream out = resp.getOutputStream(); InputStream is = descr.getStream(); IOUtils.copy(descr.getStream(), out); is.close(); out.close(); return; } catch (Exception e) { logger.error("Error during item retrieving "+itemId,e); handleError(urlRedirectOnError, req, resp, itemId, HttpServletResponse.SC_INTERNAL_SERVER_ERROR +": Error during data retrieving: "+e.getMessage()); return; } } case GCUBE_ITEM:{ try{ // Document document = (Document)item; org.gcube.common.storagehubwrapper.shared.tohl.items.GCubeItem gcubeItem = (org.gcube.common.storagehubwrapper.shared.tohl.items.GCubeItem) item; //Cast GCubeItem logger.info("Downloading: "+gcubeItem); String mimeType = "text/plain"; String contentDisposition = viewContent?"inline":"attachment"; resp.setHeader("Content-Disposition", contentDisposition+"; filename=\"" + gcubeItem.getName() + ".txt\"" ); resp.setContentType(mimeType); //MODIFIED 22-05-2013 CLOSE STREAM OutputStream out = resp.getOutputStream(); InputStream is = descr.getStream(); IOUtils.copy(is, out); is.close(); out.close(); return; } catch (Exception e) { logger.error("Error during item retrieving "+itemId,e); handleError(urlRedirectOnError, req, resp, itemId, HttpServletResponse.SC_INTERNAL_SERVER_ERROR +": Error during data retrieving: "+e.getMessage()); return; } } default:{ try{ String itemName = MimeTypeUtility.getNameWithExtension(descr.getItemName(), workspaceFileItem.getMimeType()); logger.info("Downloading default item: "+workspaceFileItem); //String contentDisposition = viewContent?"inline":"attachment"; //Support #16430 //The 'inline' option may be badly managed by browser String contentDisposition = "attachment"; List allowedPrefixes = AllowedMimeTypeToInline.getAllowedMimeTypePrefixes(); if(viewContent) { logger.info("Checking if the mime type "+workspaceFileItem.getMimeType()+" exists among Mime Type Prefixes"); for (String prefix : allowedPrefixes) { if(workspaceFileItem.getMimeType().startsWith(prefix)) { logger.info("yes, the prefix "+prefix+" is matching the mimetype "+workspaceFileItem.getMimeType()+", so returning 'Content-Disposition' at 'inline'"); contentDisposition = "inline"; break; } } } resp.setHeader("Content-Disposition", contentDisposition+"; filename=\"" + itemName + "\"" ); //Fixing Incident: 18926, replacing workspaceFileItem.getSize() with ItemStreamDescriptor.getSize() if(descr.getSize()!=null && descr.getSize()>0) { resp = setContentLength(resp, descr.getSize()); } logger.info("The size is: "+descr.getSize()); //MODIFIED 22-05-2013 CLOSE STREAM OutputStream out = resp.getOutputStream(); InputStream is = descr.getStream(); IOUtils.copy(descr.getStream(), out); is.close(); out.close(); return; } catch (Exception e) { logger.error("Error during item retrieving "+itemId,e); handleError(urlRedirectOnError, req, resp, itemId, HttpServletResponse.SC_INTERNAL_SERVER_ERROR +": Error during data retrieving: "+e.getMessage()); return; } } } } default: break; } handleError(urlRedirectOnError, req, resp, itemId,HttpServletResponse.SC_INTERNAL_SERVER_ERROR +": Error during data retrieving"); return; } /** * To list. * * @param ids the ids * @param separator the separator * @return the list */ private static List toList(String ids, String separator){ String[] toArray = ids.split(separator); List lstIds = new ArrayList(toArray.length); for (String id : toArray) { if(id!=null && !id.isEmpty()) lstIds.add(id); } logger.trace("ids to list: "+lstIds); return lstIds; } /** * To workspace items. * * @param ws the ws * @param workspaceItemIds the workspace item ids * @return the list */ /*private List toWorkspaceItems(Workspace ws, List workspaceItemIds){ if(workspaceItemIds==null) return null; List listWI = new ArrayList(workspaceItemIds.size()); for (String wsId : workspaceItemIds) { try{ listWI.add(ws.getItem(wsId)); }catch(Exception e){ logger.warn("Error on getting item id: "+wsId +", skipping item"); } } return listWI; }*/ /** * Method to manage HttpServletResponse content length also to big data. * * @param resp the resp * @param length the length * @return the http servlet response */ protected HttpServletResponse setContentLength(HttpServletResponse resp, long length){ try{ if (length <= Integer.MAX_VALUE) resp.setContentLength((int)length); else resp.addHeader("Content-Length", Long.toString(length)); }catch(Exception e){ //silent } return resp; } /** * Handle error. * * @param urlRedirectOnError the url redirect on error * @param req the req * @param resp the resp * @param itemId the item id * @param message the message * @throws IOException Signals that an I/O exception has occurred. */ protected void handleError(boolean urlRedirectOnError, HttpServletRequest req, HttpServletResponse resp, String itemId, String message) throws IOException{ logger.warn("Handle error occurred: "+message); logger.trace("urlRedirectOnError is active: "+urlRedirectOnError); if(urlRedirectOnError){ urlRedirect(req, resp, ERROR404_HTML); }else sendError(resp,message); } /** * Send error. * * @param response the response * @param message the message * @throws IOException Signals that an I/O exception has occurred. */ protected void sendError(HttpServletResponse response, String message) throws IOException { response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); HandlerResultMessage resultMessage = HandlerResultMessage.errorResult(message); logger.trace("error message: "+resultMessage); logger.trace("writing response..."); StringReader sr = new StringReader(resultMessage.toString()); IOUtils.copy(sr, response.getOutputStream()); logger.trace("response writed"); response.flushBuffer(); } /** * Send error for status. * * @param response the response * @param message the message * @param status the status * @throws IOException Signals that an I/O exception has occurred. */ protected void sendErrorForStatus(HttpServletResponse response, String message, int status) throws IOException { response.setStatus(status); HandlerResultMessage resultMessage = HandlerResultMessage.errorResult(message); logger.trace("error message: "+resultMessage); logger.trace("writing response..."); StringReader sr = new StringReader(resultMessage.toString()); IOUtils.copy(sr, response.getOutputStream()); logger.trace("response writed"); response.flushBuffer(); } /** * Send message. * * @param response the response * @param message the message * @throws IOException Signals that an I/O exception has occurred. */ protected void sendMessage(HttpServletResponse response, String message) throws IOException { response.setStatus(HttpServletResponse.SC_ACCEPTED); HandlerResultMessage resultMessage = HandlerResultMessage.okResult(message); response.getWriter().write(resultMessage.toString()); response.flushBuffer(); } /** * Send message resource available. * * @param response the response * @param message the message * @throws IOException Signals that an I/O exception has occurred. */ protected void sendMessageResourceAvailable(HttpServletResponse response, String message) throws IOException { response.setStatus(HttpServletResponse.SC_ACCEPTED); HandlerResultMessage resultMessage = HandlerResultMessage.okResult(message); response.getWriter().write(resultMessage.toString()); response.flushBuffer(); } /** * Send warn message. * * @param response the response * @param message the message * @throws IOException Signals that an I/O exception has occurred. */ protected void sendWarnMessage(HttpServletResponse response, String message) throws IOException { response.setStatus(HttpServletResponse.SC_ACCEPTED); HandlerResultMessage resultMessage = HandlerResultMessage.warnResult(message); response.getWriter().write(resultMessage.toString()); response.flushBuffer(); } /** * Url redirect. * * @param req the req * @param response the response * @param errorPage the error page * @throws IOException Signals that an I/O exception has occurred. */ protected void urlRedirect(HttpServletRequest req, HttpServletResponse response, String errorPage) throws IOException { String requestUrl = getRedirectURL(req) +errorPage; logger.trace("Url redirect on: "+requestUrl); // System.out.println("Url redirect on: "+requestUrl); response.sendRedirect(response.encodeRedirectURL(requestUrl)); return; } /** * Gets the redirect url. * * @param req the req * @return the redirect url */ public static String getRedirectURL(HttpServletRequest req) { String scheme = req.getScheme(); // http String serverName = req.getServerName(); // hostname.com int serverPort = req.getServerPort(); // 80 String contextPath = req.getContextPath(); // /mywebapp // String servletPath = req.getServletPath(); // /servlet/MyServlet // String pathInfo = req.getPathInfo(); // /a/b;c=123 // String queryString = req.getQueryString(); // d=789 // Reconstruct original requesting URL StringBuffer url = new StringBuffer(); url.append(scheme).append("://").append(serverName); if (serverPort != 80 && serverPort != 443) { url.append(":").append(serverPort); } url.append("/").append(contextPath); logger.trace("returning url: "+url); return url.toString(); } }