org.jahia.ajax.gwt.content.server.GWTFileManagerUploadServlet.java Source code

Java tutorial

Introduction

Here is the source code for org.jahia.ajax.gwt.content.server.GWTFileManagerUploadServlet.java

Source

/**
 * ==========================================================================================
 * =                   JAHIA'S DUAL LICENSING - IMPORTANT INFORMATION                       =
 * ==========================================================================================
 *
 *                                 http://www.jahia.com
 *
 *     Copyright (C) 2002-2017 Jahia Solutions Group SA. All rights reserved.
 *
 *     THIS FILE IS AVAILABLE UNDER TWO DIFFERENT LICENSES:
 *     1/GPL OR 2/JSEL
 *
 *     1/ GPL
 *     ==================================================================================
 *
 *     IF YOU DECIDE TO CHOOSE THE GPL LICENSE, YOU MUST COMPLY WITH THE FOLLOWING TERMS:
 *
 *     This program is free software: you can redistribute it and/or modify
 *     it under the terms of the GNU General Public License as published by
 *     the Free Software Foundation, either version 3 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 General Public License for more details.
 *
 *     You should have received a copy of the GNU General Public License
 *     along with this program. If not, see <http://www.gnu.org/licenses/>.
 *
 *
 *     2/ JSEL - Commercial and Supported Versions of the program
 *     ===================================================================================
 *
 *     IF YOU DECIDE TO CHOOSE THE JSEL LICENSE, YOU MUST COMPLY WITH THE FOLLOWING TERMS:
 *
 *     Alternatively, commercial and supported versions of the program - also known as
 *     Enterprise Distributions - must be used in accordance with the terms and conditions
 *     contained in a separate written agreement between you and Jahia Solutions Group SA.
 *
 *     If you are unsure which license is appropriate for your use,
 *     please contact the sales department at sales@jahia.com.
 */
package org.jahia.ajax.gwt.content.server;

import com.google.gwt.safehtml.shared.UriUtils;
import org.apache.commons.fileupload.*;
import org.apache.commons.fileupload.FileUploadBase.FileSizeLimitExceededException;
import org.apache.commons.fileupload.FileUploadBase.FileUploadIOException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.fileupload.util.LimitedInputStream;
import org.apache.commons.fileupload.util.Streams;
import org.apache.commons.io.IOUtils;
import org.jahia.ajax.gwt.client.service.GWTJahiaServiceException;
import org.jahia.ajax.gwt.helper.VersioningHelper;
import org.jahia.ajax.gwt.helper.ZipHelper;
import org.jahia.api.Constants;
import org.jahia.bin.SessionNamedDataStorage;
import org.jahia.exceptions.JahiaRuntimeException;
import org.jahia.services.content.JCRContentUtils;
import org.jahia.services.content.JCRNodeWrapper;
import org.jahia.services.content.JCRSessionFactory;
import org.jahia.services.content.JCRVersionService;
import org.jahia.services.usermanager.JahiaUser;
import org.jahia.settings.SettingsBean;
import org.jahia.utils.i18n.Messages;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;

import javax.jcr.RepositoryException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.*;

/**
 * File upload servlet to handle requests from GWT upload form.
 *
 * @author rfelden
 * @version 2 avr. 2008 - 16:51:39
 */
public class GWTFileManagerUploadServlet extends HttpServlet {

    private static final int OK = 0;
    private static final int EXISTS = 1;
    private static final int READONLY = 2;
    private static final int BAD_LOCATION = 3;
    private static final int UNKNOWN_ERROR = 9;

    private static final Logger logger = LoggerFactory.getLogger(GWTFileManagerUploadServlet.class);
    private static final long serialVersionUID = 1048509772346464862L;

    private volatile SessionNamedDataStorage<UploadedPendingFile> fileStorage;

