org.eclipse.winery.repository.rest.resources.entitytemplates.artifacttemplates.FilesResource.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.winery.repository.rest.resources.entitytemplates.artifacttemplates.FilesResource.java

Source

/*******************************************************************************
 * Copyright (c) 2012-2018 Contributors to the Eclipse Foundation
 *
 * See the NOTICE file(s) distributed with this work for additional
 * information regarding copyright ownership.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License 2.0 which is available at
 * http://www.eclipse.org/legal/epl-2.0, or the Apache Software License 2.0
 * which is available at https://www.apache.org/licenses/LICENSE-2.0.
 *
 * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
 *******************************************************************************/
package org.eclipse.winery.repository.rest.resources.entitytemplates.artifacttemplates;

import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.HeaderParam;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import javax.ws.rs.core.UriInfo;

import org.eclipse.winery.common.RepositoryFileReference;
import org.eclipse.winery.common.Util;
import org.eclipse.winery.common.ids.definitions.ArtifactTemplateId;
import org.eclipse.winery.repository.backend.BackendUtils;
import org.eclipse.winery.repository.backend.RepositoryFactory;
import org.eclipse.winery.repository.datatypes.ids.elements.DirectoryId;
import org.eclipse.winery.repository.rest.RestUtils;
import org.eclipse.winery.repository.rest.datatypes.FileMeta;
import org.eclipse.winery.repository.rest.resources.apiData.ArtifactResourceApiData;
import org.eclipse.winery.repository.rest.resources.apiData.ArtifactResourcesApiData;

