com.qwazr.tools.ArchiverTool.java Source code

Java tutorial

Introduction

Here is the source code for com.qwazr.tools.ArchiverTool.java

Source

/**
 * Copyright 2014-2016 Emmanuel Keller / QWAZR
 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 **/
package com.qwazr.tools;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;
import com.qwazr.library.AbstractLibrary;
import com.qwazr.utils.CharsetUtils;
import com.qwazr.utils.IOUtils;
import com.qwazr.utils.json.JsonMapper;
import org.apache.commons.compress.archivers.ArchiveEntry;
import org.apache.commons.compress.archivers.ArchiveException;
import org.apache.commons.compress.archivers.ArchiveInputStream;
import org.apache.commons.compress.archivers.ArchiveStreamFactory;
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
import org.apache.commons.compress.compressors.CompressorException;
import org.apache.commons.compress.compressors.CompressorOutputStream;
import org.apache.commons.compress.compressors.CompressorStreamFactory;
import org.apache.commons.io.FilenameUtils;
import org.apache.http.entity.ContentType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

public class ArchiverTool extends AbstractLibrary {

    private static final Logger logger = LoggerFactory.getLogger(ArchiverTool.class);

    private volatile CompressorStreamFactory factory = null;

    public enum CodecType {

        deflate(CompressorStreamFactory.DEFLATE),

        gzip(CompressorStreamFactory.GZIP),

        bzip2(CompressorStreamFactory.BZIP2),

        z(CompressorStreamFactory.Z);

        private final String codecName;

        CodecType(String codecName) {
            this.codecName = codecName;
        }
    }

    public final CodecType codec;

    public ArchiverTool() {
        codec = null;
    }

    @Override
    public void load(File parentDir) {
        factory = new CompressorStreamFactory();
    }

    private InputStream getCompressorNewInputStream(InputStream input) throws IOException, CompressorException {
        if (codec == null)
            return factory.createCompressorInputStream(input);
        else
            return factory.createCompressorInputStream(codec.codecName, input);
    }

    /**
     * Return a reader for the given file
     *
     * @param source  the source file
     * @param context an optional autoclosing context
     * @return a new reader
     * @throws IOException
     * @throws CompressorException
     */
    @JsonIgnore
    public InputStreamReader getCompressorReader(File source, IOUtils.CloseableContext context)
            throws IOException, CompressorException {
        InputStream input = getCompressorNewInputStream(new BufferedInputStream(new FileInputStream(source)));
        InputStreamReader reader = new InputStreamReader(input);
        if (context != null)
            context.add(reader);
        return reader;
    }

    public void decompress(File source, File destFile) throws IOException, CompressorException {
        if (destFile.exists())
            throw new IOException("The file already exists: " + destFile.getPath());
        InputStream input = getCompressorNewInputStream(new BufferedInputStream(new FileInputStream(source)));
        try {
            IOUtils.copy(input, destFile);
        } catch (IOException e) {
            throw new IOException("Unable to decompress the file: " + source.getPath(), e);
        } finally {
            IOUtils.closeQuietly(input);
        }
    }

    /**
     * Decompress the file as a String
     *
     * @param sourceFile the file to uncompress
     * @return a string with the uncompressed content
     * @throws IOException         related to I/O errors
     * @throws CompressorException if any compression error occurs
     */
    public String decompressString(File sourceFile) throws IOException, CompressorException {
        InputStream input = getCompressorNewInputStream(new BufferedInputStream(new FileInputStream(sourceFile)));
        try {
            return IOUtils.toString(input);
        } finally {
            IOUtils.closeQuietly(input);
        }
    }

    /**
     * Decompress a JSON structure
     *
     * @param sourceFile
     * @return the decompressed object
     * @throws IOException         related to I/O errors
     * @throws CompressorException if any compression error occurs
     */
    public <T> T decompressJsonClass(File sourceFile, Class<T> valueType) throws IOException, CompressorException {
        InputStream input = getCompressorNewInputStream(new BufferedInputStream(new FileInputStream(sourceFile)));
        try {
            return JsonMapper.MAPPER.readValue(input, valueType);
        } finally {
            IOUtils.closeQuietly(input);
        }
    }