    private static long getContentLength(FileItemHeaders pHeaders) {
        try {
            return Long.parseLong(pHeaders.getHeader(FileUploadBase.CONTENT_LENGTH));
        } catch (Exception e) {
            return -1;
        }
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        FileItemFactory factory = new DiskFileItemFactory();
        ServletFileUpload upload = new ServletFileUpload(factory);
        SettingsBean settingsBean = SettingsBean.getInstance();
        final long fileSizeLimit = settingsBean.getJahiaFileUploadMaxSize();
        upload.setHeaderEncoding("UTF-8");
        Map<String, FileItem> uploads = new HashMap<String, FileItem>();
        String location = null;
        String type = null;
        boolean unzip = false;
        response.setContentType("text/plain; charset=" + settingsBean.getCharacterEncoding());
        final PrintWriter printWriter = response.getWriter();
        try {
            FileItemIterator itemIterator = upload.getItemIterator(request);
            FileSizeLimitExceededException sizeLimitExceededException = null;
            while (itemIterator.hasNext()) {
                final FileItemStream item = itemIterator.next();
                if (sizeLimitExceededException != null) {
                    continue;
                }
                FileItem fileItem = factory.createItem(item.getFieldName(), item.getContentType(),
                        item.isFormField(), item.getName());
                long contentLength = getContentLength(item.getHeaders());

                // If we have a content length in the header we can use it
                if (fileSizeLimit > 0 && contentLength != -1L && contentLength > fileSizeLimit) {
                    throw new FileSizeLimitExceededException("The field " + item.getFieldName()
                            + " exceeds its maximum permitted size of " + fileSizeLimit + " bytes.", contentLength,
                            fileSizeLimit);
                }
                InputStream itemStream = item.openStream();

                InputStream limitedInputStream = null;
                try {
                    limitedInputStream = fileSizeLimit > 0 ? new LimitedInputStream(itemStream, fileSizeLimit) {

                        @Override
                        protected void raiseError(long pSizeMax, long pCount) throws IOException {
                            throw new FileUploadIOException(new FileSizeLimitExceededException(
                                    "The field " + item.getFieldName() + " exceeds its maximum permitted size of "
                                            + fileSizeLimit + " bytes.",
                                    pCount, pSizeMax));
                        }
                    } : itemStream;

                    Streams.copy(limitedInputStream, fileItem.getOutputStream(), true);
                } catch (FileUploadIOException e) {
                    if (e.getCause() instanceof FileSizeLimitExceededException) {
                        if (sizeLimitExceededException == null) {
                            sizeLimitExceededException = (FileSizeLimitExceededException) e.getCause();
                        }
                    } else {
                        throw e;
                    }
                } finally {
                    IOUtils.closeQuietly(limitedInputStream);
                }

                if ("unzip".equals(fileItem.getFieldName())) {
                    unzip = true;
                } else if ("uploadLocation".equals(fileItem.getFieldName())) {
                    location = fileItem.getString("UTF-8");
                } else if ("asyncupload".equals(fileItem.getFieldName())) {
                    String name = fileItem.getName();
                    if (name.trim().length() > 0) {
                        uploads.put(extractFileName(name, uploads), fileItem);
                    }
                    type = "async";
                } else if (!fileItem.isFormField() && fileItem.getFieldName().startsWith("uploadedFile")) {
                    String name = fileItem.getName();
                    if (name.trim().length() > 0) {
                        uploads.put(extractFileName(name, uploads), fileItem);
                    }
                    type = "sync";
                }
            }
            if (sizeLimitExceededException != null) {
                throw sizeLimitExceededException;
            }
        } catch (FileUploadBase.FileSizeLimitExceededException e) {
            printWriter.write("UPLOAD-SIZE-ISSUE: " + getSizeLimitErrorMessage(fileSizeLimit, e, request) + "\n");
            return;
        } catch (FileUploadIOException e) {
            if (e.getCause() != null && (e.getCause() instanceof FileSizeLimitExceededException)) {
                printWriter.write("UPLOAD-SIZE-ISSUE: " + getSizeLimitErrorMessage(fileSizeLimit,
                        (FileSizeLimitExceededException) e.getCause(), request) + "\n");
            } else {
                logger.error("UPLOAD-ISSUE", e);
                printWriter.write("UPLOAD-ISSUE: " + e.getLocalizedMessage() + "\n");
            }
            return;
        } catch (FileUploadException e) {
            logger.error("UPLOAD-ISSUE", e);
            printWriter.write("UPLOAD-ISSUE: " + e.getLocalizedMessage() + "\n");
            return;
        }

        if (type == null || type.equals("sync")) {
            response.setContentType("text/plain");

            final JahiaUser user = (JahiaUser) request.getSession().getAttribute(Constants.SESSION_USER);

            final List<String> pathsToUnzip = new ArrayList<String>();
            for (String fileName : uploads.keySet()) {
                final FileItem fileItem = uploads.get(fileName);
                try {
                    StringBuilder name = new StringBuilder(fileName);
                    final int saveResult = saveToJcr(user, fileItem, location, name);
                    switch (saveResult) {
                    case OK:
                        if (unzip && fileName.toLowerCase().endsWith(".zip")) {
                            pathsToUnzip.add(
                                    new StringBuilder(location).append("/").append(name.toString()).toString());
                        }
                        printWriter.write("OK: " + UriUtils.encode(name.toString()) + "\n");
                        break;
                    case EXISTS:
                        storeUploadedFile(request.getSession().getId(), fileItem);
                        printWriter.write("EXISTS: " + UriUtils.encode(fileItem.getFieldName()) + " "
                                + UriUtils.encode(fileItem.getName()) + " " + UriUtils.encode(fileName) + "\n");
                        break;
                    case READONLY:
                        printWriter.write("READONLY: " + UriUtils.encode(fileItem.getFieldName()) + "\n");
                        break;
                    default:
                        printWriter.write("UPLOAD-FAILED: " + UriUtils.encode(fileItem.getFieldName()) + "\n");
                        break;
                    }
                } catch (IOException e) {
                    logger.error("Upload failed for file \n", e);
                } finally {
                    fileItem.delete();
                }
            }

            // direct blocking unzip
            if (unzip && pathsToUnzip.size() > 0) {
                try {
                    ZipHelper zip = ZipHelper.getInstance();
                    //todo : in which workspace do we upload ?
                    zip.unzip(pathsToUnzip, true, JCRSessionFactory.getInstance().getCurrentUserSession(),
                            (Locale) request.getSession().getAttribute(Constants.SESSION_UI_LOCALE));
                } catch (RepositoryException e) {
                    logger.error("Auto-unzipping failed", e);
                } catch (GWTJahiaServiceException e) {
                    logger.error("Auto-unzipping failed", e);
                }
            }
        } else {
            response.setContentType("text/html");
            for (FileItem fileItem : uploads.values()) {
                storeUploadedFile(request.getSession().getId(), fileItem);
                printWriter.write("<html><body>");
                printWriter.write("<div id=\"uploaded\" key=\"" + fileItem.getName() + "\" name=\""
                        + fileItem.getName() + "\"></div>\n");
                printWriter.write("</body></html>");
            }
        }
    }

