Newer
Older
/*
* This file is part of vospace-file-service
* Copyright (C) 2021 Istituto Nazionale di Astrofisica
* SPDX-License-Identifier: GPL-3.0-or-later
*/
package it.inaf.ia2.transfer.controller;
import it.inaf.ia2.transfer.persistence.model.FileInfo;
import it.inaf.ia2.transfer.persistence.FileDAO;
import it.inaf.ia2.transfer.service.PutFileService;
import it.inaf.oats.vospace.exception.InvalidArgumentException;
import it.inaf.oats.vospace.exception.NodeNotFoundException;
import it.inaf.oats.vospace.exception.QuotaExceededException;
import java.io.IOException;
import java.io.InputStream;
Nicola Fulvio Calabria
committed
import java.security.NoSuchAlgorithmException;
import javax.servlet.http.HttpServletRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
Nicola Fulvio Calabria
committed
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.http.HttpHeaders;
@RestController
public class PutFileController extends FileController {
private static final Logger LOG = LoggerFactory.getLogger(PutFileController.class);
Nicola Fulvio Calabria
committed
@Autowired
private FileDAO fileDAO;
Nicola Fulvio Calabria
committed
@Autowired
private PutFileService putFileService;
@PutMapping("/**")
public void putFile(@RequestHeader(value = HttpHeaders.CONTENT_ENCODING, required = false) String contentEncoding,
@RequestParam(value = "file", required = false) MultipartFile file,
@RequestParam(value = "jobId", required = false) String jobId,
HttpServletRequest request) throws IOException, NoSuchAlgorithmException {
Nicola Fulvio Calabria
committed
Nicola Fulvio Calabria
committed
if (jobId == null) {
LOG.debug("putFile called for path {}", path);
} else {
LOG.debug("putFile called for path {} with jobId {}", path, jobId);
if (!jobDAO.isJobExisting(jobId)) {
throw new InvalidArgumentException("Job " + jobId + " not found");
Nicola Fulvio Calabria
committed
}
Nicola Fulvio Calabria
committed
}
handleFileJob(() -> {
int nodes = fileDAO.setBusy(path, jobId);
if (nodes == 1) {
try {
FileInfo fileInfo
= fileDAO.getFileInfo(path).orElseThrow(
// This can happen only if some code ignores busy state
// and deletes the node
() -> {
throw new NodeNotFoundException(path);
});
String parentPath = FileInfo.getVosParentPath(fileInfo);
Long remainingQuota = fileDAO.getRemainingQuota(parentPath);
// if MultipartFile provides file size it is possible to check
// quota limit before reading the stream
if (remainingQuota != null && file != null && file.getSize() > remainingQuota) {
throw new QuotaExceededException("Path: " + fileInfo.getVirtualPath());
}
if (file != null) {
fileInfo.setContentType(file.getContentType());
}
fileInfo.setContentEncoding(contentEncoding);
try (InputStream in = file != null ? file.getInputStream() : request.getInputStream()) {
putFileService.storeFileFromInputStream(fileInfo, in, remainingQuota);
} catch (IOException ex) {
throw new UncheckedIOException(ex);
}
} finally {
fileDAO.setBusy(path, null);
Nicola Fulvio Calabria
committed
}
} else {
throw new NodeNotFoundException(path);
}, jobId);