    /**
     * Decompress a JSON structure
     *
     * @param sourceFile
     * @param typeReference
     * @param <T>
     * @return
     * @throws IOException
     * @throws CompressorException
     */
    public <T> T decompressJsonType(File sourceFile, TypeReference<T> typeReference)
            throws IOException, CompressorException {
        InputStream input = getCompressorNewInputStream(new BufferedInputStream(new FileInputStream(sourceFile)));
        try {
            return JsonMapper.MAPPER.readValue(input, typeReference);
        } finally {
            IOUtils.closeQuietly(input);
        }
    }

    /**
     * Decompress a JSON structure
     *
     * @param sourceFile
     * @return
     * @throws IOException
     * @throws CompressorException
     */
    public JsonNode decompressJson(File sourceFile) throws IOException, CompressorException {
        InputStream input = getCompressorNewInputStream(new BufferedInputStream(new FileInputStream(sourceFile)));
        try {
            return JsonMapper.MAPPER.readTree(input);
        } finally {
            IOUtils.closeQuietly(input);
        }
    }

    public void decompress_dir(File sourceDir, String sourceExtension, File destDir, String destExtension)
            throws IOException, CompressorException {
        if (!sourceDir.exists())
            throw new FileNotFoundException("The source directory does not exist: " + sourceDir.getPath());
        if (!destDir.exists())
            throw new FileNotFoundException("The destination directory does not exist: " + destDir.getPath());
        File[] sourceFiles = sourceDir.listFiles();
        if (sourceFiles == null)
            return;
        for (File sourceFile : sourceFiles) {
            if (!sourceFile.isFile())
                continue;
            String ext = FilenameUtils.getExtension(sourceFile.getName());
            if (!sourceExtension.equals(ext))
                continue;
            String newName = FilenameUtils.getBaseName(sourceFile.getName()) + '.' + destExtension;
            File destFile = new File(destDir, newName);
            if (destFile.exists())
                continue;
            decompress(sourceFile, destFile);
        }
    }

    public void decompress_dir(String sourcePath, String sourceExtension, String destPath, String destExtension)
            throws IOException, CompressorException {
        decompress_dir(new File(sourcePath), sourceExtension, new File(destPath), destExtension);
    }

    public void extract(File sourceFile, File destDir) throws IOException, ArchiveException {
        final InputStream is = new BufferedInputStream(new FileInputStream(sourceFile));
        try {
            ArchiveInputStream in = new ArchiveStreamFactory().createArchiveInputStream(is);
            try {
                ArchiveEntry entry;
                while ((entry = in.getNextEntry()) != null) {
                    if (!in.canReadEntryData(entry))
                        continue;
                    if (entry.isDirectory()) {
                        new File(destDir, entry.getName()).mkdir();
                        continue;
                    }
                    if (entry instanceof ZipArchiveEntry)
                        if (((ZipArchiveEntry) entry).isUnixSymlink())
                            continue;
                    File destFile = new File(destDir, entry.getName());
                    File parentDir = destFile.getParentFile();
                    if (!parentDir.exists())
                        parentDir.mkdirs();
                    IOUtils.copy(in, destFile);
                }
            } catch (IOException e) {
                throw new IOException("Unable to extract the archive: " + sourceFile.getPath(), e);
            } finally {
                IOUtils.closeQuietly(in);
            }
        } catch (ArchiveException e) {
            throw new ArchiveException("Unable to extract the archive: " + sourceFile.getPath(), e);
        } finally {
            IOUtils.closeQuietly(is);
        }
    }

    public void extract_dir(File sourceDir, String sourceExtension, File destDir, Boolean logErrorAndContinue)
            throws IOException, ArchiveException {
        if (logErrorAndContinue == null)
            logErrorAndContinue = false;
        if (!sourceDir.exists())
            throw new FileNotFoundException("The source directory does not exist: " + sourceDir.getPath());
        if (!destDir.exists())
            throw new FileNotFoundException("The destination directory does not exist: " + destDir.getPath());
        File[] sourceFiles = sourceDir.listFiles();
        if (sourceFiles == null)
            return;
        for (File sourceFile : sourceFiles) {
            if (!sourceFile.isFile())
                continue;
            String ext = FilenameUtils.getExtension(sourceFile.getName());
            if (!sourceExtension.equals(ext))
                continue;
            try {
                extract(sourceFile, destDir);
            } catch (IOException | ArchiveException e) {
                if (logErrorAndContinue)
                    logger.error(e.getMessage(), e);
                else
                    throw e;
            }
        }
    }

