fr.gael.dhus.datastore.FileSystemDataStore.java Source code

Java tutorial

Introduction

Here is the source code for fr.gael.dhus.datastore.FileSystemDataStore.java

Source

/*
 * Data Hub Service (DHuS) - For Space data distribution.
 * Copyright (C) 2013,2014,2015 GAEL Systems
 *
 * This file is part of DHuS software sources.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
package fr.gael.dhus.datastore;

import fr.gael.dhus.database.object.Product;
import fr.gael.dhus.datastore.exception.DataStoreException;
import fr.gael.dhus.system.config.ConfigurationManager;
import fr.gael.dhus.util.UnZip;

import org.apache.commons.io.FileUtils;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * Manages binaries of Product on the local file system.
 */
@Component
public class FileSystemDataStore implements DataStore<Product> {
    private static final Logger LOGGER = LogManager.getLogger(FileSystemDataStore.class);
    private final int BUFFER_SIZE = 1024;

    @Autowired
    private ConfigurationManager cfgManager;

    @Autowired
    private IncomingManager incomingManager;

    // Getters & Setters
    public ConfigurationManager getCfgManager() {
        return cfgManager;
    }

    public void setCfgManager(ConfigurationManager cfgManager) {
        this.cfgManager = cfgManager;
    }

    public IncomingManager getIncomingManager() {
        return incomingManager;
    }

    public void setIncomingManager(IncomingManager incomingManager) {
        this.incomingManager = incomingManager;
    }

    @Override
    public void add(Product product) {
        throw new UnsupportedOperationException("No supported yet !");
    }

    @Override
    public void remove(Product product, Destination destination) {
        if (product == null) {
            throw new DataStoreException("Cannot remove a null product");
        }
        if (product.getLocked()) {
            throw new DataStoreException("Cannot remove product: " + product + ", it is locked by the system");
        }

        if (!isRemovable(product)) {
            LOGGER.warn("Cannot delete product :" + product);
        }

        switch (destination) {
        case TRASH:
            moveProduct(product, cfgManager.getArchiveConfiguration().getEvictionConfiguration().getTrashPath());
            break;
        case ERROR:
            moveProduct(product, cfgManager.getArchiveConfiguration().getIncomingConfiguration().getErrorPath());
            break;

        case NONE:
            break;

        default:
            LOGGER.warn("Unknown destination the product will be deleted");
        }

        removeFiles(product);
    }

    /**
     * Deletes all binaries of the given product.
     *
     * @param product product to delete
     */
    private void removeFiles(Product product) {
        try {
            // Delete product file from path
            String prodPath = product.getPath().toString();
            if (!prodPath.equals(product.getOrigin())) {
                prodPath = prodPath.replaceAll("file://?", "/");
                deleteIncomingFolder(prodPath);
            }
            // Delete product file from download path
            deleteIncomingFolder(product.getDownloadablePath());
            // Delete product thumbnail
            if (product.getThumbnailFlag()) {
                deleteIncomingFolder(product.getThumbnailPath());
            }
            // Delete product quick-look
            if (product.getQuicklookFlag()) {
                deleteIncomingFolder(product.getQuicklookPath());
            }
        } catch (Exception e) {
            LOGGER.error("There was an error while removing processed files for" + " product '"
                    + product.getIdentifier() + "'", e);
        }
    }

    /**
     * Delete a file or a directory via it path.
     *
     * @param path path of file to delete.
     * @throws IOException in case deletion is unsuccessful.
     */
    private void deleteIncomingFolder(String path) throws IOException {
        if (path == null) {
            return;
        }
        File container = new File(path);
        if (!container.exists() || !incomingManager.isInIncoming(container)) {
            return;
        }
        if (IncomingManager.INCOMING_PRODUCT_DIR.equals(container.getParentFile().getName())) {
            container = container.getParentFile();
        }
        if (HierarchicalDirectoryBuilder.DHUS_ENTRY_NAME.equals(container.getParentFile().getName())) {
            container = container.getParentFile();
        }
        if (container != null) {
            FileUtils.forceDelete(container);
        }
    }

