blob: 504962476ac2bb29c37d8bb2c041e90c85cba523 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2020 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 v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* SPDX-License-Identifier: EPL-2.0
*******************************************************************************/
package org.eclipse.mdm.businessobjects.boundary;
import static org.eclipse.mdm.businessobjects.boundary.ResourceConstants.REQUESTPARAM_ID;
import static org.eclipse.mdm.businessobjects.boundary.ResourceConstants.REQUESTPARAM_REMOTEPATH;
import static org.eclipse.mdm.businessobjects.boundary.ResourceConstants.REQUESTPARAM_SOURCENAME;
import static org.eclipse.mdm.businessobjects.service.EntityService.V;
import java.io.InputStream;
import javax.ejb.EJB;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import org.eclipse.mdm.api.base.model.Environment;
import org.eclipse.mdm.api.base.model.FileLink;
import org.eclipse.mdm.api.base.model.FilesAttachable;
import org.eclipse.mdm.api.base.model.MimeType;
import org.eclipse.mdm.businessobjects.control.FileLinkActivity;
import org.eclipse.mdm.businessobjects.entity.FileSize;
import org.eclipse.mdm.businessobjects.entity.MDMEntityResponse;
import org.eclipse.mdm.businessobjects.entity.MDMFileLink;
import org.eclipse.mdm.businessobjects.service.EntityService;
import org.eclipse.mdm.businessobjects.utils.Serializer;
import org.eclipse.mdm.businessobjects.utils.ServiceUtils;
import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
import org.glassfish.jersey.media.multipart.FormDataParam;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.ArraySchema;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.vavr.Tuple;
/**
* Subresource for {@link FilesAttachable}s.
*
* @author Johannes Stamm, peak-Solution GmbH
*
*/
public class FilesAttachableSubresource {
@EJB
private EntityService entityService;
@EJB
private FileLinkActivity fileLinkActivity;
private Class<? extends FilesAttachable> fileAttachableClass;
/**
* Set the Entity class of the parent resource. This method has to be called
* right after the resource was initialized by the container. The entity class
* is used to distinguish the type of the parent resource.
*
* This method is package-private to workaround an issue in WELD complaining
* about: Parameter 1 of type ... is not resolvable to a concrete type.
*
* @param fileAttachableClass the Entity class of the parent resource
*/
void setEntityClass(Class<? extends FilesAttachable> fileAttachableClass) {
this.fileAttachableClass = fileAttachableClass;
}
/**
* Stream the contents of a file link.
*
* @param sourceName name of the source (MDM {@link Environment} name)
* @param id The identifier of the {@link FilesAttachable} which
* contains the {@link FileLink}
* @param remotePath The remote path of the {@link FileLink} to identify, which
* {@link FileLink}'s content is requests.
* @return The content of the file as {@link javax.ws.rs.core.StreamingOutput}.
* The response also has the MimeType set according to
* {@link FileLink#getMimeType()}.
*/
@GET
@Operation(summary = "Stream the contents of a file link", responses = {
@ApiResponse(description = "The content of the file link as a stream. MimeType is set to that of the file link.", content = @Content(schema = @Schema(implementation = MDMEntityResponse.class))),
@ApiResponse(responseCode = "400", description = "Invalid ID or remote path supplied") })
@Path("/{" + REQUESTPARAM_REMOTEPATH + "}")
public Response streamFileLink(
@Parameter(description = "Name of the MDM datasource", required = true) @PathParam(REQUESTPARAM_SOURCENAME) String sourceName,
@Parameter(description = "ID of the Test containing the file link", required = true) @PathParam(REQUESTPARAM_ID) String id,
@Parameter(description = "The remote path of the file link whose content is to be retrieved", required = true) @PathParam(REQUESTPARAM_REMOTEPATH) String remotePath) {
return entityService.find(V(sourceName), fileAttachableClass, V(id))
.map(filesAttachable -> Tuple.of(filesAttachable,
fileLinkActivity.findFileLinkAtFileAttachable(remotePath, filesAttachable)))
.map(tuple -> Tuple.of(fileLinkActivity.toStreamingOutput(sourceName, tuple._1, tuple._2),
tuple._2.getMimeType().toString()))
.map(tuple -> Response.ok(tuple._1, tuple._2).build()).recover(ServiceUtils.ERROR_RESPONSE_SUPPLIER)
.getOrElse(ServiceUtils.SERVER_ERROR_RESPONSE);
}
/**
* Deletes attached file from {@link FilesAttachable}.
*
* @param sourceName name of the source (MDM {@link Environment} name)
* @param id The identifier of the {@link FilesAttachable} which
* contains the {@link FileLink}
* @param remotePath The remote path of the {@link FileLink} to delete.
* @return
*/
@DELETE
@Operation(summary = "Deletes an attached file.", responses = {
@ApiResponse(description = "The deleted file link", content = @Content(schema = @Schema(implementation = MDMFileLink.class))),
@ApiResponse(responseCode = "400", description = "Error") })
@Produces(MediaType.APPLICATION_JSON)
@Path("/{" + REQUESTPARAM_REMOTEPATH + "}")
public Response deleteFile(
@Parameter(description = "Name of the MDM datasource", required = true) @PathParam(REQUESTPARAM_SOURCENAME) String sourceName,
@Parameter(description = "ID of the FilesAttachable containing the file link", required = true) @PathParam(REQUESTPARAM_ID) String id,
@Parameter(description = "The remote path of the file link whose content is to be retrieved", required = true) @PathParam(REQUESTPARAM_REMOTEPATH) String remotePath) {
return entityService.find(V(sourceName), fileAttachableClass, V(id))
.map(fileAttachable -> fileLinkActivity.deleteFileLink(sourceName, fileAttachable, remotePath))
.map(fileLink -> ServiceUtils.toResponse(Serializer.serializeFileLink(fileLink), Status.OK))
.recover(ServiceUtils.ERROR_RESPONSE_SUPPLIER).getOrElse(ServiceUtils.SERVER_ERROR_RESPONSE);
}
/**
* Creates new {@link FileLink} for {@link FilesAttachable}.
*
* @param sourceName name of the source (MDM {@link Environment} name)
* @param body The {@link FileLink} to create.
* @return
*/
@POST
@Operation(summary = "Attaches a new file.", responses = {
@ApiResponse(description = "The stored file link.", content = @Content(schema = @Schema(implementation = MDMFileLink.class))),
@ApiResponse(responseCode = "400", description = "Error") })
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.MULTIPART_FORM_DATA)
public Response createFile(
@Parameter(description = "Name of the MDM datasource", required = true) @PathParam(REQUESTPARAM_SOURCENAME) String sourceName,
@Parameter(description = "ID of the FilesAttachable containing the file link", required = true) @PathParam(REQUESTPARAM_ID) String id,
@Parameter(description = "InputStream containing file data", required = true) @FormDataParam("file") InputStream fileInputStream,
@Parameter(description = "Meta data describing file", required = true) @FormDataParam("file") FormDataContentDisposition cdh,
@Parameter(description = "File description", required = true) @FormDataParam("description") String description,
@Parameter(description = "Mimetype of the file", required = true) @FormDataParam("mimeType") MimeType mimeType) {
return entityService.find(V(sourceName), fileAttachableClass, V(id))
.map(fileAttachable -> fileLinkActivity.createFile(sourceName, fileAttachable, cdh.getFileName(),
fileInputStream, description, mimeType))
.map(fileLink -> ServiceUtils.toResponse(Serializer.serializeFileLink(fileLink), Status.OK))
.recover(ServiceUtils.ERROR_RESPONSE_SUPPLIER).getOrElse(ServiceUtils.SERVER_ERROR_RESPONSE);
}
/**
* Load the file size of a file link.
*
* @param sourceName name of the source (MDM {@link Environment} name)
* @param id The identifier of the {@link FilesAttachable} which
* contains the {@link FileLink}
* @param remotePath The remote path of the {@link FileLink} to identify, which
* {@link FileLink}'s content is requests.
* @return The serialized {@link FileLink} with the size.
*/
@GET
@Operation(summary = "Returns the file size of file link.", responses = {
@ApiResponse(description = "The file size of the requested file link.", content = @Content(schema = @Schema(implementation = FileSize.class))),
@ApiResponse(responseCode = "400", description = "Error") })
@Produces(MediaType.APPLICATION_JSON)
@Path("/size/{" + REQUESTPARAM_REMOTEPATH + "}")
public Response loadFileSize(
@Parameter(description = "Name of the MDM datasource", required = true) @PathParam(REQUESTPARAM_SOURCENAME) String sourceName,
@Parameter(description = "The identifier of the FilesAttachable containing the file links", required = true) @PathParam(REQUESTPARAM_ID) String id,
@Parameter(description = "The remote path of the file link whose size is to be retrieved", required = true) @PathParam(REQUESTPARAM_REMOTEPATH) String remotePath) {
return entityService.find(V(sourceName), fileAttachableClass, V(id))
.map(filesAttachable -> Tuple.of(filesAttachable,
fileLinkActivity.findFileLinkAtFileAttachable(remotePath, filesAttachable)))
.map(tuple -> fileLinkActivity.loadFileSize(sourceName, tuple._1, tuple._2))
.map(fileSize -> ServiceUtils.toResponse(fileSize, Status.OK))
.recover(ServiceUtils.ERROR_RESPONSE_SUPPLIER).getOrElse(ServiceUtils.SERVER_ERROR_RESPONSE);
}
/**
* Load the file sizes for all {@link FileLink}s of the {@link FilesAttachable}.
*
* @param sourceName name of the source (MDM {@link Environment} name)
* @param id The identifier of the {@link FilesAttachable} which
* contains the {@link FileLink}
* @param remotePath The remote path of the {@link FileLink} to identify, which
* {@link FileLink}'s content is requests.
* @return The serialized {@link FileLink} with the size.
*/
@GET
@Operation(summary = "Returns the sizes of all file links attached to a FilesAttachable.", responses = {
@ApiResponse(description = "The file size of the requested file link.", content = @Content(array = @ArraySchema(schema = @Schema(implementation = FileSize.class)))),
@ApiResponse(responseCode = "400", description = "Error") })
@Produces(MediaType.APPLICATION_JSON)
@Path("/sizes")
public Response loadFileSizes(
@Parameter(description = "Name of the MDM datasource", required = true) @PathParam(REQUESTPARAM_SOURCENAME) String sourceName,
@Parameter(description = "ID of the FilesAttachable containing the file link", required = true) @PathParam(REQUESTPARAM_ID) String id) {
return entityService.find(V(sourceName), fileAttachableClass, V(id))
.map(filesAttachable -> fileLinkActivity.loadFileSizes(sourceName, filesAttachable))
.map(fileSizes -> ServiceUtils.toResponse(fileSizes, Status.OK))
.recover(ServiceUtils.ERROR_RESPONSE_SUPPLIER).getOrElse(ServiceUtils.SERVER_ERROR_RESPONSE);
}
}