    public void extract_dir(String sourcePath, String sourceExtension, String destPath, Boolean logErrorAndContinue)
            throws IOException, ArchiveException {
        extract_dir(new File(sourcePath), sourceExtension, new File(destPath), logErrorAndContinue);
    }

    private CompressorOutputStream getCompressor(OutputStream input) throws CompressorException {
        return factory.createCompressorOutputStream(codec.codecName, input);
    }

    /**
     * Compress a stream an write the compressed content in a file
     *
     * @param input    the stream to compress
     * @param destFile the compressed file
     * @throws CompressorException if any compression error occurs
     * @throws IOException         if any I/O error occurs
     */
    public void compress(InputStream input, File destFile) throws IOException, CompressorException {
        OutputStream output = getCompressor(new BufferedOutputStream(new FileOutputStream(destFile)));
        try {
            IOUtils.copy(input, output);
        } finally {
            IOUtils.closeQuietly(output);
        }
    }

    /**
     * Compress an array of byte and write it to a file
     *
     * @param bytes    the bytes to compress
     * @param destFile the compressed file
     * @throws CompressorException if any compression error occurs
     * @throws IOException         related to I/O errors
     */
    public void compress(byte[] bytes, File destFile) throws CompressorException, IOException {
        InputStream input = new ByteArrayInputStream(bytes);
        try {
            compress(input, destFile);
        } finally {
            IOUtils.closeQuietly(input);
        }
    }

    /**
     * Compress an UTF-8 string and write it to a file
     *
     * @param content  the text to compress
     * @param destFile the compressed file
     * @throws CompressorException if any compression error occurs
     * @throws IOException         related to I/O errors
     */
    public void compress(String content, File destFile) throws CompressorException, IOException {
        compress(CharsetUtils.encodeUtf8(content), destFile);
    }

    /**
     * Compress the content of a file to a new file
     *
     * @param sourceFile the file to compress
     * @param destFile   the compressed file
     * @throws CompressorException if any compression error occurs
     * @throws IOException         related to I/O errors
     */
    public void compress(File sourceFile, File destFile) throws CompressorException, IOException {
        InputStream input = new BufferedInputStream(new FileInputStream(sourceFile));
        try {
            compress(input, destFile);
        } finally {
            IOUtils.closeQuietly(input);
        }
    }

    public void createZipArchive(Map<String, Object> sourcePaths, File zipFile) throws IOException {
        FileOutputStream fos = new FileOutputStream(zipFile);
        try {
            ZipOutputStream zos = new ZipOutputStream(fos);
            try {
                for (Map.Entry<String, Object> entry : sourcePaths.entrySet())
                    addToZipFile(entry.getKey(), entry.getValue().toString(), zos);
            } finally {
                IOUtils.closeQuietly(zos);
            }
        } finally {
            IOUtils.closeQuietly(fos);
        }
    }

    public void createZipArchive(Map<String, Object> sourcePaths, String zipFilePath) throws IOException {
        createZipArchive(sourcePaths, new File(zipFilePath));
    }

    public void addToZipFile(String entryName, String filePath, ZipOutputStream zos) throws IOException {

        File srcFile = new File(filePath);
        if (!srcFile.exists())
            throw new FileNotFoundException("The file does not exists: " + srcFile.getPath());
        FileInputStream fis = new FileInputStream(srcFile);
        try {
            ZipEntry zipEntry = new ZipEntry(entryName);
            zos.putNextEntry(zipEntry);
            IOUtils.copy(fis, zos);
            zos.closeEntry();
        } finally {
            IOUtils.closeQuietly(fis);
        }
    }

    public final static ContentType APPLICATION_ZIP = ContentType.create("application/zip");

    @JsonIgnore
    public static ContentType getApplicationZipContentType() {
        return APPLICATION_ZIP;
    }
}