    /**
     * Returns true if binaries of product are in the file system storage defined
     * in configuration.
     *
     * @param product product to check for deletion.
     * @return true if product is present in file system storage.
     */
    private boolean isRemovable(Product product) {
        String a_path = cfgManager.getArchiveConfiguration().getIncomingConfiguration().getPath();
        if (a_path.startsWith("file:/")) {
            a_path = a_path.substring(6);
        }

        File a_file = new File(a_path);
        if (a_file.exists() && a_file.isDirectory()) {
            a_path = a_file.getAbsolutePath();
            String p_file = product.getPath().getPath();
            return p_file.startsWith(a_path) && !product.getLocked();
        }
        return false;
    }

    /**
     * Moves product download zip into the given destination.
     * <p><b>Note:</b> generates the zip of product if necessary.</p>
     *
     * @param product     product to move.
     * @param destination destination of product
     */
    private void moveProduct(Product product, String destination) {

        if (destination == null || destination.trim().isEmpty()) {
            return;
        }

        Path zip_destination = Paths.get(destination);
        String download_path = product.getDownloadablePath();
        try {
            if (download_path != null) {
                File product_zip_file = Paths.get(download_path).toFile();
                FileUtils.moveFileToDirectory(product_zip_file, zip_destination.toFile(), true);
            } else {
                Path product_path = Paths.get(product.getPath().getPath());
                if (UnZip.supported(product_path.toAbsolutePath().toString())) {
                    FileUtils.moveFileToDirectory(product_path.toFile(), zip_destination.toFile(), true);
                } else {
                    zip_destination.resolve(product_path.getFileName());
                    generateZip(product_path.toFile(), zip_destination.toFile());
                }
            }
        } catch (IOException e) {
            LOGGER.error("Cannot move product: " + product.getPath() + " into " + destination, e);
        }
    }

    /**
     * Generates a zip file.
     *
     * @param source      source file or directory to compress.
     * @param destination destination of zipped file.
     * @return the zipped file.
     */
    private void generateZip(File source, File destination) throws IOException {
        if (source == null || !source.exists()) {
            throw new IllegalArgumentException("source file should exist");
        }
        if (destination == null) {
            throw new IllegalArgumentException("destination file should be not null");
        }

        FileOutputStream output = new FileOutputStream(destination);
        ZipOutputStream zip_out = new ZipOutputStream(output);
        zip_out.setLevel(cfgManager.getDownloadConfiguration().getCompressionLevel());

        List<QualifiedFile> file_list = getFileList(source);
        byte[] buffer = new byte[BUFFER_SIZE];
        for (QualifiedFile qualified_file : file_list) {
            ZipEntry entry = new ZipEntry(qualified_file.getQualifier());
            InputStream input = new FileInputStream(qualified_file.getFile());

            int read;
            zip_out.putNextEntry(entry);
            while ((read = input.read(buffer)) != -1) {
                zip_out.write(buffer, 0, read);
            }
            input.close();
            zip_out.closeEntry();
        }
        zip_out.close();
        output.close();
    }

    /**
     * Computes all normal files present in a file.
     * @param src
     * @return a list of {@link QualifiedFile}
     */
    private List<QualifiedFile> getFileList(File src) {
        ArrayList<QualifiedFile> result = new ArrayList<>();
        getFileList(src, null, result);
        return result;
    }

    /**
     * Internal method of {@link FileSystemDataStore#getFileList(File)}
     */
    private void getFileList(File src, String prefix_folder, ArrayList<QualifiedFile> files) {
        String qualifier;
        if (prefix_folder == null) {
            qualifier = src.getName();
        } else {
            qualifier = prefix_folder + File.separator + src.getName();
        }

        if (src.isFile()) {
            files.add(new QualifiedFile(src, qualifier));
        } else if (src.isDirectory()) {
            for (File file : src.listFiles()) {
                getFileList(file, qualifier, files);
            }
        }
    }

    /**
     * Represent a {@link File} with a qualifier name.
     */
    private static class QualifiedFile {
        private final File file;
        private final String qualifier;

        public QualifiedFile(File file, String qualifier) {
            this.qualifier = qualifier;
            this.file = file;
        }

        public String getQualifier() {
            return qualifier;
        }

        public File getFile() {
            return file;
        }

        @Override
        public String toString() {
            return file.getAbsolutePath() + " --> " + qualifier;
        }
    }
}