org.ngrinder.common.util.CompressionUtils.java Source code

Java tutorial

Introduction

Here is the source code for org.ngrinder.common.util.CompressionUtils.java

Source

/* 
 * 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
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * 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 org.ngrinder.common.util;

import org.apache.commons.compress.archivers.ArchiveStreamFactory;
import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream;
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream;
import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.nio.charset.Charset;
import java.util.*;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream;

import static org.ngrinder.common.util.ExceptionUtils.processException;
import static org.ngrinder.common.util.Preconditions.checkNotNull;

/**
 * Compression utility.
 *
 * @author JunHo Yoon
 */
@SuppressWarnings("All")
public abstract class CompressionUtils {
    private static final Logger LOGGER = LoggerFactory.getLogger(CompressionUtils.class);

    /**
     * Unzip the given zipped file with given character set.
     *
     * @param zippedFile  zipped file
     * @param charsetName character set
     */
    public static void unzip(File zippedFile, String charsetName) {
        unzip(zippedFile, zippedFile.getParentFile(), charsetName);
    }

    /**
     * Unzip the given zipped file into destination directory.
     *
     * @param zippedFile zipped file
     * @param destDir    destination directory
     */
    public static void unzip(File zippedFile, File destDir) {
        try {
            unzip(new FileInputStream(zippedFile), destDir, Charset.defaultCharset().name());
        } catch (FileNotFoundException e) {
            throw processException(e);
        }
    }

    /**
     * Unzip the given zipped file into destination directory with the given
     * character set.
     *
     * @param zippedFile  zipped file
     * @param destDir     destination directory
     * @param charsetName character set name
     */
    public static void unzip(File zippedFile, File destDir, String charsetName) {
        try {
            unzip(new FileInputStream(zippedFile), destDir, charsetName);
        } catch (FileNotFoundException e) {
            throw processException(e);
        }
    }

    /**
     * Unzip the given input stream into destination directory with the default
     * character set.
     *
     * @param is      input stream
     * @param destDir destination directory
     */
    public static void unzip(InputStream is, File destDir) {
        unzip(is, destDir, Charset.defaultCharset().name());
    }

    /**
     * Unzip the given input stream into destination directory with the given
     * character set.
     *
     * @param is          input stream
     * @param destDir     destination directory
     * @param charsetName character set name
     */
    public static void unzip(InputStream is, File destDir, String charsetName) {
        byte[] buffer = new byte[1024];
        ZipInputStream zis = null;
        FileOutputStream fos = null;
        try {
            File folder = destDir;
            if (!folder.exists()) {
                folder.mkdir();
            }

            zis = new ZipInputStream(is);
            ZipEntry ze = zis.getNextEntry();

            while (ze != null) {
                String fileName = ze.getName();

                File newFile = new File(destDir.getAbsolutePath(), fileName);
                if (newFile.getPath().contains("..")) {
                    throw new IllegalArgumentException("zip entry should not contain .. in the path.");
                }
                if (ze.isDirectory()) {
                    newFile.mkdirs();
                } else {
                    fos = new FileOutputStream(newFile);
                    int len;
                    while ((len = zis.read(buffer)) > 0) {
                        fos.write(buffer, 0, len);
                    }
                    IOUtils.closeQuietly(fos);
                }

                ze = zis.getNextEntry();
            }
        } catch (Exception e) {
            throw processException(e);
        } finally {
            IOUtils.closeQuietly(fos);
            IOUtils.closeQuietly(is);
            IOUtils.closeQuietly(zis);
        }
    }

    /**
     * Compresses the given file(or dir) and creates new file under the same
     * directory.
     *
     * @param src file or directory
     * @throws IOException IOException
     */
    public static void zip(File src) throws IOException {
        zip(src, Charset.defaultCharset().name(), true);
    }

    /**
     * Zips the given file(or dir) and create.
     *
     * @param src        file or directory to compress
     * @param includeSrc if true and src is directory, then src is not included in the
     *                   compression. if false, src is included.
     * @throws IOException IOException
     */
    public static void zip(File src, boolean includeSrc) throws IOException {
        zip(src, Charset.defaultCharset().name(), includeSrc);
    }

    /**
     * Compresses the given src file (or directory) with the given encoding.
     *
     * @param src         src
     * @param charSetName character set
     * @param includeSrc  true if sub-directory will be zipped as well.
     * @throws IOException IOException
     */
    public static void zip(File src, String charSetName, boolean includeSrc) throws IOException {
        zip(src, src.getParentFile(), charSetName, includeSrc);
    }

    /**
     * Compresses the given src file(or directory) and writes to the given
     * output stream with sub directory.
     *
     * @param src src
     * @param os  output stream
     * @throws IOException IOException
     */
    public static void zip(File src, OutputStream os) throws IOException {
        zip(src, os, Charset.defaultCharset().name(), true);
    }