    private void storeUploadedFile(String sessionID, final FileItem fileItem) {
        try {
            final InputStream contentStream = new BufferedInputStream(fileItem.getInputStream());
            try {
                getFileStorage().put(sessionID, fileItem.getName(), new UploadedPendingFile() {

                    @Override
                    public String getContentType() {
                        return fileItem.getContentType();
                    }

                    @Override
                    public InputStream getContentStream() {
                        return contentStream;
                    }

                    @Override
                    public void close() {
                    }
                });
            } finally {
                contentStream.close();
            }
        } catch (IOException e) {
            throw new JahiaRuntimeException(e);
        }
    }

    private String getSizeLimitErrorMessage(final long fileSizeLimit, FileSizeLimitExceededException e,
            HttpServletRequest request) {
        Locale locale = (Locale) request.getSession().getAttribute(Constants.SESSION_UI_LOCALE);
        if (locale == null) {
            locale = (Locale) request.getSession().getAttribute(Constants.SESSION_LOCALE);
        }
        if (logger.isDebugEnabled()) {
            logger.warn("File upload exceeding limit of " + fileSizeLimit + " bytes", e);
        } else {
            logger.warn("File upload exceeding limit of {} bytes", fileSizeLimit);
        }
        return Messages.getInternalWithArguments("fileSizeError.label", "File upload exceeding limit of {0} bytes",
                locale, fileSizeLimit);
    }

