/** * */ package org.gcube.portlets.widgets.workspaceuploader.server; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Random; import java.util.UUID; import java.util.concurrent.TimeUnit; import javax.servlet.Servlet; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import org.apache.commons.fileupload.FileItemFactory; import org.apache.commons.fileupload.FileItemIterator; import org.apache.commons.fileupload.FileItemStream; import org.apache.commons.fileupload.FileUploadBase; import org.apache.commons.fileupload.FileUploadException; import org.apache.commons.fileupload.disk.DiskFileItemFactory; import org.apache.commons.fileupload.servlet.ServletFileUpload; import org.apache.commons.fileupload.util.Streams; import org.apache.commons.io.FilenameUtils; import org.apache.commons.io.IOUtils; import org.apache.commons.lang.Validate; import org.gcube.common.portal.PortalContext; import org.gcube.common.storagehub.model.items.FolderItem; import org.gcube.common.storagehub.model.items.Item; import org.gcube.common.storagehubwrapper.server.StorageHubWrapper; import org.gcube.common.storagehubwrapper.shared.tohl.WorkspaceFolder; import org.gcube.common.storagehubwrapper.shared.tohl.WorkspaceItem; import org.gcube.common.storagehubwrapper.shared.tohl.WorkspaceItemType; import org.gcube.common.storagehubwrapper.shared.tohl.exceptions.InsufficientPrivilegesException; import org.gcube.common.storagehubwrapper.shared.tohl.exceptions.InternalErrorException; import org.gcube.common.storagehubwrapper.shared.tohl.exceptions.ItemAlreadyExistException; import org.gcube.common.storagehubwrapper.shared.tohl.exceptions.ItemNotFoundException; import org.gcube.common.storagehubwrapper.shared.tohl.exceptions.WrongItemTypeException; import org.gcube.portlets.widgets.workspaceuploader.client.ConstantsWorkspaceUploader; import org.gcube.portlets.widgets.workspaceuploader.server.notification.NotificationsWorkspaceUploader; import org.gcube.portlets.widgets.workspaceuploader.server.notification.NotificationsWorkspaceUploaderProducer; import org.gcube.portlets.widgets.workspaceuploader.server.upload.AbstractUploadProgressListener; import org.gcube.portlets.widgets.workspaceuploader.server.upload.MemoryUploadListener; import org.gcube.portlets.widgets.workspaceuploader.server.upload.UploadCanceledException; import org.gcube.portlets.widgets.workspaceuploader.server.upload.UploadProgressInputStream; import org.gcube.portlets.widgets.workspaceuploader.server.upload.UploadProgressListener; import org.gcube.portlets.widgets.workspaceuploader.server.upload.WorkspaceUploaderMng; import org.gcube.portlets.widgets.workspaceuploader.server.util.WsUtil; import org.gcube.portlets.widgets.workspaceuploader.shared.HandlerResultMessage; import org.gcube.portlets.widgets.workspaceuploader.shared.WorkspaceUploadFile; import org.gcube.portlets.widgets.workspaceuploader.shared.WorkspaceUploaderItem; import org.gcube.portlets.widgets.workspaceuploader.shared.WorkspaceUploaderItem.UPLOAD_STATUS; import org.gcube.vomanagement.usermanagement.model.GCubeUser; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import org.json.JSONTokener; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * The Class WorkspaceUploadServletStream. * * @author Francesco Mangiacrapa francesco.mangiacrapa@isti.cnr.it * May 10, 2016 */ public class WorkspaceUploadServletStream extends HttpServlet implements Servlet{ public static final String UNKNOWN_UNKNOWN = "unknown/unknown"; private static final long serialVersionUID = 1778008252774571216L; protected static final String UTF_8 = "UTF-8"; public static final String VRE_ID_ATTR_NAME = "gcube-vreid"; public static final String CURR_GROUP_ID = ConstantsWorkspaceUploader.CURR_GROUP_ID; //public static final String CURR_USER_ID = ConstantsWorkspaceUploader.CURR_USER_ID; public static final String UPLOAD_TYPE = ConstantsWorkspaceUploader.UPLOAD_TYPE; public static final String ID_FOLDER = ConstantsWorkspaceUploader.ID_FOLDER; public static final String UPLOAD_FORM_ELEMENT = ConstantsWorkspaceUploader.UPLOAD_FORM_ELEMENT; public static final String CLIENT_UPLOAD_KEYS = ConstantsWorkspaceUploader.CLIENT_UPLOAD_KEYS; public static final String JSON_CLIENT_KEYS = ConstantsWorkspaceUploader.JSON_CLIENT_KEYS; public static final String IS_OVERWRITE = ConstantsWorkspaceUploader.IS_OVERWRITE; public static final String CANCEL_UPLOAD = ConstantsWorkspaceUploader.CANCEL_UPLOAD; public static final String FILE = "File"; public static final String ARCHIVE = "Archive"; public static final Map SUPPORTED_UNPACKING_ARCHIVE = new HashMap() {{ put("zip","application/zip"); //.zip put("7z","application/x-7z-compressed"); //.7z put("tar","application/x-tar"); //tar put("java archive","application/java-archive");//.jar put("jar","application/x-java-archive"); put("gtar","application/x-gtar"); }}; public static Logger logger = LoggerFactory.getLogger(WorkspaceUploadServletStream.class); private static boolean appEngine = false; /* * (non-Javadoc) * * @see javax.servlet.GenericServlet#init() */ @Override public void init() throws ServletException { super.init(); String appe = getInitParameter("appEngine"); if (appe != null) { appEngine = "true".equalsIgnoreCase(appe); } else { appEngine = isAppEngine(); } logger.debug("init: appEngine is "+appEngine); } /** * {@inheritDoc} */ @Override public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { logger.debug("GET method in "+WorkspaceUploadServletStream.class.getName()+" is running"); String clientUploadKey = request.getParameter(CLIENT_UPLOAD_KEYS); if (clientUploadKey == null){ sendError(response, "Internal error: UPLOAD KEY NOT FOUND"); return; } logger.debug("GET method CLIENT_UPLOAD_KEY "+clientUploadKey); boolean cancelUpload = Boolean.parseBoolean(request.getParameter(CANCEL_UPLOAD)); logger.debug("GET method CANCEL_UPLOAD "+cancelUpload); if (cancelUpload) { boolean cancelled = cancelUpload(request.getSession(), clientUploadKey); if(cancelled){ sendMessage(response, "Upload aborted "+clientUploadKey); // try { //// removeCurrentListener(request.getSession(), clientUploadKey); // WsUtil.eraseWorkspaceUploaderInSession(request.getSession(), clientUploadKey); // }catch (Exception e) { // logger.warn("An error occurred during removing cancelled upload from session "); // } } else sendWarnMessage(response, "Upload aborted for id: "+clientUploadKey +" has skipped, already aborted or completed?"); }else logger.debug(CANCEL_UPLOAD + " param not found"); return; } /** * {@inheritDoc} */ public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { logger.info("POST on UploadServlet"); boolean requestIsNull = request==null; logger.trace("[1] HttpServletRequest is: null? "+requestIsNull+", URI: "+request.getRequestURI() +", ServerName: "+request.getServerName()); if (!ServletFileUpload.isMultipartContent(request)) { logger.error("ERROR: multipart request not found"); sendError(response, "ERROR: multipart request not found"); return; } try { logger.info("UPLOAD-SERVLET starting"); HttpSession session = request.getSession(); logger.info("UPLOAD-SERVLET session: "+session); logger.debug("UPLOAD-SERVLET (" + session.getId() + ") new upload request received."); if(WsUtil.isSessionExpired(request)){ logger.error("SESSION_EXPIRED: session is expired"); sendSessionExpired(response, "SESSION_EXPIRED: session is expired"); return; } String destinationId = null; String uploadType = null; boolean isOverwrite = true; //CREATE A NEW VERSION OF FILE IS BEHAVIOUR BY DEFAULT // String clientUploadKey = null; FileItemStream uploadItem = null; ArrayList listClientUploadKeys = null; GCubeUser user = PortalContext.getConfiguration().getCurrentUser(request); FileItemFactory factory = new DiskFileItemFactory(); ServletFileUpload servletFileUpload = new ServletFileUpload(factory); /** * An iterator to instances of FileItemStream * parsed from the request, in the order that they were *transmitted. */ FileItemIterator fileItemIterator = servletFileUpload.getItemIterator(request); int uploadItemsCnt = 0; String scopeGroupId = ""; //GET FILE STREAM while (fileItemIterator.hasNext()) { FileItemStream item = fileItemIterator.next(); if (item.isFormField() && ID_FOLDER.equals(item.getFieldName())){ destinationId = Streams.asString(item.openStream()); logger.debug("ID_FOLDER OK "+destinationId); } if (item.isFormField() && UPLOAD_TYPE.equals(item.getFieldName())){ uploadType = Streams.asString(item.openStream()); logger.debug("UPLOAD_TYPE OK " +uploadType); } if (item.isFormField() && IS_OVERWRITE.equals(item.getFieldName())){ try{ isOverwrite = Boolean.parseBoolean(Streams.asString(item.openStream())); logger.debug("IS_OVERWRITE OK "+ isOverwrite); }catch(Exception e){ //Silent exception; } } if(item.isFormField() && CLIENT_UPLOAD_KEYS.equals(item.getFieldName())){ String jsonClientUploadKey = Streams.asString(item.openStream()); logger.debug("CLIENT_UPLOAD_KEY OK "+jsonClientUploadKey); LinkedHashMap mapKeys = parseJSONClientUploadKeys(jsonClientUploadKey); listClientUploadKeys = new ArrayList(mapKeys.keySet()); removeListenersIfDone(session, listClientUploadKeys); for (String clientUploadKey : listClientUploadKeys) { String fileName = mapKeys.get(clientUploadKey); WorkspaceUploaderItem workspaceUploader = createNewWorkspaceUploader(clientUploadKey,destinationId,mapKeys.get(clientUploadKey),isOverwrite); logger.debug("created "+workspaceUploader); saveWorkspaceUploaderStatus(workspaceUploader, UPLOAD_STATUS.WAIT, "Uploading "+fileName+" at 0%", request.getSession()); } } if (item.isFormField() && CURR_GROUP_ID.equals(item.getFieldName())){ scopeGroupId = Streams.asString(item.openStream()); logger.debug("currentGroupId passed as parameter = " + scopeGroupId); logger.debug("currentGroupId into PortalContext scope= " + PortalContext.getConfiguration().getCurrentScope(scopeGroupId)); } // if (item.isFormField() && CURR_USER_ID.equals(item.getFieldName())){ // currUserId = Streams.asString(item.openStream()); // logger.debug("currUserId passed as parameter = " + currUserId); // logger.debug("currUserinto PortalContext = " + PortalContext.getConfiguration().getCurrentUser(request)); // } //MUST BE THE LAST PARAMETER TRASMITTED if (UPLOAD_FORM_ELEMENT.equals(item.getFieldName())){ uploadItem = item; logger.debug("UPLOAD_FORM_ELEMENT OK "+uploadItem.getName() + " scopeGroupId="+scopeGroupId); // break; uploadData(user, scopeGroupId, request, response, uploadItem, destinationId, uploadType, listClientUploadKeys.get(uploadItemsCnt), isOverwrite); uploadItemsCnt++; } } } catch (FileUploadException e) { logger.error("Error processing request in upload servlet", e); sendError(response, "Internal error: Error during request processing"); return; } catch (Exception e) { logger.error("Error processing request in upload servlet", e); sendError(response, "Internal error: Error during request processing"); return; } } public File coyStreamToFile(InputStream in, String fileExtension) throws IOException{ File tempFile = File.createTempFile(UUID.randomUUID().toString(), fileExtension); tempFile.deleteOnExit(); FileOutputStream out = new FileOutputStream(tempFile); IOUtils.copy(in, out); return tempFile; } // public static InputStream clone(final InputStream inputStream) { // try { // inputStream.mark(0); // ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); // byte[] buffer = new byte[1024]; // int readLength = 0; // while ((readLength = inputStream.read(buffer)) != -1) { // outputStream.write(buffer, 0, readLength); // } // inputStream.reset(); // outputStream.flush(); // return new ByteArrayInputStream(outputStream.toByteArray()); // } // catch (Exception ex) { // ex.printStackTrace(); // } // return null; // } /** * Removes the listener if done. * * @param session the session * @param keys the keys */ private void removeListenersIfDone(HttpSession session, List keys){ for (String key : keys) { AbstractUploadProgressListener listener = getCurrentListener(session, key); if (listener != null) { logger.debug("Listener found"); if (listener.isCanceled() || listener.getPercentage() >= 100){ logger.debug("Listener isCanceled or 100%, removing"); removeCurrentListener(session, key); } }else logger.debug("Session id: "+session.getId() +" - "+key+" - Listener not found"); } } /** * Parses the json client upload keys. * * @param jsonClientUploadKeys the json client upload keys * @return the linked hash map * @throws FileUploadException the file upload exception */ @SuppressWarnings("rawtypes") private static LinkedHashMap parseJSONClientUploadKeys(final String jsonClientUploadKeys) throws FileUploadException{ JSONTokener tokener = new JSONTokener(jsonClientUploadKeys); JSONObject root; LinkedHashMap keyFiles = null; try { root = new JSONObject(tokener); JSONArray jsonArray = root.getJSONArray(JSON_CLIENT_KEYS); keyFiles = new LinkedHashMap(jsonArray.length()); logger.debug("jsonArray :"+jsonArray.toString()); for (int i=0; i