org.codice.ddf.admin.application.rest.ApplicationUploadEndpoint.java Source code

Java tutorial

Introduction

Here is the source code for org.codice.ddf.admin.application.rest.ApplicationUploadEndpoint.java

Source

/**
 * Copyright (c) Codice Foundation
 * <p>
 * This is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser
 * General Public License as published by the Free Software Foundation, either version 3 of the
 * License, or any later version.
 * <p>
 * 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
 * Lesser General Public License for more details. A copy of the GNU Lesser General Public License
 * is distributed along with this program and can be found at
 * <http://www.gnu.org/licenses/lgpl.html>.
 */
package org.codice.ddf.admin.application.rest;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;

import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.cxf.jaxrs.ext.multipart.Attachment;
import org.apache.cxf.jaxrs.ext.multipart.MultipartBody;
import org.codice.ddf.admin.application.service.Application;
import org.codice.ddf.admin.application.service.ApplicationService;
import org.codice.ddf.admin.application.service.ApplicationServiceException;
import org.codice.ddf.admin.application.service.impl.ApplicationFileInstaller;
import org.codice.ddf.admin.application.service.impl.ZipFileApplicationDetails;
import org.eclipse.jetty.http.HttpStatus;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * The REST Endpoint for the Application Service that provides an endpoint to upload new/upgraded applications
 * to the system.
 *
 */
@Path("/")
public class ApplicationUploadEndpoint {
    private static final String FILENAME_CONTENT_DISPOSITION_PARAMETER_NAME = "filename";

    private static final String DEFAULT_FILE_NAME = "file.jar";

    private static String defaultFileLocation = "data/installer/uploads/";

    private static final String JAR_EXT = "jar";

    private static final String KAR_EXT = "kar";

    private final ApplicationService appService;

    private static final Logger LOGGER = LoggerFactory.getLogger(ApplicationUploadEndpoint.class);

    public ApplicationUploadEndpoint(ApplicationService appService) {
        this.appService = appService;
    }

    @POST
    @Path("/update")
    @Produces("application/json")
    public Response update(MultipartBody multipartBody, @Context UriInfo requestUriInfo) {
        LOGGER.trace("ENTERING: update");

        Response response = null;

        List<Attachment> attachmentList = multipartBody.getAllAttachments();
        File newFile = null;
        for (Attachment attachment : attachmentList) {
            newFile = createFileFromAttachement(attachment, response);
        }

        if (response == null) {
            try {
                if (newFile != null) {
                    ZipFileApplicationDetails appDetails = ApplicationFileInstaller.getAppDetails(newFile);

                    if (appDetails != null) {
                        // lets get the existing app if it exists.
                        Application existingApplication = appService.getApplication(appDetails.getName());
                        boolean wasExistingAppStarted = false; // assume false until proved
                        // otherwise.
                        if (existingApplication != null) {
                            wasExistingAppStarted = appService.isApplicationStarted(existingApplication);
                            appService.removeApplication(existingApplication);
                        }
                        appService.addApplication(newFile.toURI());

                        // if application was started before it was removed, lets try and start it.
                        if (wasExistingAppStarted) {
                            appService.startApplication(appDetails.getName());
                        }
                    } else {
                        throw new ApplicationServiceException(
                                "No Application details could be extracted from the provided file.");
                    }
                } else {
                    throw new ApplicationServiceException("No file attachment provided.");
                }

                // we need to output valid JSON to the client so fileupload can correctly call
                // done/fail callbacks correctly.
                Response.ResponseBuilder responseBuilder = Response.ok("{\"status\":\"success\"}")
                        .type("application/json");
                response = responseBuilder.build();
            } catch (ApplicationServiceException e) {
                LOGGER.error("Unable to update an application on the server: {}", newFile, e);
                Response.ResponseBuilder responseBuilder = Response.serverError();
                response = responseBuilder.build();
            }
        }

        LOGGER.trace("EXITING: update");

        return response;
    }

    @POST
    @Path("/")
    public Response create(MultipartBody multipartBody, @Context UriInfo requestUriInfo) {
        LOGGER.trace("ENTERING: create");

        Response response = null;

        List<Attachment> attachmentList = multipartBody.getAllAttachments();
        File newFile = null;
        for (Attachment attachment : attachmentList) {
            newFile = createFileFromAttachement(attachment, response);
        }

        if (response == null) {
            try {
                if (newFile != null) {
                    appService.addApplication(newFile.toURI());
                }

                Response.ResponseBuilder responseBuilder = Response.ok();
                response = responseBuilder.build();
            } catch (ApplicationServiceException e) {
                LOGGER.error("Unable to add the application to the server: " + newFile, e);
                Response.ResponseBuilder responseBuilder = Response.serverError();
                response = responseBuilder.build();
            }
        }

        LOGGER.trace("EXITING: create");

        return response;
    }

    /**
     * Copies the attachment to a system file location. Once copied, a file is returned of the
     * copied file.
     *
     * @param attachment
     *            the attachment to copy and extract.
     * @param response
     *            the response object to manipulate if anything goes wrong.
     * @return The file of the copied attachment.
     */
    private File createFileFromAttachement(Attachment attachment, Response response) {
        InputStream inputStream = null;
        String filename = null;
        File newFile = null;
        if (attachment.getContentDisposition() != null) {
            filename = attachment.getContentDisposition().getParameter(FILENAME_CONTENT_DISPOSITION_PARAMETER_NAME);
        }

        if (StringUtils.isEmpty(filename)) {
            LOGGER.debug("Filename not found, using default.");
            filename = DEFAULT_FILE_NAME;
        } else {
            filename = FilenameUtils.getName(filename);
            LOGGER.debug("Filename: {}", filename);
        }

        try {
            inputStream = attachment.getDataHandler().getInputStream();
            if (inputStream != null && inputStream.available() == 0) {
                inputStream.reset();
            }
        } catch (IOException e) {
            LOGGER.warn("IOException reading stream from file attachment in multipart body", e);
            IOUtils.closeQuietly(inputStream);
        }

        if (filename.endsWith(JAR_EXT) || filename.endsWith(KAR_EXT)) {
            if (inputStream != null) {
                try {
                    File uploadDir = new File(defaultFileLocation);
                    if (!uploadDir.exists()) {
                        if (uploadDir.mkdirs()) {
                            LOGGER.warn("Unable to make directory");
                        }
                    }

                    newFile = new File(uploadDir, filename);

                    FileUtils.copyInputStreamToFile(inputStream, newFile);

                } catch (IOException e) {
                    LOGGER.warn("Unable to write file.", e);
                    newFile = null;
                } finally {
                    IOUtils.closeQuietly(inputStream);
                }
            } else {
                LOGGER.debug("No file attachment found");
            }
        } else {
            LOGGER.debug("Wrong file type.");
            Response.ResponseBuilder responseBuilder = Response.serverError();
            responseBuilder.status(HttpStatus.UNSUPPORTED_MEDIA_TYPE_415);
            IOUtils.closeQuietly(inputStream);
        }
        return newFile;
    }

    /**
     * Setter method for DEFAULT_FILE_LOCATION for testing purposes
     *
     * @param fileLocation
     *            the desired fileLocation
     */
    void setDefaultFileLocation(String fileLocation) {
        defaultFileLocation = fileLocation;
    }
}