    private String extractFileName(String rawFileName, Map<String, FileItem> uploads) {

        String basename;
        if (rawFileName.indexOf("\\") >= 0) {
            basename = rawFileName.substring(rawFileName.lastIndexOf("\\") + 1);
        } else if (rawFileName.indexOf("/") >= 0) {
            basename = rawFileName.substring(rawFileName.lastIndexOf("/") + 1);
        } else {
            basename = rawFileName;
        }

        int i = 1;
        String name = basename;
        int dot = basename.lastIndexOf('.');
        String ext = "";
        if (dot > 0) {
            ext = basename.substring(dot);
            basename = basename.substring(0, dot);
        }
        int und = basename.lastIndexOf('-');
        if (und > -1 && basename.substring(und + 1).matches("[0-9]+")) {
            basename = basename.substring(0, und);
        }

        do {
            if (!uploads.containsKey(name)) {
                break;
            } else {
                name = basename + "-" + (i++) + ext;
            }
        } while (true);

        return name;
    }

    private int saveToJcr(JahiaUser user, FileItem item, String location, StringBuilder name) throws IOException {

        String filename = name.toString();
        if (logger.isDebugEnabled()) {
            logger.debug("item : " + item);
            logger.debug("destination : " + location);
            logger.debug("filename : " + filename);
            logger.debug("size : " + item.getSize());
        }
        if (item == null || location == null || filename == null) {
            return UNKNOWN_ERROR;
        }

        JCRNodeWrapper locationFolder;
        try {
            locationFolder = JCRSessionFactory.getInstance().getCurrentUserSession().getNode(location);
        } catch (RepositoryException e) {
            logger.error(e.toString(), e);
            return BAD_LOCATION;
        }

        if (!locationFolder.hasPermission("jcr:addChildNodes") || locationFolder.isLocked()) {
            logger.debug("destination is not writable for user " + user.getName());
            return READONLY;
        }
        try {
            if (locationFolder.hasNode(JCRContentUtils.escapeLocalNodeName(filename))) {
                return EXISTS;
            }
            InputStream is = item.getInputStream();
            try {
                boolean versioningAvailable = false;
                if (locationFolder.getProvider().isVersioningAvailable()) {
                    versioningAvailable = true;
                }
                if (versioningAvailable) {
                    locationFolder.getSession().checkout(locationFolder);
                }
                JCRNodeWrapper node = locationFolder.uploadFile(filename, is,
                        JCRContentUtils.getMimeType(filename, item.getContentType()));
                node.getSession().save();
                if (!node.getName().equals(filename)) {
                    name.delete(0, name.length());
                    name.append(node.getName());
                }
                // Handle potential move of the node after save
                node = node.getSession().getNodeByIdentifier(node.getIdentifier());
                if (node.getProvider().isVersioningAvailable()) {
                    node.checkpoint();
                    JCRVersionService.getInstance().addVersionLabel(node, VersioningHelper
                            .getVersionLabel(node.getProperty("jcr:created").getDate().getTime().getTime()));
                }
            } finally {
                IOUtils.closeQuietly(is);
            }
            locationFolder.saveSession();
        } catch (RepositoryException e) {
            logger.error("exception ", e);
            return UNKNOWN_ERROR;
        }
        return OK;
    }

    @SuppressWarnings("unchecked")
    private SessionNamedDataStorage<UploadedPendingFile> getFileStorage() {
        if (fileStorage != null) {
            return fileStorage;
        }
        synchronized (this) {
            if (fileStorage != null) {
                return fileStorage;
            }
            ApplicationContext context = WebApplicationContextUtils
                    .getRequiredWebApplicationContext(getServletContext());
            fileStorage = (SessionNamedDataStorage<UploadedPendingFile>) context
                    .getBean("UploadedPendingFileStorage");
            return fileStorage;
        }
    }
}