import com.sun.jersey.core.header.FormDataContentDisposition;
import com.sun.jersey.multipart.FormDataBodyPart;
import com.sun.jersey.multipart.FormDataParam;
import io.swagger.annotations.ApiParam;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class FilesResource {

    private static final Logger LOGGER = LoggerFactory.getLogger(FilesResource.class);
    private final DirectoryId fileDir;
    private final FilesResource destinationDir;

    public FilesResource(DirectoryId fileDir, FilesResource destinationDir) {
        this.fileDir = fileDir;
        this.destinationDir = destinationDir;
    }

    public FilesResource(DirectoryId fileDir) {
        this(fileDir, null);
    }

    /**
     * Handles the upload of a <em>single</em> file. Adds the given file to the current artifact template.
     * <p>
     * If the file already exists, is it <em>overridden</em>
     *
     * @return JSON with data required by JQuery-File-Upload (see https://github.com/blueimp/jQuery-File-Upload/wiki/Setup)
     */
    @POST
    @Produces(MediaType.APPLICATION_JSON)
    @Consumes(MediaType.MULTIPART_FORM_DATA)
    public Response onPost(@FormDataParam("file") InputStream uploadedInputStream,
            @FormDataParam("file") FormDataContentDisposition fileDetail,
            @FormDataParam("file") FormDataBodyPart body, @Context UriInfo uriInfo) {
        // existence check not required as instantiation of the resource ensures that the object only exists if the resource exists
        FilesResource.LOGGER.debug("Beginning with file upload");

        String fileName = fileDetail.getFileName();
        if (StringUtils.isEmpty(fileName)) {
            return Response.status(Status.BAD_REQUEST).build();
        }
        RepositoryFileReference ref = this.fileName2fileRef(fileName, false);

        // TODO: instead of fixing the media type, we could overwrite the browser's mediatype by using some user configuration
        BufferedInputStream bis = new BufferedInputStream(uploadedInputStream);
        org.apache.tika.mime.MediaType mediaType = BackendUtils.getFixedMimeType(bis, fileName,
                org.apache.tika.mime.MediaType.parse(body.getMediaType().toString()));

        Response response = RestUtils.putContentToFile(ref, bis, mediaType);
        if (response.getStatus() == Status.INTERNAL_SERVER_ERROR.getStatusCode()) {
            return response;
        }

        try {
            BackendUtils.synchronizeReferences(RepositoryFactory.getRepository(),
                    (ArtifactTemplateId) fileDir.getParent());
        } catch (IOException e) {
            throw new WebApplicationException(e, Status.INTERNAL_SERVER_ERROR);
        }

        String URL = RestUtils.getAbsoluteURL(this.fileDir) + Util.URLencode(fileName);
        return Response.created(RestUtils.createURI(URL)).entity(this.getAllFileMetas()).build();
    }

    /**
     * Returns a list of file meta object
     */
    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public String getJSON() {
        String json = BackendUtils.Object2JSON(this.getAllFileMetas());
        String pathsJson = BackendUtils.Object2JSON(this.getAllFilePaths());
        json = "{\"files\":" + json + "," + "\"paths\":" + pathsJson + "}";
        return json;
    }

    private List<FileMeta> getAllFileMetas() {
        return RepositoryFactory.getRepository().getContainedFiles(this.fileDir).stream()
                .map(ref -> new FileMeta(ref)).collect(Collectors.toList());
    }

    private List<String> getAllFilePaths() {
        List<String> paths = new ArrayList<>();
        for (RepositoryFileReference ref : RepositoryFactory.getRepository().getContainedFiles(this.fileDir)) {
            if (ref.getSubDirectory().isPresent()) {
                paths.add(ref.getSubDirectory().get().toString());
            } else {
                paths.add("");
            }
        }
        return paths;
    }

    private RepositoryFileReference fileName2fileRef(String fileName, boolean fileNameEncoded) {
        String name = fileNameEncoded ? Util.URLdecode(fileName) : fileName;
        return new RepositoryFileReference(this.fileDir, name);
    }

    private RepositoryFileReference fileName2fileRef(String fileName, String path, boolean fileNameEncoded) {
        String name = fileNameEncoded ? Util.URLdecode(fileName) : fileName;
        return new RepositoryFileReference(this.fileDir, Paths.get(path), name);
    }

    @GET
    @Path("/{fileName}")
    public Response getFile(@PathParam("fileName") String fileName,
            @HeaderParam("If-Modified-Since") String modified, @QueryParam("path") String path) {
        path = Objects.isNull(path) ? "" : path;
        RepositoryFileReference ref = this.fileName2fileRef(fileName, path, true);
        return RestUtils.returnRepoPath(ref, modified);
    }

    @DELETE
    @Path("/{fileName}")
    public Response deleteFile(@PathParam("fileName") String fileName, @QueryParam("path") String path) {
        path = Objects.isNull(path) ? "" : path;
        RepositoryFileReference ref = this.fileName2fileRef(fileName, path, true);
        return RestUtils.delete(ref);
    }

    @POST
    @Path("/{fileName}")
    @Consumes(MediaType.APPLICATION_JSON)
    public Response postFile(@PathParam("fileName") String fileName, ArtifactResourceApiData data) {
        if (StringUtils.isEmpty(fileName)) {
            return Response.status(Status.BAD_REQUEST).build();
        }
        RepositoryFileReference ref = this.fileName2fileRef(fileName, data.subDirectory, false);
        return RestUtils.putContentToFile(ref, data.content, MediaType.TEXT_PLAIN_TYPE);
    }

    @PUT
    @Path("/{fileName}")
    @Consumes(MediaType.APPLICATION_JSON)
    public Response putFile(@PathParam("fileName") String fileName, ArtifactResourceApiData data) {
        if (StringUtils.isEmpty(fileName)) {
            return Response.status(Status.BAD_REQUEST).build();
        }
        RepositoryFileReference ref = this.fileName2fileRef(fileName, data.subDirectory, false);
        return RestUtils.putContentToFile(ref, data.content, MediaType.TEXT_PLAIN_TYPE);
    }

    @POST
    @Consumes(MediaType.APPLICATION_JSON)
    public Response copySourceToFiles(@ApiParam(value = "if data contains a non-empty array than only the files"
            + " whose names are included are copied ", required = true) ArtifactResourcesApiData data) {
        if (Objects.isNull(this.destinationDir)) {
            return Response.status(Status.BAD_REQUEST).build();
        }
        List<String> artifactList = data.getArtifactNames();
        for (RepositoryFileReference ref : RepositoryFactory.getRepository().getContainedFiles(this.fileDir)) {
            if (artifactList == null || artifactList.contains(ref.getFileName())) {
                try (InputStream inputStream = RepositoryFactory.getRepository().newInputStream(ref)) {
                    String fileName = ref.getFileName();
                    String subDirectory = ref.getSubDirectory().map(s -> s.toString()).orElse("");
                    this.destinationDir.putFile(fileName, subDirectory, inputStream);
                } catch (IOException e) {
                    LOGGER.debug("The artifact source " + ref.getFileName()
                            + " could not be copied to the files directory.", e);
                    return Response.status(Status.INTERNAL_SERVER_ERROR).build();
                }
            }
        }
        return Response.status(Status.CREATED).build();
    }

    private Response putFile(String fileName, String subDirectory, InputStream content) {
        if (StringUtils.isEmpty(fileName)) {
            return Response.status(Status.BAD_REQUEST).build();
        }
        RepositoryFileReference ref = this.fileName2fileRef(fileName, subDirectory, false);
        return RestUtils.putContentToFile(ref, content, MediaType.TEXT_PLAIN_TYPE);
    }
}