    /**
     * Compresses the given src file(or directory) and create the compressed
     * file under the given destDir.
     *
     * @param src         src to be zipped.
     * @param destDir     destination directory
     * @param charSetName character set to be used
     * @param includeSrc  true if sub-directory will be zipped as well.
     * @throws IOException IOException
     */
    public static void zip(File src, File destDir, String charSetName, boolean includeSrc) throws IOException {
        String fileName = src.getName();
        if (!src.isDirectory()) {
            int pos = fileName.lastIndexOf(".");
            if (pos > 0) {
                fileName = fileName.substring(0, pos);
            }
        }
        fileName += ".zip";

        File zippedFile = new File(destDir, fileName);
        if (!zippedFile.exists()) {
            zippedFile.createNewFile();
        }
        FileOutputStream os = null;
        try {
            os = new FileOutputStream(zippedFile);
            zip(src, os, charSetName, includeSrc);
        } finally {
            IOUtils.closeQuietly(os);
        }
    }

    /**
     * Zip the given src into the given output stream.
     *
     * @param src         src to be zipped
     * @param os          output stream
     * @param charsetName character set to be used
     * @param includeSrc  true if src will be included.
     * @throws IOException IOException
     */
    public static void zip(File src, OutputStream os, String charsetName, boolean includeSrc) throws IOException {
        ZipArchiveOutputStream zos = new ZipArchiveOutputStream(os);
        zos.setEncoding(charsetName);
        FileInputStream fis = null;

        int length;
        ZipArchiveEntry ze;
        byte[] buf = new byte[8 * 1024];
        String name;

        Stack<File> stack = new Stack<File>();
        File root;
        if (src.isDirectory()) {
            if (includeSrc) {
                stack.push(src);
                root = src.getParentFile();
            } else {
                File[] fs = checkNotNull(src.listFiles());
                for (int i = 0; i < fs.length; i++) {
                    stack.push(fs[i]);
                }

                root = src;
            }
        } else {
            stack.push(src);
            root = src.getParentFile();
        }

        while (!stack.isEmpty()) {
            File f = stack.pop();
            name = toPath(root, f);
            if (f.isDirectory()) {
                File[] fs = checkNotNull(f.listFiles());
                for (int i = 0; i < fs.length; i++) {
                    if (fs[i].isDirectory()) {
                        stack.push(fs[i]);
                    } else {
                        stack.add(0, fs[i]);
                    }
                }
            } else {
                ze = new ZipArchiveEntry(name);
                zos.putArchiveEntry(ze);
                try {
                    fis = new FileInputStream(f);
                    while ((length = fis.read(buf, 0, buf.length)) >= 0) {
                        zos.write(buf, 0, length);
                    }
                } finally {
                    IOUtils.closeQuietly(fis);
                }
                zos.closeArchiveEntry();
            }
        }
        zos.close();
    }

    private static String toPath(File root, File dir) {
        String path = dir.getAbsolutePath();
        path = path.substring(root.getAbsolutePath().length()).replace(File.separatorChar, '/');
        if (path.startsWith("/")) {
            path = path.substring(1);
        }
        if (dir.isDirectory() && !path.endsWith("/")) {
            path += "/";
        }
        return path;
    }

    public static final List<String> EXECUTABLE_EXTENSION = Arrays.asList("bat", "sh");

    /**
     * Untar an input file into an output file.
     * The output file is created in the output folder, having the same name as
     * the input file, minus the '.tar' extension.
     *
     * @param inFile    the input .tar file
     * @param outputDir the output directory file.
     * @return The {@link List} of {@link File}s with the untared content.
     */
    @SuppressWarnings("resource")
    public static List<File> untar(final File inFile, final File outputDir) {
        final List<File> untaredFiles = new LinkedList<File>();
        InputStream is = null;
        TarArchiveInputStream debInputStream = null;
        try {
            is = new FileInputStream(inFile);
            debInputStream = (TarArchiveInputStream) new ArchiveStreamFactory().createArchiveInputStream("tar", is);
            TarArchiveEntry entry;
            while ((entry = (TarArchiveEntry) debInputStream.getNextEntry()) != null) {
                final File outputFile = new File(outputDir, entry.getName());
                if (entry.isDirectory()) {
                    if (!outputFile.exists()) {
                        if (!outputFile.mkdirs()) {
                            throw new IllegalStateException(
                                    String.format("Couldn't create directory %s.", outputFile.getAbsolutePath()));
                        }
                    }
                } else {
                    File parentFile = outputFile.getParentFile();
                    if (!parentFile.exists()) {
                        parentFile.mkdirs();
                    }
                    final OutputStream outputFileStream = new FileOutputStream(outputFile);
                    try {
                        IOUtils.copy(debInputStream, outputFileStream);
                    } finally {
                        IOUtils.closeQuietly(outputFileStream);
                    }

                    if (FilenameUtils.isExtension(outputFile.getName(), EXECUTABLE_EXTENSION)) {
                        outputFile.setExecutable(true, true);
                    }
                    outputFile.setReadable(true);
                    outputFile.setWritable(true, true);
                }
                untaredFiles.add(outputFile);
            }
        } catch (Exception e) {
            throw processException("Error while untar file", e);
        } finally {
            IOUtils.closeQuietly(is);
            IOUtils.closeQuietly(debInputStream);
        }
        return untaredFiles;
    }

