Loading src/main/java/it/inaf/ia2/transfer/controller/ArchiveFileController.java +1 −1 Original line number Diff line number Diff line Loading @@ -46,7 +46,7 @@ public class ArchiveFileController extends AuthenticatedFileController { job.setPrincipal(getPrincipal()); job.setJobId(archiveRequest.getJobId()); job.setType(type); job.setVosPaths(archiveRequest.getPaths()); job.setEntryDescriptors(archiveRequest.getEntryDescriptors()); CompletableFuture.runAsync(() -> { handleFileJob(() -> archiveService.createArchive(job, servletRequest), job.getJobId()); Loading src/main/java/it/inaf/ia2/transfer/controller/ArchiveRequest.java +6 −5 Original line number Diff line number Diff line Loading @@ -5,13 +5,14 @@ */ package it.inaf.ia2.transfer.controller; import it.inaf.oats.vospace.parent.exchange.ArchiveEntryDescriptor; import java.util.List; public class ArchiveRequest { private String type; private String jobId; private List<String> paths; private List<ArchiveEntryDescriptor> entryDescriptors; public String getType() { return type; Loading @@ -29,11 +30,11 @@ public class ArchiveRequest { this.jobId = jobId; } public List<String> getPaths() { return paths; public List<ArchiveEntryDescriptor> getEntryDescriptors() { return entryDescriptors; } public void setPaths(List<String> paths) { this.paths = paths; public void setEntryDescriptors(List<ArchiveEntryDescriptor> entryDescriptors) { this.entryDescriptors = entryDescriptors; } } src/main/java/it/inaf/ia2/transfer/service/ArchiveJob.java +7 −5 Original line number Diff line number Diff line Loading @@ -6,6 +6,7 @@ package it.inaf.ia2.transfer.service; import it.inaf.ia2.transfer.auth.TokenPrincipal; import it.inaf.oats.vospace.parent.exchange.ArchiveEntryDescriptor; import java.util.List; public class ArchiveJob { Loading @@ -26,17 +27,17 @@ public class ArchiveJob { } } private List<String> vosPaths; private List<ArchiveEntryDescriptor> entryDescriptors; private TokenPrincipal tokenPrincipal; private String jobId; private Type type; public List<String> getVosPaths() { return vosPaths; public List<ArchiveEntryDescriptor> getEntryDescriptors() { return entryDescriptors; } public void setVosPaths(List<String> vosPaths) { this.vosPaths = vosPaths; public void setEntryDescriptors(List<ArchiveEntryDescriptor> entryDescriptors) { this.entryDescriptors = entryDescriptors; } public TokenPrincipal getPrincipal() { Loading @@ -62,4 +63,5 @@ public class ArchiveJob { public void setType(Type type) { this.type = type; } } src/main/java/it/inaf/ia2/transfer/service/ArchiveService.java +107 −45 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ import it.inaf.ia2.transfer.persistence.model.FileInfo; import it.inaf.oats.vospace.exception.InternalFaultException; import it.inaf.oats.vospace.exception.PermissionDeniedException; import it.inaf.oats.vospace.exception.QuotaExceededException; import it.inaf.oats.vospace.parent.exchange.ArchiveEntryDescriptor; import it.inaf.oats.vospace.parent.persistence.LinkedServiceDAO; import java.io.BufferedOutputStream; import java.io.File; Loading @@ -29,6 +30,7 @@ import java.nio.file.Files; import java.security.Principal; import java.util.List; import java.util.Map; import java.util.stream.Collectors; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; import javax.annotation.PostConstruct; Loading Loading @@ -105,30 +107,95 @@ public class ArchiveService { // TODO: check total size limit File archiveFile = getArchiveFile(job); String commonParent = getCommonParent(job.getVosPaths()); List<ArchiveEntryDescriptor> entryDescriptors = job.getEntryDescriptors(); String commonParent = getCommonParent(entryDescriptors); // support directory used to generate folder inside tar files (path is redefined each time by TarEntry class) File supportDir = Files.createTempDirectory("dir").toFile(); try (ArchiveHandler<O, E> handler = getArchiveHandler(archiveFile, job.getType())) { fillArchive(entryDescriptors, commonParent, supportDir, job.getPrincipal(), servletRequest, handler); } finally { FileSystemUtils.deleteRecursively(supportDir); } } catch (IOException ex) { throw new UncheckedIOException(ex); } } private <O extends OutputStream, E> void fillArchive( List<ArchiveEntryDescriptor> entryDescriptors, String commonParent, File supportDir, TokenPrincipal tokenPrincipal, HttpServletRequest servletRequest, ArchiveHandler<O, E> handler) throws IOException { // it will be initialized only when necessary Map<Integer, String> portalLocationUrls = null; try (ArchiveHandler<O, E> handler = getArchiveHandler(archiveFile, job.getType())) { List<ArchiveEntryDescriptor> noTargetEntryDescriptors = entryDescriptors.stream().filter(ed -> !ed.isPointingToAnotherNode()) .collect(Collectors.toList()); for (FileInfo fileInfo : fileDAO.getArchiveFileInfos(job.getVosPaths())) { // Start with archive entry descriptors which don't point to another node List<String> vosPaths = noTargetEntryDescriptors.stream() .map(ed -> ed.getVosPath()) .collect(Collectors.toList()); if (!vosPaths.isEmpty()) { for (FileInfo fileInfo : fileDAO.getArchiveFileInfos(vosPaths)) { String relPath = fileInfo.getVirtualPath().substring(commonParent.length()); this.insertEntryIntoArchive(fileInfo, supportDir, relPath, tokenPrincipal, portalLocationUrls, servletRequest, handler); } } List<ArchiveEntryDescriptor> pointingEntryDescriptors = entryDescriptors.stream().filter(ed -> ed.isPointingToAnotherNode()) .collect(Collectors.toList()); // Now archive entry descriptors pointing to another node List<String> targetNodesVosPaths = pointingEntryDescriptors.stream() .map(ed -> ed.getTargetNodeVosPath()) .collect(Collectors.toList()); if (!targetNodesVosPaths.isEmpty()) { for (FileInfo fileInfo : fileDAO.getArchiveFileInfos(targetNodesVosPaths)) { // relPaths is calculated from base node String targetNodeVosPath = fileInfo.getVirtualPath(); String vosPath = pointingEntryDescriptors.stream() .filter(ed->ed.getTargetNodeVosPath().equals(targetNodeVosPath)) .findFirst().get().getVosPath(); String relPath = vosPath.substring(commonParent.length()); this.insertEntryIntoArchive(fileInfo, supportDir, relPath, tokenPrincipal, portalLocationUrls, servletRequest, handler); } } } private <O extends OutputStream, E> void insertEntryIntoArchive( FileInfo fileInfo, File supportDir, String relPath, TokenPrincipal tokenPrincipal, Map<Integer, String> portalLocationUrls, HttpServletRequest servletRequest, ArchiveHandler<O, E> handler) throws IOException { if (fileInfo.isDirectory()) { handler.putNextEntry(supportDir, relPath); continue; return; } // I expect only external links // local links have been resolved before calling this endpoint if (fileInfo.isLink()) { downloadExternalLinkIntoArchive(fileInfo, relPath, job.getPrincipal(), handler, servletRequest); continue; tokenPrincipal, handler, servletRequest); return; } if (fileInfo.getLocationId() != null && "portal".equals(fileInfo.getLocationType())) { Loading @@ -137,18 +204,10 @@ public class ArchiveService { portalLocationUrls = locationDAO.getPortalLocationUrls(); } String url = portalLocationUrls.get(fileInfo.getLocationId()); downloadRemoteLocationFileIntoArchive(fileInfo, relPath, job.getPrincipal(), handler, url); downloadRemoteLocationFileIntoArchive(fileInfo, relPath, tokenPrincipal, handler, url); } else { // local file or virtual directory writeFileIntoArchive(fileInfo, relPath, job.getPrincipal(), handler); } } } finally { FileSystemUtils.deleteRecursively(supportDir); } } catch (IOException ex) { throw new UncheckedIOException(ex); writeFileIntoArchive(fileInfo, relPath, tokenPrincipal, handler); } } Loading Loading @@ -191,7 +250,11 @@ public class ArchiveService { return generatedDir.toPath().resolve(principal.getName()).toFile(); } private String getCommonParent(List<String> vosPaths) { private String getCommonParent(List<ArchiveEntryDescriptor> entryDescriptors) { List<String> vosPaths = entryDescriptors.stream().map(ed -> ed.getVosPath()) .collect(Collectors.toList()); String commonParent = null; for (String vosPath : vosPaths) { if (commonParent == null) { Loading Loading @@ -342,7 +405,6 @@ public class ArchiveService { } // Append token if url is recognized if (linkedServiceDAO.isLinkedServiceUrl(url)) { url += "?token=" + getEndpointToken(tokenPrincipal, url, servletRequest); } Loading src/test/java/it/inaf/ia2/transfer/controller/ArchiveFileControllerTest.java +5 −2 Original line number Diff line number Diff line Loading @@ -44,6 +44,8 @@ public class ArchiveFileControllerTest { @Autowired private MockMvc mockMvc; // TODO: refactor tests /* @Test public void testCreateTarArchive() throws Exception { Loading @@ -66,7 +68,7 @@ public class ArchiveFileControllerTest { assertEquals(2, job.getVosPaths().size()); return true; }), any()); } }*/ @Test public void testGetArchive() throws Exception { Loading @@ -88,6 +90,7 @@ public class ArchiveFileControllerTest { } } /* @Test public void testAnonymousCantCreateArchive() throws Exception { Loading @@ -102,7 +105,7 @@ public class ArchiveFileControllerTest { .content(MAPPER.writeValueAsString(request))) .andDo(print()) .andExpect(status().isForbidden()); } }*/ @Test public void testAnonymousCantGetArchive() throws Exception { Loading Loading
src/main/java/it/inaf/ia2/transfer/controller/ArchiveFileController.java +1 −1 Original line number Diff line number Diff line Loading @@ -46,7 +46,7 @@ public class ArchiveFileController extends AuthenticatedFileController { job.setPrincipal(getPrincipal()); job.setJobId(archiveRequest.getJobId()); job.setType(type); job.setVosPaths(archiveRequest.getPaths()); job.setEntryDescriptors(archiveRequest.getEntryDescriptors()); CompletableFuture.runAsync(() -> { handleFileJob(() -> archiveService.createArchive(job, servletRequest), job.getJobId()); Loading
src/main/java/it/inaf/ia2/transfer/controller/ArchiveRequest.java +6 −5 Original line number Diff line number Diff line Loading @@ -5,13 +5,14 @@ */ package it.inaf.ia2.transfer.controller; import it.inaf.oats.vospace.parent.exchange.ArchiveEntryDescriptor; import java.util.List; public class ArchiveRequest { private String type; private String jobId; private List<String> paths; private List<ArchiveEntryDescriptor> entryDescriptors; public String getType() { return type; Loading @@ -29,11 +30,11 @@ public class ArchiveRequest { this.jobId = jobId; } public List<String> getPaths() { return paths; public List<ArchiveEntryDescriptor> getEntryDescriptors() { return entryDescriptors; } public void setPaths(List<String> paths) { this.paths = paths; public void setEntryDescriptors(List<ArchiveEntryDescriptor> entryDescriptors) { this.entryDescriptors = entryDescriptors; } }
src/main/java/it/inaf/ia2/transfer/service/ArchiveJob.java +7 −5 Original line number Diff line number Diff line Loading @@ -6,6 +6,7 @@ package it.inaf.ia2.transfer.service; import it.inaf.ia2.transfer.auth.TokenPrincipal; import it.inaf.oats.vospace.parent.exchange.ArchiveEntryDescriptor; import java.util.List; public class ArchiveJob { Loading @@ -26,17 +27,17 @@ public class ArchiveJob { } } private List<String> vosPaths; private List<ArchiveEntryDescriptor> entryDescriptors; private TokenPrincipal tokenPrincipal; private String jobId; private Type type; public List<String> getVosPaths() { return vosPaths; public List<ArchiveEntryDescriptor> getEntryDescriptors() { return entryDescriptors; } public void setVosPaths(List<String> vosPaths) { this.vosPaths = vosPaths; public void setEntryDescriptors(List<ArchiveEntryDescriptor> entryDescriptors) { this.entryDescriptors = entryDescriptors; } public TokenPrincipal getPrincipal() { Loading @@ -62,4 +63,5 @@ public class ArchiveJob { public void setType(Type type) { this.type = type; } }
src/main/java/it/inaf/ia2/transfer/service/ArchiveService.java +107 −45 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ import it.inaf.ia2.transfer.persistence.model.FileInfo; import it.inaf.oats.vospace.exception.InternalFaultException; import it.inaf.oats.vospace.exception.PermissionDeniedException; import it.inaf.oats.vospace.exception.QuotaExceededException; import it.inaf.oats.vospace.parent.exchange.ArchiveEntryDescriptor; import it.inaf.oats.vospace.parent.persistence.LinkedServiceDAO; import java.io.BufferedOutputStream; import java.io.File; Loading @@ -29,6 +30,7 @@ import java.nio.file.Files; import java.security.Principal; import java.util.List; import java.util.Map; import java.util.stream.Collectors; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; import javax.annotation.PostConstruct; Loading Loading @@ -105,30 +107,95 @@ public class ArchiveService { // TODO: check total size limit File archiveFile = getArchiveFile(job); String commonParent = getCommonParent(job.getVosPaths()); List<ArchiveEntryDescriptor> entryDescriptors = job.getEntryDescriptors(); String commonParent = getCommonParent(entryDescriptors); // support directory used to generate folder inside tar files (path is redefined each time by TarEntry class) File supportDir = Files.createTempDirectory("dir").toFile(); try (ArchiveHandler<O, E> handler = getArchiveHandler(archiveFile, job.getType())) { fillArchive(entryDescriptors, commonParent, supportDir, job.getPrincipal(), servletRequest, handler); } finally { FileSystemUtils.deleteRecursively(supportDir); } } catch (IOException ex) { throw new UncheckedIOException(ex); } } private <O extends OutputStream, E> void fillArchive( List<ArchiveEntryDescriptor> entryDescriptors, String commonParent, File supportDir, TokenPrincipal tokenPrincipal, HttpServletRequest servletRequest, ArchiveHandler<O, E> handler) throws IOException { // it will be initialized only when necessary Map<Integer, String> portalLocationUrls = null; try (ArchiveHandler<O, E> handler = getArchiveHandler(archiveFile, job.getType())) { List<ArchiveEntryDescriptor> noTargetEntryDescriptors = entryDescriptors.stream().filter(ed -> !ed.isPointingToAnotherNode()) .collect(Collectors.toList()); for (FileInfo fileInfo : fileDAO.getArchiveFileInfos(job.getVosPaths())) { // Start with archive entry descriptors which don't point to another node List<String> vosPaths = noTargetEntryDescriptors.stream() .map(ed -> ed.getVosPath()) .collect(Collectors.toList()); if (!vosPaths.isEmpty()) { for (FileInfo fileInfo : fileDAO.getArchiveFileInfos(vosPaths)) { String relPath = fileInfo.getVirtualPath().substring(commonParent.length()); this.insertEntryIntoArchive(fileInfo, supportDir, relPath, tokenPrincipal, portalLocationUrls, servletRequest, handler); } } List<ArchiveEntryDescriptor> pointingEntryDescriptors = entryDescriptors.stream().filter(ed -> ed.isPointingToAnotherNode()) .collect(Collectors.toList()); // Now archive entry descriptors pointing to another node List<String> targetNodesVosPaths = pointingEntryDescriptors.stream() .map(ed -> ed.getTargetNodeVosPath()) .collect(Collectors.toList()); if (!targetNodesVosPaths.isEmpty()) { for (FileInfo fileInfo : fileDAO.getArchiveFileInfos(targetNodesVosPaths)) { // relPaths is calculated from base node String targetNodeVosPath = fileInfo.getVirtualPath(); String vosPath = pointingEntryDescriptors.stream() .filter(ed->ed.getTargetNodeVosPath().equals(targetNodeVosPath)) .findFirst().get().getVosPath(); String relPath = vosPath.substring(commonParent.length()); this.insertEntryIntoArchive(fileInfo, supportDir, relPath, tokenPrincipal, portalLocationUrls, servletRequest, handler); } } } private <O extends OutputStream, E> void insertEntryIntoArchive( FileInfo fileInfo, File supportDir, String relPath, TokenPrincipal tokenPrincipal, Map<Integer, String> portalLocationUrls, HttpServletRequest servletRequest, ArchiveHandler<O, E> handler) throws IOException { if (fileInfo.isDirectory()) { handler.putNextEntry(supportDir, relPath); continue; return; } // I expect only external links // local links have been resolved before calling this endpoint if (fileInfo.isLink()) { downloadExternalLinkIntoArchive(fileInfo, relPath, job.getPrincipal(), handler, servletRequest); continue; tokenPrincipal, handler, servletRequest); return; } if (fileInfo.getLocationId() != null && "portal".equals(fileInfo.getLocationType())) { Loading @@ -137,18 +204,10 @@ public class ArchiveService { portalLocationUrls = locationDAO.getPortalLocationUrls(); } String url = portalLocationUrls.get(fileInfo.getLocationId()); downloadRemoteLocationFileIntoArchive(fileInfo, relPath, job.getPrincipal(), handler, url); downloadRemoteLocationFileIntoArchive(fileInfo, relPath, tokenPrincipal, handler, url); } else { // local file or virtual directory writeFileIntoArchive(fileInfo, relPath, job.getPrincipal(), handler); } } } finally { FileSystemUtils.deleteRecursively(supportDir); } } catch (IOException ex) { throw new UncheckedIOException(ex); writeFileIntoArchive(fileInfo, relPath, tokenPrincipal, handler); } } Loading Loading @@ -191,7 +250,11 @@ public class ArchiveService { return generatedDir.toPath().resolve(principal.getName()).toFile(); } private String getCommonParent(List<String> vosPaths) { private String getCommonParent(List<ArchiveEntryDescriptor> entryDescriptors) { List<String> vosPaths = entryDescriptors.stream().map(ed -> ed.getVosPath()) .collect(Collectors.toList()); String commonParent = null; for (String vosPath : vosPaths) { if (commonParent == null) { Loading Loading @@ -342,7 +405,6 @@ public class ArchiveService { } // Append token if url is recognized if (linkedServiceDAO.isLinkedServiceUrl(url)) { url += "?token=" + getEndpointToken(tokenPrincipal, url, servletRequest); } Loading
src/test/java/it/inaf/ia2/transfer/controller/ArchiveFileControllerTest.java +5 −2 Original line number Diff line number Diff line Loading @@ -44,6 +44,8 @@ public class ArchiveFileControllerTest { @Autowired private MockMvc mockMvc; // TODO: refactor tests /* @Test public void testCreateTarArchive() throws Exception { Loading @@ -66,7 +68,7 @@ public class ArchiveFileControllerTest { assertEquals(2, job.getVosPaths().size()); return true; }), any()); } }*/ @Test public void testGetArchive() throws Exception { Loading @@ -88,6 +90,7 @@ public class ArchiveFileControllerTest { } } /* @Test public void testAnonymousCantCreateArchive() throws Exception { Loading @@ -102,7 +105,7 @@ public class ArchiveFileControllerTest { .content(MAPPER.writeValueAsString(request))) .andDo(print()) .andExpect(status().isForbidden()); } }*/ @Test public void testAnonymousCantGetArchive() throws Exception { Loading