Skip to content
ArchiveService.java 3.77 KiB
Newer Older
/*
 * 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.persistence.FileDAO;
import it.inaf.ia2.transfer.persistence.model.FileInfo;
import java.io.BufferedInputStream;
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 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.stereotype.Service;

@Service
public class ArchiveService {

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

    private final static int BUFFER_SIZE = 100 * 1024;

    @Autowired
    private FileDAO fileDAO;

    @Autowired
    private AuthorizationService authorizationService;

    private final File generatedDir;

    public ArchiveService(@Value("${generated.dir}") String generatedDir) {
        this.generatedDir = new File(generatedDir);
        if (!this.generatedDir.exists()) {
            if (!this.generatedDir.mkdirs()) {
                throw new IllegalStateException("Unable to create directory " + this.generatedDir.getAbsolutePath());
            }
        }
    }

    public void createArchive(ArchiveJob job) {

        LOG.trace("Started archive job " + job.getJobId());

        try {
            // TODO: check total size limit
            // TODO: switch on archive type
            File parentDir = generatedDir.toPath().resolve(job.getPrincipal().getName()).toFile();

            if (!parentDir.exists()) {
                if (!parentDir.mkdirs()) {
                    throw new IllegalStateException("Unable to create directory " + parentDir.getAbsolutePath());
                }
            }

            File archiveFile = parentDir.toPath().resolve(job.getJobId() + ".tar").toFile();
            if (!archiveFile.createNewFile()) {
                throw new IllegalStateException("Unable to create file " + archiveFile.getAbsolutePath());
            }

            try ( TarOutputStream tos = new TarOutputStream(
                    new BufferedOutputStream(new FileOutputStream(archiveFile)))) {

                for (FileInfo fileInfo : fileDAO.getArchiveFileInfos(job.getVosPaths())) {
                    // TODO: handle different locations

                    if (!authorizationService.isDownloadable(fileInfo, job.getPrincipal())) {
                        // TODO: proper exception type
                        throw new RuntimeException("Unauthorized");
                    }

                    File file = new File(fileInfo.getOsPath());
                    LOG.trace("Adding file " + file.getAbsolutePath() + " to tar archive");
                    writeFileIntoTarArchive(file, tos);
                }
            }
            // TODO: update job status

        } catch (Throwable t) {
            LOG.error("Error happened creating archive", t);
        }
    }

    private void writeFileIntoTarArchive(File file, TarOutputStream tos) throws IOException {
        TarEntry tarEntry = new TarEntry(file, file.getName());

        try ( InputStream is = new FileInputStream(file)) {
            tos.putNextEntry(tarEntry);
            try ( BufferedInputStream origin = new BufferedInputStream(is)) {
                int count;
                byte data[] = new byte[BUFFER_SIZE];

                while ((count = origin.read(data)) != -1) {
                    tos.write(data, 0, count);
                }

                tos.flush();
            }
        }
    }
}