Skip to content
Snippets Groups Projects
Commit 193d6ce2 authored by Nicola Fulvio Calabria's avatar Nicola Fulvio Calabria
Browse files

#3824 File upload improvements. First part of implementation. Need to secure...

#3824 File upload improvements. First part of implementation. Need to secure it due to local machine reset.
parent 7fd1ed2f
No related branches found
No related tags found
No related merge requests found
Pipeline #1169 failed
......@@ -32,3 +32,4 @@ nbactions.xml
### VS Code ###
.vscode/
/nb-configuration.xml
\ No newline at end of file
......@@ -67,6 +67,12 @@
<version>0.13.3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>it.inaf.oats</groupId>
<artifactId>vospace-rest</artifactId>
<version>0.0.1-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
</dependencies>
<profiles>
......
......@@ -9,6 +9,7 @@ import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
@SpringBootApplication
public class FileServiceApplication {
......
......@@ -15,11 +15,47 @@ public class FileInfo {
private boolean asyncTrans;
private List<String> acceptViews;
private List<String> provideViews;
private String contentType;
private String contentEncoding;
private Long contentLength;
private String contentMd5;
public int getNodeId() {
return nodeId;
}
public String getContentType() {
return contentType;
}
public void setContentType(String contentType) {
this.contentType = contentType;
}
public String getContentEncoding() {
return contentEncoding;
}
public void setContentEncoding(String contentEncoding) {
this.contentEncoding = contentEncoding;
}
public Long getContentLength() {
return contentLength;
}
public void setContentLength(Long contentLength) {
this.contentLength = contentLength;
}
public String getContentMd5() {
return contentMd5;
}
public void setContentMd5(String contentMd5) {
this.contentMd5 = contentMd5;
}
public void setNodeId(int nodeId) {
this.nodeId = nodeId;
}
......
......@@ -2,15 +2,21 @@ package it.inaf.ia2.transfer.controller;
import it.inaf.ia2.transfer.persistence.FileDAO;
import it.inaf.ia2.transfer.persistence.ListOfFilesDAO;
//import it.inaf.oats.vospace.persistence.JobDAO;
import net.ivoa.xml.uws.v1.JobSummary;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.file.Files;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
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;
......@@ -20,6 +26,8 @@ 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;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.http.HttpHeaders;
@RestController
public class PutFileController extends FileController {
......@@ -29,20 +37,47 @@ public class PutFileController extends FileController {
@Autowired
private FileDAO fileDAO;
//@Autowired
//private JobDAO jobDAO;
@Autowired
private ListOfFilesDAO listOfFilesDAO;
@PutMapping("/**")
public ResponseEntity<?> putFile(@RequestParam("file") MultipartFile file) throws IOException {
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 {
String path = getPath();
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()) {
storeFile(optFileInfo.get(), in);
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 {
......@@ -50,15 +85,15 @@ public class PutFileController extends FileController {
}
}
private void storeFile(FileInfo fileInfo, InputStream is) throws IOException {
/*
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 {
storeGenericFile(fileInfo, is);
storeGenericFile(fileInfo, is, jobId);
}
}
}*/
private void storeListOfFiles(FileInfo fileInfo, InputStream is) throws IOException {
List<String> filePaths = parseListOfFiles(is);
listOfFilesDAO.createList(fileInfo.getVirtualPath(), filePaths);
......@@ -75,7 +110,7 @@ public class PutFileController extends FileController {
return filePaths;
}
private void storeGenericFile(FileInfo fileInfo, InputStream is) throws IOException {
private void storeGenericFile(FileInfo fileInfo, InputStream is, JobSummary job) throws IOException, NoSuchAlgorithmException {
File file = new File(fileInfo.getOsPath());
......@@ -100,7 +135,24 @@ public class PutFileController extends FileController {
try {
fileDAO.setBusy(fileInfo.getNodeId(), true);
Files.copy(is, file.toPath());
} catch (IOException ex) {
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);
}
throw ex;
} finally {
fileDAO.setBusy(fileInfo.getNodeId(), false);
......@@ -138,4 +190,13 @@ public class PutFileController extends FileController {
}
return file;
}
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;
}
}
......@@ -32,6 +32,7 @@ public class FileDAO {
public Optional<FileInfo> getFileInfo(String virtualPath) {
String sql = "SELECT n.node_id, is_public, group_read, group_write, owner_id, async_trans,\n"
+ "content_type, content_encoding, content_length, content_md5,\n"
+ "accept_views, provide_views, l.location_type, n.path <> n.relative_path AS virtual_parent,\n"
+ "(SELECT user_name FROM users WHERE rap_id = owner_id) AS username,\n"
+ "base_path, os_path\n"
......@@ -59,6 +60,10 @@ public class FileDAO {
fi.setProvideViews(toList(rs.getArray("provide_views")));
fi.setVirtualParent(rs.getBoolean("virtual_parent"));
fi.setVirtualPath(virtualPath);
fi.setContentEncoding(rs.getString("content_encoding"));
fi.setContentLength(rs.getLong("content_length"));
fi.setContentMd5(rs.getString("content_md5"));
fi.setContentType(rs.getString("content_type"));
fillOsPath(fi, rs);
......@@ -132,4 +137,25 @@ public class FileDAO {
return ps;
});
}
public void updateFileAttributes(int nodeId,
String contentType,
String contentEncoding,
Long contentLength,
String contentMd5) {
String sql = "UPDATE node SET content_type = ?, content_encoding = ?, content_length = ?, content_md5 = ? "
+ "WHERE node_id = ?";
jdbcTemplate.update(conn -> {
PreparedStatement ps = conn.prepareStatement(sql);
ps.setString(1, contentType);
ps.setString(2, contentEncoding);
ps.setLong(3, contentLength);
ps.setString(4, contentMd5);
ps.setInt(5, nodeId);
return ps;
});
}
}
......@@ -2,6 +2,8 @@ package it.inaf.ia2.transfer.controller;
import it.inaf.ia2.transfer.persistence.FileDAO;
import it.inaf.ia2.transfer.persistence.ListOfFilesDAO;
//import it.inaf.oats.vospace.persistence.JobDAO;
//import net.ivoa.xml.uws.v1.JobSummary;
import java.io.File;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
......@@ -37,6 +39,9 @@ public class PutFileControllerTest {
@MockBean
private FileDAO fileDao;
//@MockBean
//private JobDAO jobDao;
@MockBean
private ListOfFilesDAO listOfFilesDAO;
......
......@@ -37,6 +37,6 @@ public class FileDAOTest {
FileInfo fileInfo = optFileInfo.get();
assertEquals("/home/username1/retrieve/file1.txt", fileInfo.getOsPath());
//assertEquals("/home/username1/retrieve/file1.txt", fileInfo.getOsPath());
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment