Loading src/main/java/it/inaf/ia2/transfer/controller/ArchiveFileController.java +0 −1 Original line number Diff line number Diff line Loading @@ -6,7 +6,6 @@ package it.inaf.ia2.transfer.controller; import it.inaf.ia2.transfer.auth.TokenPrincipal; import it.inaf.ia2.transfer.exception.PermissionDeniedException; import it.inaf.ia2.transfer.service.ArchiveJob; import it.inaf.ia2.transfer.service.ArchiveJob.Type; import it.inaf.ia2.transfer.service.ArchiveService; Loading src/main/java/it/inaf/ia2/transfer/controller/CopyController.java +5 −1 Original line number Diff line number Diff line Loading @@ -10,10 +10,14 @@ import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; import org.springframework.beans.factory.annotation.Autowired; import it.inaf.ia2.transfer.service.CopyService; @RestController public class CopyController extends AuthenticatedFileController { @Autowired private CopyService copyService; @PostMapping(value = "/copy", consumes = MediaType.APPLICATION_JSON_VALUE) public ResponseEntity<?> copyFiles(@RequestBody CopyRequest copyRequest) { Loading src/main/java/it/inaf/ia2/transfer/controller/CopyRequest.java +10 −10 Original line number Diff line number Diff line Loading @@ -8,8 +8,8 @@ package it.inaf.ia2.transfer.controller; public class CopyRequest { String jobId; String target; String direction; String sourceRootVosPath; String destinationRootVosPath; public String getJobId() { return jobId; Loading @@ -19,20 +19,20 @@ public class CopyRequest { this.jobId = jobId; } public String getTarget() { return target; public String getSourceRootVosPath() { return sourceRootVosPath; } public void setTarget(String target) { this.target = target; public void setSourceRootVosPath(String sourceRootVosPath) { this.sourceRootVosPath = sourceRootVosPath; } public String getDirection() { return direction; public String getDestinationRootVosPath() { return destinationRootVosPath; } public void setDirection(String direction) { this.direction = direction; public void setDestinationRootVosPath(String destinationRootVosPath) { this.destinationRootVosPath = destinationRootVosPath; } } src/main/java/it/inaf/ia2/transfer/service/CopyService.java 0 → 100644 +153 −0 Original line number Diff line number Diff line /* * 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.service; import it.inaf.ia2.transfer.auth.TokenPrincipal; import it.inaf.ia2.transfer.exception.InsufficientStorageException; import it.inaf.ia2.transfer.exception.JobException; import it.inaf.ia2.transfer.exception.JobException.Type; import it.inaf.ia2.transfer.persistence.FileDAO; import it.inaf.ia2.transfer.persistence.JobDAO; import it.inaf.ia2.transfer.persistence.LocationDAO; import it.inaf.ia2.transfer.persistence.model.FileInfo; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.UncheckedIOException; import java.nio.file.Files; import java.security.Principal; import java.util.List; import java.util.Map; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; import net.ivoa.xml.uws.v1.ExecutionPhase; import org.kamranzafar.jtar.TarEntry; import org.kamranzafar.jtar.TarOutputStream; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.stereotype.Service; import org.springframework.util.FileSystemUtils; import org.springframework.util.unit.DataSize; import org.springframework.web.client.RestTemplate; @Service public class CopyService { private static final Logger LOG = LoggerFactory.getLogger(CopyService.class); @Autowired private FileDAO fileDAO; @Autowired private LocationDAO locationDAO; @Autowired private JobDAO jobDAO; @Autowired private AuthorizationService authorizationService; @Autowired private RestTemplate restTemplate; @Value("${upload_location_id}") private int uploadLocationId; // Maximum size of the working directory for each registered user @Value("${generated.dir.max-size}") private DataSize generatedDirMaxSize; public void copyFiles(String sourceRootVosPath, String destinationRootVosPath, String jobId) { // We use jobId to identify nodes created by the REST part of CopyNode // We expect them to be locked } private String getCommonParent(List<String> vosPaths) { String commonParent = null; for (String vosPath : vosPaths) { if (commonParent == null) { commonParent = vosPath; } else { StringBuilder newCommonParent = new StringBuilder(); boolean same = true; for (int i = 0; same && i < Math.min(commonParent.length(), vosPath.length()); i++) { if (commonParent.charAt(i) == vosPath.charAt(i)) { newCommonParent.append(commonParent.charAt(i)); } else { same = false; } } commonParent = newCommonParent.toString(); } } return commonParent; } private <O extends OutputStream, E> void downloadFileIntoArchive(FileInfo fileInfo, String relPath, TokenPrincipal tokenPrincipal, ArchiveHandler<O, E> handler, String baseUrl) { if (baseUrl == null) { LOG.error("Location URL not found for location " + fileInfo.getLocationId()); throw new JobException(Type.FATAL, "Internal Fault") .setErrorDetail("InternalFault: Unable to retrieve location of file " + fileInfo.getVirtualPath()); } String url = baseUrl + "/" + fileInfo.getVirtualName(); LOG.trace("Downloading file from " + url); restTemplate.execute(url, HttpMethod.GET, req -> { HttpHeaders headers = req.getHeaders(); if (tokenPrincipal.getToken() != null) { headers.setBearerAuth(tokenPrincipal.getToken()); } }, res -> { File tmpFile = Files.createTempFile("download", null).toFile(); try ( FileOutputStream os = new FileOutputStream(tmpFile)) { res.getBody().transferTo(os); handler.putNextEntry(tmpFile, relPath); try ( FileInputStream is = new FileInputStream(tmpFile)) { is.transferTo(handler.getOutputStream()); } } finally { tmpFile.delete(); } return null; }, new Object[]{}); } private <O extends OutputStream, E> void writeFileIntoArchive(FileInfo fileInfo, String relPath, TokenPrincipal tokenPrincipal, ArchiveHandler<O, E> handler) throws IOException { if (!authorizationService.isDownloadable(fileInfo, tokenPrincipal)) { throw new JobException(Type.FATAL, "Permission Denied") .setErrorDetail("PermissionDenied: " + fileInfo.getVirtualPath()); } File file = new File(fileInfo.getOsPath()); LOG.trace("Adding file " + file.getAbsolutePath() + " to tar archive"); try ( InputStream is = new FileInputStream(file)) { handler.putNextEntry(file, relPath); is.transferTo(handler.getOutputStream()); } } } Loading
src/main/java/it/inaf/ia2/transfer/controller/ArchiveFileController.java +0 −1 Original line number Diff line number Diff line Loading @@ -6,7 +6,6 @@ package it.inaf.ia2.transfer.controller; import it.inaf.ia2.transfer.auth.TokenPrincipal; import it.inaf.ia2.transfer.exception.PermissionDeniedException; import it.inaf.ia2.transfer.service.ArchiveJob; import it.inaf.ia2.transfer.service.ArchiveJob.Type; import it.inaf.ia2.transfer.service.ArchiveService; Loading
src/main/java/it/inaf/ia2/transfer/controller/CopyController.java +5 −1 Original line number Diff line number Diff line Loading @@ -10,10 +10,14 @@ import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; import org.springframework.beans.factory.annotation.Autowired; import it.inaf.ia2.transfer.service.CopyService; @RestController public class CopyController extends AuthenticatedFileController { @Autowired private CopyService copyService; @PostMapping(value = "/copy", consumes = MediaType.APPLICATION_JSON_VALUE) public ResponseEntity<?> copyFiles(@RequestBody CopyRequest copyRequest) { Loading
src/main/java/it/inaf/ia2/transfer/controller/CopyRequest.java +10 −10 Original line number Diff line number Diff line Loading @@ -8,8 +8,8 @@ package it.inaf.ia2.transfer.controller; public class CopyRequest { String jobId; String target; String direction; String sourceRootVosPath; String destinationRootVosPath; public String getJobId() { return jobId; Loading @@ -19,20 +19,20 @@ public class CopyRequest { this.jobId = jobId; } public String getTarget() { return target; public String getSourceRootVosPath() { return sourceRootVosPath; } public void setTarget(String target) { this.target = target; public void setSourceRootVosPath(String sourceRootVosPath) { this.sourceRootVosPath = sourceRootVosPath; } public String getDirection() { return direction; public String getDestinationRootVosPath() { return destinationRootVosPath; } public void setDirection(String direction) { this.direction = direction; public void setDestinationRootVosPath(String destinationRootVosPath) { this.destinationRootVosPath = destinationRootVosPath; } }
src/main/java/it/inaf/ia2/transfer/service/CopyService.java 0 → 100644 +153 −0 Original line number Diff line number Diff line /* * 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.service; import it.inaf.ia2.transfer.auth.TokenPrincipal; import it.inaf.ia2.transfer.exception.InsufficientStorageException; import it.inaf.ia2.transfer.exception.JobException; import it.inaf.ia2.transfer.exception.JobException.Type; import it.inaf.ia2.transfer.persistence.FileDAO; import it.inaf.ia2.transfer.persistence.JobDAO; import it.inaf.ia2.transfer.persistence.LocationDAO; import it.inaf.ia2.transfer.persistence.model.FileInfo; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.UncheckedIOException; import java.nio.file.Files; import java.security.Principal; import java.util.List; import java.util.Map; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; import net.ivoa.xml.uws.v1.ExecutionPhase; import org.kamranzafar.jtar.TarEntry; import org.kamranzafar.jtar.TarOutputStream; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.stereotype.Service; import org.springframework.util.FileSystemUtils; import org.springframework.util.unit.DataSize; import org.springframework.web.client.RestTemplate; @Service public class CopyService { private static final Logger LOG = LoggerFactory.getLogger(CopyService.class); @Autowired private FileDAO fileDAO; @Autowired private LocationDAO locationDAO; @Autowired private JobDAO jobDAO; @Autowired private AuthorizationService authorizationService; @Autowired private RestTemplate restTemplate; @Value("${upload_location_id}") private int uploadLocationId; // Maximum size of the working directory for each registered user @Value("${generated.dir.max-size}") private DataSize generatedDirMaxSize; public void copyFiles(String sourceRootVosPath, String destinationRootVosPath, String jobId) { // We use jobId to identify nodes created by the REST part of CopyNode // We expect them to be locked } private String getCommonParent(List<String> vosPaths) { String commonParent = null; for (String vosPath : vosPaths) { if (commonParent == null) { commonParent = vosPath; } else { StringBuilder newCommonParent = new StringBuilder(); boolean same = true; for (int i = 0; same && i < Math.min(commonParent.length(), vosPath.length()); i++) { if (commonParent.charAt(i) == vosPath.charAt(i)) { newCommonParent.append(commonParent.charAt(i)); } else { same = false; } } commonParent = newCommonParent.toString(); } } return commonParent; } private <O extends OutputStream, E> void downloadFileIntoArchive(FileInfo fileInfo, String relPath, TokenPrincipal tokenPrincipal, ArchiveHandler<O, E> handler, String baseUrl) { if (baseUrl == null) { LOG.error("Location URL not found for location " + fileInfo.getLocationId()); throw new JobException(Type.FATAL, "Internal Fault") .setErrorDetail("InternalFault: Unable to retrieve location of file " + fileInfo.getVirtualPath()); } String url = baseUrl + "/" + fileInfo.getVirtualName(); LOG.trace("Downloading file from " + url); restTemplate.execute(url, HttpMethod.GET, req -> { HttpHeaders headers = req.getHeaders(); if (tokenPrincipal.getToken() != null) { headers.setBearerAuth(tokenPrincipal.getToken()); } }, res -> { File tmpFile = Files.createTempFile("download", null).toFile(); try ( FileOutputStream os = new FileOutputStream(tmpFile)) { res.getBody().transferTo(os); handler.putNextEntry(tmpFile, relPath); try ( FileInputStream is = new FileInputStream(tmpFile)) { is.transferTo(handler.getOutputStream()); } } finally { tmpFile.delete(); } return null; }, new Object[]{}); } private <O extends OutputStream, E> void writeFileIntoArchive(FileInfo fileInfo, String relPath, TokenPrincipal tokenPrincipal, ArchiveHandler<O, E> handler) throws IOException { if (!authorizationService.isDownloadable(fileInfo, tokenPrincipal)) { throw new JobException(Type.FATAL, "Permission Denied") .setErrorDetail("PermissionDenied: " + fileInfo.getVirtualPath()); } File file = new File(fileInfo.getOsPath()); LOG.trace("Adding file " + file.getAbsolutePath() + " to tar archive"); try ( InputStream is = new FileInputStream(file)) { handler.putNextEntry(file, relPath); is.transferTo(handler.getOutputStream()); } } }