Newer
Older
package it.inaf.ia2.transfer.controller;
import it.inaf.ia2.transfer.persistence.FileDAO;
import it.inaf.ia2.transfer.persistence.ListOfFilesDAO;
Nicola Fulvio Calabria
committed
//import it.inaf.oats.vospace.persistence.JobDAO;
import net.ivoa.xml.uws.v1.JobSummary;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
Nicola Fulvio Calabria
committed
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
Nicola Fulvio Calabria
committed
import javax.xml.bind.DatatypeConverter;
import net.ivoa.xml.uws.v1.ExecutionPhase;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import static org.springframework.http.HttpStatus.NOT_FOUND;
import org.springframework.http.ResponseEntity;
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 JobDAO jobDAO;
@Autowired
private ListOfFilesDAO listOfFilesDAO;
@PutMapping("/**")
Nicola Fulvio Calabria
committed
public ResponseEntity<?> putFile(@RequestHeader(value = HttpHeaders.CONTENT_ENCODING, required = false) String contentEncoding,
@RequestParam("file") MultipartFile file,
@RequestParam(value = "jobid", required = false) String jobId) throws IOException, NoSuchAlgorithmException {
Nicola Fulvio Calabria
committed
JobSummary job = null;
if (jobId == null) {
LOG.debug("putFile called for path {}", path);
} else {
LOG.debug("putFile called for path {} with jobId {}", path, jobId);
/*
Optional<JobSummary> resultJob = jobDAO.getJob(jobId);
if(resultJob.isPresent())
{
job = resultJob.get();
} else {
return new ResponseEntity<>("Job "+jobId+ " not found", NOT_FOUND);
}*/
}
Optional<FileInfo> optFileInfo = fileDAO.getFileInfo(path);
if (optFileInfo.isPresent()) {
try (InputStream in = file.getInputStream()) {
Nicola Fulvio Calabria
committed
FileInfo fileInfo = optFileInfo.get();
if (fileInfo.getAcceptViews() != null && fileInfo.getAcceptViews().contains("urn:list-of-files")) {
storeListOfFiles(fileInfo, in);
} else {
fileInfo.setContentType(file.getContentType());
fileInfo.setContentEncoding(contentEncoding);
storeGenericFile(fileInfo, in, job);
}
}
return ResponseEntity.ok().build();
} else {
return new ResponseEntity<>("File " + path + " not found", NOT_FOUND);
}
}
Nicola Fulvio Calabria
committed
/*
private void storeFile(FileInfo fileInfo, InputStream is, String jobId) throws IOException {
if (fileInfo.getAcceptViews() != null && fileInfo.getAcceptViews().contains("urn:list-of-files")) {
storeListOfFiles(fileInfo, is);
} else {
Nicola Fulvio Calabria
committed
storeGenericFile(fileInfo, is, jobId);
Nicola Fulvio Calabria
committed
}*/
private void storeListOfFiles(FileInfo fileInfo, InputStream is) throws IOException {
List<String> filePaths = parseListOfFiles(is);
listOfFilesDAO.createList(fileInfo.getVirtualPath(), filePaths);
}
private List<String> parseListOfFiles(InputStream is) throws IOException {
List<String> filePaths = new ArrayList<>();
try (BufferedReader br = new BufferedReader(new InputStreamReader(is))) {
String line;
while ((line = br.readLine()) != null && !line.isBlank()) {
filePaths.add(line.trim());
}
}
return filePaths;
}
Nicola Fulvio Calabria
committed
private void storeGenericFile(FileInfo fileInfo, InputStream is, JobSummary job) throws IOException, NoSuchAlgorithmException {
File file = new File(fileInfo.getOsPath());
/**
* This block must be synchronized, to avoid concurrency issues when
* multiple files are uploaded to a new folder in parallel.
*/
synchronized (this) {
if (!file.getParentFile().exists()) {
if (!file.getParentFile().mkdirs()) {
throw new IllegalStateException("Unable to create parent folder: " + file.getParentFile().getAbsolutePath());
}
String originalFileName = file.getName();
file = getEmptyFile(file, 1);
if (!originalFileName.equals(file.getName())) {
fileDAO.setOsName(fileInfo.getNodeId(), file.getName());
}
try {
fileDAO.setBusy(fileInfo.getNodeId(), true);
Files.copy(is, file.toPath());
Nicola Fulvio Calabria
committed
Long fileSize = Files.size(file.toPath());
String md5Checksum = makeMD5Checksum(file);
fileDAO.updateFileAttributes(fileInfo.getNodeId(),
fileInfo.getContentType(),
fileInfo.getContentEncoding(),
fileSize,
md5Checksum);
if (job != null) {
//job.setPhase(ExecutionPhase.COMPLETED);
//jobDAO.updateJob(job);
}
} catch (IOException | NoSuchAlgorithmException ex) {
if (job != null) {
//job.setPhase(ExecutionPhase.ERROR);
//jobDAO.updateJob(job);
}
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
throw ex;
} finally {
fileDAO.setBusy(fileInfo.getNodeId(), false);
}
}
/**
* Handles duplicate file uploads generating a new non existent path. This
* is necessary in some edge cases, like when a file has been renamed in
* VOSpace only but the original file on disk still has the old name or if a
* file has been marked for deletion and a file with the same name is
* uploaded before the cleanup.
*/
private File getEmptyFile(File file, int index) {
if (file.exists()) {
String fileName = file.getName();
String nameWithoutExtension;
String extension = null;
if (fileName.contains(".")) {
nameWithoutExtension = fileName.substring(0, fileName.lastIndexOf("."));
extension = fileName.substring(fileName.lastIndexOf(".") + 1, fileName.length());
} else {
nameWithoutExtension = fileName;
}
String newName = nameWithoutExtension + "-" + index;
if (extension != null) {
newName += "." + extension;
}
File newFile = file.toPath().getParent().resolve(newName).toFile();
return getEmptyFile(newFile, index + 1);
}
return file;
Nicola Fulvio Calabria
committed
private String makeMD5Checksum(File file) throws NoSuchAlgorithmException, IOException {
MessageDigest md = MessageDigest.getInstance("MD5");
md.update(Files.readAllBytes(file.toPath()));
byte[] digest = md.digest();
String checksum = DatatypeConverter.printHexBinary(digest);
return checksum;
}