Commit 0608bd6a authored by Sonia Zorba's avatar Sonia Zorba
Browse files

Tar/Zip archive generation: added endpoint for retrieving generated files,...

Tar/Zip archive generation: added endpoint for retrieving generated files, modified generation endpoint payload and added tests
parent 4a576fcf
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -148,6 +148,9 @@
            <plugin>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>2.22.2</version>
                <configuration>
                    <trimStackTrace>false</trimStackTrace>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.springframework.boot</groupId>
+32 −11
Original line number Diff line number Diff line
@@ -7,15 +7,21 @@ package it.inaf.ia2.transfer.controller;

import it.inaf.ia2.transfer.auth.TokenPrincipal;
import it.inaf.ia2.transfer.service.ArchiveJob;
import it.inaf.ia2.transfer.service.ArchiveJob.Type;
import it.inaf.ia2.transfer.service.ArchiveService;
import java.util.List;
import java.io.File;
import java.util.concurrent.CompletableFuture;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
@@ -27,21 +33,36 @@ public class ArchiveFileController {
    @Autowired
    private HttpServletRequest request;

    @PostMapping(value = "/tar", consumes = MediaType.APPLICATION_JSON_VALUE)
    public void createTarArchive(@RequestParam(value = "jobId", required = true) String jobId, @RequestBody List<String> vosPaths) {
    @Autowired
    private HttpServletResponse response;

    @PostMapping(value = "/archive", consumes = MediaType.APPLICATION_JSON_VALUE)
    public ResponseEntity<?> createArchiveFile(@RequestBody ArchiveRequest archiveRequest) {

        Type type = Type.valueOf(archiveRequest.getType());

        ArchiveJob job = new ArchiveJob();
        job.setPrincipal((TokenPrincipal) request.getUserPrincipal());
        job.setJobId(jobId);
        job.setType(ArchiveJob.Type.TAR);
        job.setVosPaths(vosPaths);
        job.setJobId(archiveRequest.getJobId());
        job.setType(type);
        job.setVosPaths(archiveRequest.getPaths());

        startArchiveJob(job);
    }

    private void startArchiveJob(ArchiveJob job) {
        CompletableFuture.runAsync(() -> {
            archiveService.createArchive(job);
        });

        HttpHeaders headers = new HttpHeaders();
        headers.set("Location", request.getRequestURL() + "/" + archiveRequest.getJobId() + "." + type.getExtension());
        return new ResponseEntity<>(headers, HttpStatus.SEE_OTHER);
    }

    @GetMapping(value = "/archive/{fileName}")
    public ResponseEntity<?> getArchiveFile(@PathVariable("fileName") String fileName) {

        TokenPrincipal principal = (TokenPrincipal) request.getUserPrincipal();

        File file = archiveService.getArchiveParentDir(principal).toPath().resolve(fileName).toFile();

        return FileResponseUtil.getFileResponse(response, file);
    }
}
+27 −4
Original line number Diff line number Diff line
@@ -3,14 +3,37 @@
 * Copyright (C) 2021 Istituto Nazionale di Astrofisica
 * SPDX-License-Identifier: GPL-3.0-or-later
 */

package it.inaf.ia2.transfer.controller;

import java.util.List;

public class ArchiveRequest {

    private List<String> vosPaths;
    String jobId;
    String type;
    private String type;
    private String jobId;
    private List<String> paths;

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    public String getJobId() {
        return jobId;
    }

    public void setJobId(String jobId) {
        this.jobId = jobId;
    }

    public List<String> getPaths() {
        return paths;
    }

    public void setPaths(List<String> paths) {
        this.paths = paths;
    }
}
+59 −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.controller;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UncheckedIOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR;
import static org.springframework.http.HttpStatus.NOT_FOUND;
import org.springframework.http.ResponseEntity;

public class FileResponseUtil {

    private static final Logger LOG = LoggerFactory.getLogger(FileResponseUtil.class);

    public static ResponseEntity<?> getFileResponse(HttpServletResponse response, File file) {
        return getFileResponse(response, file, null);
    }

    public static ResponseEntity<?> getFileResponse(HttpServletResponse response, File file, String fileName) {

        if (!file.exists()) {
            LOG.error("File not found: " + file.getAbsolutePath());
            return new ResponseEntity<>("File " + file.getName() + " not found", NOT_FOUND);
        }

        if (!file.canRead()) {
            LOG.error("File not readable: " + file.getAbsolutePath());
            return new ResponseEntity<>("File " + file.getName() + " is not readable", INTERNAL_SERVER_ERROR);
        }

        response.setHeader("Content-Disposition", "attachment; filename="
                + URLEncoder.encode(fileName == null ? file.getName() : fileName, StandardCharsets.UTF_8));
        response.setHeader("Content-Length", String.valueOf(file.length()));
        response.setCharacterEncoding("UTF-8");

        byte[] bytes = new byte[1024];
        try ( OutputStream out = response.getOutputStream();  InputStream is = new FileInputStream(file)) {
            int read;
            while ((read = is.read(bytes)) != -1) {
                out.write(bytes, 0, read);
            }
        } catch (IOException ex) {
            throw new UncheckedIOException(ex);
        }
        return null;
    }
}
+3 −35
Original line number Diff line number Diff line
@@ -10,19 +10,11 @@ import it.inaf.ia2.transfer.auth.TokenPrincipal;
import it.inaf.ia2.transfer.persistence.FileDAO;
import it.inaf.ia2.transfer.service.AuthorizationService;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UncheckedIOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Optional;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import static org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR;
import static org.springframework.http.HttpStatus.NOT_FOUND;
import static org.springframework.http.HttpStatus.UNAUTHORIZED;
import org.springframework.http.ResponseEntity;
@@ -69,33 +61,9 @@ public class GetFileController extends FileController {
    private ResponseEntity<?> getFileResponse(FileInfo fileInfo) {

        File file = new File(fileInfo.getOsPath());
        String vosName = fileInfo.getVirtualPath() == null ? null
                : fileInfo.getVirtualPath().substring(fileInfo.getVirtualPath().lastIndexOf("/") + 1);

        if (!file.exists()) {
            LOG.error("File not found: " + file.getAbsolutePath());
            return new ResponseEntity<>("File " + file.getName() + " not found", NOT_FOUND);
        }

        if (!file.canRead()) {
            LOG.error("File not readable: " + file.getAbsolutePath());
            return new ResponseEntity<>("File " + file.getName() + " is not readable", INTERNAL_SERVER_ERROR);
        }

        String vosName = fileInfo.getVirtualPath().substring(fileInfo.getVirtualPath().lastIndexOf("/") + 1);

        response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(vosName, StandardCharsets.UTF_8));
        response.setHeader("Content-Length", String.valueOf(file.length()));
        response.setCharacterEncoding("UTF-8");

        byte[] bytes = new byte[1024];
        try (OutputStream out = response.getOutputStream();
                InputStream is = new FileInputStream(file)) {
            int read;
            while ((read = is.read(bytes)) != -1) {
                out.write(bytes, 0, read);
            }
        } catch (IOException ex) {
            throw new UncheckedIOException(ex);
        }
        return null;
        return FileResponseUtil.getFileResponse(response, file, vosName);
    }
}
Loading