    /**
     * Ungzip the given file.
     *
     * @param inFile  file
     * @param outFile to
     * @return ungzipped file.
     */
    public static File ungzip(final File inFile, final File outFile) {
        FileInputStream fin = null;
        BufferedInputStream in = null;
        FileOutputStream fout = null;
        GzipCompressorInputStream gzIn = null;
        try {
            fin = new FileInputStream(inFile);
            in = new BufferedInputStream(fin);
            gzIn = new GzipCompressorInputStream(in);
            if (!outFile.getParentFile().exists()) {
                outFile.getParentFile().mkdirs();
            }
            fout = new FileOutputStream(outFile);
            final byte[] buffer = new byte[4048];
            int n;
            while (-1 != (n = gzIn.read(buffer))) {
                fout.write(buffer, 0, n);
            }
        } catch (Exception e) {
            throw processException("Error while ungzip file", e);
        } finally {
            IOUtils.closeQuietly(fin);
            IOUtils.closeQuietly(in);
            IOUtils.closeQuietly(fout);
            IOUtils.closeQuietly(gzIn);
        }
        return outFile;
    }

    /**
     * Process each jar entry in the  given jar file.
     *
     * @param jarFile   jar file
     * @param processor jar file entry predicate
     * @throws IOException thrown when having IO problem.
     */
    public static void processJarEntries(File jarFile, ZipEntryProcessor processor) {
        try {
            JarFile jarfile = new JarFile(jarFile);
            Enumeration<java.util.jar.JarEntry> enu = jarfile.entries();
            while (enu.hasMoreElements()) {
                JarEntry je = enu.nextElement();
                if (je.isDirectory()) {
                    continue;
                }
                processor.process(jarfile, je);
            }
        } catch (IOException e) {
            throw processException("Error while extracting jar file", e);
        }
    }

    /**
     * Add a file into tar.
     *
     * @param tarStream TarArchive outputStream
     * @param file      file
     * @param path      relative path to append
     * @throws IOException thrown when having IO problem.
     */
    public static void addFileToTar(TarArchiveOutputStream tarStream, File file, String path) throws IOException {
        int mode = file.isDirectory() ? TarArchiveEntry.DEFAULT_DIR_MODE : TarArchiveEntry.DEFAULT_FILE_MODE;
        addFileToTar(tarStream, file, path, mode);
    }

    /**
     * Add a folder into tar.
     *
     * @param tarStream TarArchive outputStream
     * @param path      path to append
     * @throws IOException thrown when having IO problem.
     */
    public static void addFolderToTar(TarArchiveOutputStream tarStream, String path) throws IOException {
        TarArchiveEntry archiveEntry = new TarArchiveEntry(path);
        archiveEntry.setMode(TarArchiveEntry.DEFAULT_DIR_MODE);
        tarStream.putArchiveEntry(archiveEntry);
        tarStream.closeArchiveEntry();
    }

    /**
     * Add the given input stream into tar.
     *
     * @param tarStream   TarArchive outputStream
     * @param inputStream input stream
     * @param path        relative path to append
     * @param size        size of stream
     * @param mode        mode for this entry
     * @throws IOException thrown when having IO problem.
     */
    public static void addInputStreamToTar(TarArchiveOutputStream tarStream, InputStream inputStream, String path,
            long size, int mode) throws IOException {
        TarArchiveEntry entry = new TarArchiveEntry(path);
        entry.setSize(size);
        entry.setMode(mode);
        try {
            tarStream.putArchiveEntry(entry);
            IOUtils.copy(inputStream, tarStream);
        } catch (IOException e) {
            throw processException("Error while adding File to Tar file", e);
        } finally {
            tarStream.closeArchiveEntry();
        }
    }

    /**
     * Add a file into tar.
     *
     * @param tarStream TarArchive outputStream
     * @param file      file
     * @param path      relative path to append
     * @param mode      mode for this entry
     * @throws IOException thrown when having IO problem.
     */
    public static void addFileToTar(TarArchiveOutputStream tarStream, File file, String path, int mode)
            throws IOException {
        TarArchiveEntry entry = new TarArchiveEntry(path);
        entry.setSize(file.length());
        entry.setMode(mode);
        BufferedInputStream bis = null;
        try {
            tarStream.putArchiveEntry(entry);
            bis = new BufferedInputStream(new FileInputStream(file));
            IOUtils.copy(bis, tarStream);
        } catch (IOException e) {
            throw processException("Error while adding File to Tar file", e);
        } finally {
            IOUtils.closeQuietly(bis);
            tarStream.closeArchiveEntry();
        }
    }

    public interface ZipEntryProcessor {
        public void process(ZipFile zipFile, ZipEntry je) throws IOException;
    }

    public interface FilePredicate {
        public boolean evaluate(Object object);
    }
}