package eu.europeana.cloud.service.mcs.rest;
import java.io.InputStream;
import java.util.UUID;
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
import eu.europeana.cloud.service.mcs.rest.storage.selector.PreBufferedInputStream;
import eu.europeana.cloud.service.mcs.rest.storage.selector.StorageSelector;
import org.apache.commons.io.IOUtils;
import org.glassfish.jersey.media.multipart.FormDataParam;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.acls.model.MutableAclService;
import org.springframework.stereotype.Component;
import eu.europeana.cloud.common.model.File;
import eu.europeana.cloud.service.mcs.RecordService;
import eu.europeana.cloud.service.mcs.exception.CannotModifyPersistentRepresentationException;
import eu.europeana.cloud.service.mcs.exception.FileAlreadyExistsException;
import eu.europeana.cloud.service.mcs.exception.FileNotExistsException;
import eu.europeana.cloud.service.mcs.exception.RepresentationNotExistsException;
import static eu.europeana.cloud.common.web.ParamConstants.*;
import static eu.europeana.cloud.service.mcs.rest.storage.selector.PreBufferedInputStream.wrap;
/**
* FilesResource
*/
@Path("/records/{" + P_CLOUDID + "}/representations/{" + P_REPRESENTATIONNAME
+ "}/versions/{" + P_VER + "}/files")
@Component
@Scope("request")
public class FilesResource {
private static final Logger LOGGER = LoggerFactory.getLogger("RequestsLogger");
@Autowired
private RecordService recordService;
@Autowired
private MutableAclService mutableAclService;
@Autowired
private Integer objectStoreSizeThreshold;
/**
* Adds a new file to representation version. URI to created resource will
* be returned in response as content location. Consumes multipart content -
* form data:
* <ul>
* <li>{@value eu.europeana.cloud.common.web.ParamConstants#F_FILE_MIME} -
* file mime type</li>
* <li>{@value eu.europeana.cloud.common.web.ParamConstants#F_FILE_NAME} -
* file name</li>
* <li>{@value eu.europeana.cloud.common.web.ParamConstants#F_FILE_DATA} -
* binary stream of file content (required)</li>
* </ul>
*
* <strong>Write permissions required.</strong>
*@summary Add a new file to a representation version
* @param globalId cloud id of the record (required).
* @param schema schema of representation (required).
* @param version a specific version of the representation(required).
* @param mimeType
* mime type of file
* @param data
* binary stream of file content (required)
* @param fileName
* name of creating file. If fileName does not provided by POST
* request fileName will assigned automatically by service.
* @return empty response with tag (content md5) and URI to the created resource
* in content location.
* @statuscode 201 object has been created.
* @throws RepresentationNotExistsException
* representation does not exist in specified version
* @throws CannotModifyPersistentRepresentationException
* specified representation version is persistent and modifying
* its files is not allowed.
* @throws FileAlreadyExistsException
* specified file already exist.
*/
@POST
@Consumes(MediaType.MULTIPART_FORM_DATA)
@PreAuthorize("hasPermission(#globalId.concat('/').concat(#schema).concat('/').concat(#version),"
+ " 'eu.europeana.cloud.common.model.Representation', write)")
public Response sendFile(@Context UriInfo uriInfo,
@PathParam(P_CLOUDID) final String globalId,
@PathParam(P_REPRESENTATIONNAME) final String schema,
@PathParam(P_VER) final String version,
@FormDataParam(F_FILE_MIME) String mimeType,
@FormDataParam(F_FILE_DATA) InputStream data,
@FormDataParam(F_FILE_NAME) String fileName)
throws RepresentationNotExistsException,
CannotModifyPersistentRepresentationException,
FileAlreadyExistsException {
ParamUtil.require(F_FILE_DATA, data);
ParamUtil.require(F_FILE_MIME, mimeType);
File f = new File();
f.setMimeType(mimeType);
PreBufferedInputStream prebufferedInputStream = wrap(data, objectStoreSizeThreshold);
f.setFileStorage(new StorageSelector(prebufferedInputStream, mimeType).selectStorage());
if (fileName != null) {
try {
File temp = recordService.getFile(globalId, schema, version,
fileName);
if (temp != null) {
throw new FileAlreadyExistsException(fileName);
}
} catch (FileNotExistsException e) {
// file does not exist, so continue and add it
}
}
if (fileName == null) {
fileName = UUID.randomUUID().toString();
}
f.setFileName(fileName);
recordService.putContent(globalId, schema, version, f, prebufferedInputStream);
IOUtils.closeQuietly(prebufferedInputStream);
EnrichUriUtil.enrich(uriInfo, globalId, schema, version, f);
LOGGER.debug(String.format("File added [%s, %s, %s], uri: %s ",
globalId, schema, version, f.getContentUri()));
return Response.created(f.getContentUri()).tag(f.getMd5()).build();
}
}