org.structr.web.servlet.DeploymentServlet.java Source code

Java tutorial

Introduction

Here is the source code for org.structr.web.servlet.DeploymentServlet.java

Source

/**
 * Copyright (C) 2010-2018 Structr GmbH
 *
 * This file is part of Structr <http://structr.org>.
 *
 * Structr is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * Structr 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 Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with Structr.  If not, see <http://www.gnu.org/licenses/>.
 */
package org.structr.web.servlet;

import com.google.common.io.Files;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.structr.api.config.Settings;
import org.structr.common.AccessMode;
import org.structr.common.SecurityContext;
import org.structr.common.error.FrameworkException;
import org.structr.core.app.StructrApp;
import org.structr.core.auth.exception.AuthenticationException;
import org.structr.core.graph.Tx;
import org.structr.rest.service.HttpServiceServlet;
import org.structr.rest.service.StructrHttpServiceConfig;
import org.structr.schema.SchemaHelper;
import org.structr.web.auth.UiAuthenticator;
import org.structr.web.maintenance.DeployCommand;

//~--- classes ----------------------------------------------------------------
/**
 * Endpoint for deployment file upload
 */
public class DeploymentServlet extends HttpServlet implements HttpServiceServlet {

    private static final Logger logger = LoggerFactory.getLogger(DeploymentServlet.class.getName());

    private static final int MEGABYTE = 1024 * 1024;
    private static final int MEMORY_THRESHOLD = 10 * MEGABYTE; // above 10 MB, files are stored on disk

    // non-static fields
    private ServletFileUpload uploader = null;
    private File filesDir = null;
    private final StructrHttpServiceConfig config = new StructrHttpServiceConfig();

    public DeploymentServlet() {
    }

    //~--- methods --------------------------------------------------------
    @Override
    public StructrHttpServiceConfig getConfig() {
        return config;
    }

    @Override
    public String getModuleName() {
        return "deployment";
    }

    @Override
    public void init() {

        try (final Tx tx = StructrApp.getInstance().tx()) {
            DiskFileItemFactory fileFactory = new DiskFileItemFactory();
            fileFactory.setSizeThreshold(MEMORY_THRESHOLD);

            filesDir = new File(Settings.TmpPath.getValue()); // new File(Services.getInstance().getTmpPath());
            if (!filesDir.exists()) {

                filesDir.mkdir();
            }

            fileFactory.setRepository(filesDir);
            uploader = new ServletFileUpload(fileFactory);

            tx.success();

        } catch (FrameworkException t) {

            logger.warn("", t);
        }
    }

    @Override
    public void destroy() {
    }

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

        try (final Tx tx = StructrApp.getInstance().tx()) {

            if (!ServletFileUpload.isMultipartContent(request)) {
                response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
                response.getOutputStream()
                        .write("ERROR (400): Request does not contain multipart content.\n".getBytes("UTF-8"));
                return;
            }

            final SecurityContext securityContext;
            try {
                securityContext = getConfig().getAuthenticator().initializeAndExamineRequest(request, response);

            } catch (AuthenticationException ae) {

                response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
                response.getOutputStream().write("ERROR (401): Invalid user or password.\n".getBytes("UTF-8"));
                return;
            }

            if (securityContext.getUser(false) == null && !Settings.DeploymentAllowAnonymousUploads.getValue()) {
                response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
                response.getOutputStream().write("ERROR (401): Anonymous uploads forbidden.\n".getBytes("UTF-8"));
                return;
            }

            // Ensure access mode is frontend
            securityContext.setAccessMode(AccessMode.Frontend);

            request.setCharacterEncoding("UTF-8");

            // Important: Set character encoding before calling response.getWriter() !!, see Servlet Spec 5.4
            response.setCharacterEncoding("UTF-8");

            // don't continue on redirects
            if (response.getStatus() == 302) {
                return;
            }

            final String pathInfo = request.getPathInfo();
            String type = null;

            if (StringUtils.isNotBlank(pathInfo)) {

                type = SchemaHelper.normalizeEntityName(StringUtils.stripStart(pathInfo.trim(), "/"));

            }

            uploader.setFileSizeMax(MEGABYTE * Settings.DeploymentMaxFileSize.getValue());
            uploader.setSizeMax(MEGABYTE * Settings.DeploymentMaxRequestSize.getValue());

            response.setContentType("text/html");

            final List<FileItem> fileItemsList = uploader.parseRequest(request);
            final Iterator<FileItem> fileItemsIterator = fileItemsList.iterator();
            final Map<String, Object> params = new HashMap<>();

            while (fileItemsIterator.hasNext()) {

                final FileItem item = fileItemsIterator.next();

                try {
                    final String directoryPath = "/tmp/" + UUID.randomUUID();
                    final String filePath = directoryPath + ".zip";

                    File file = new File(filePath);
                    Files.write(IOUtils.toByteArray(item.getInputStream()), file);

                    unzip(file, directoryPath);

                    DeployCommand deployCommand = StructrApp.getInstance(securityContext)
                            .command(DeployCommand.class);

                    final Map<String, Object> attributes = new HashMap<>();
                    attributes.put("source",
                            directoryPath + "/" + StringUtils.substringBeforeLast(item.getName(), "."));

                    deployCommand.execute(attributes);

                    file.deleteOnExit();
                    File dir = new File(directoryPath);

                    dir.deleteOnExit();

                } catch (IOException ex) {
                    logger.warn("Could not upload file", ex);
                }

            }

            tx.success();

        } catch (FrameworkException | IOException | FileUploadException t) {

            logger.error("Exception while processing request", t);
            UiAuthenticator.writeInternalServerError(response);
        }
    }

    /**
     * Unzip given file to given output directory.
     *
     * @param file
     * @param outputDir
     * @throws IOException
     */
    private void unzip(final File file, final String outputDir) throws IOException {

        try (final ZipFile zipFile = new ZipFile(file)) {

            final Enumeration<? extends ZipEntry> entries = zipFile.entries();

            while (entries.hasMoreElements()) {

                final ZipEntry entry = entries.nextElement();
                final File targetFile = new File(outputDir, entry.getName());

                if (entry.isDirectory()) {

                    targetFile.mkdirs();

                } else {

                    targetFile.getParentFile().mkdirs();
                    InputStream in = zipFile.getInputStream(entry);

                    try (OutputStream out = new FileOutputStream(targetFile)) {

                        IOUtils.copy(in, out);
                        IOUtils.closeQuietly(in);
                    }
                }
            }
        }
    }

}