org.wso2.carbon.container.ArchiveExtractor.java Source code

Java tutorial

Introduction

Here is the source code for org.wso2.carbon.container.ArchiveExtractor.java

Source

/*
 *  Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
 *
 *  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.wso2.carbon.container;

import org.apache.commons.compress.archivers.ArchiveEntry;
import org.apache.commons.compress.archivers.ArchiveInputStream;
import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
import org.apache.commons.compress.archivers.zip.ZipArchiveInputStream;
import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.ops4j.pax.exam.TestContainerException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URL;
import java.nio.file.Path;

/**
 * Extract zip or tar.gz archives to a target Directory.
 *
 * @since 5.2.0
 */
public class ArchiveExtractor {

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

    private ArchiveExtractor() {
    }

    /**
     * Extract zip or tar.gz specified by maven url to a target Directory.
     *
     * @param sourceURL       url of the archive to extract
     * @param targetDirectory where to extract to
     * @throws IOException on I/O error
     */
    public static void extract(URL sourceURL, File targetDirectory) throws IOException {
        if (Constants.FILE_PROTOCOL.equals(sourceURL.getProtocol())) {
            String file = sourceURL.getFile();
            if (file.endsWith("." + Constants.ZIP_EXTENSION)) {
                extractZipDistribution(sourceURL, targetDirectory);
            } else if (file.endsWith("." + Constants.TARGZ_EXTENSION)) {
                extractTarGzDistribution(sourceURL, targetDirectory);
            } else {
                throw new TestContainerException(
                        "Unknown packaging of distribution; only zip or tar.gz could be handled.");
            }
            return;
        }
        if (sourceURL.toExternalForm().endsWith("/" + Constants.ZIP_EXTENSION)) {
            extractZipDistribution(sourceURL, targetDirectory);
        } else if (sourceURL.toExternalForm().endsWith("/" + Constants.TARGZ_EXTENSION)) {
            extractTarGzDistribution(sourceURL, targetDirectory);
        } else {
            throw new TestContainerException(
                    "Unknown packaging; only zip or tar.gz could be handled. URL was " + sourceURL);
        }
    }

    /**
     * Extract zip file in the system to a target Directory.
     *
     * @param path            path of the archive to be extract
     * @param targetDirectory where to extract to
     * @throws IOException on I/O error
     */
    public static void extract(Path path, File targetDirectory) throws IOException {
        if (path.toString().endsWith("." + Constants.ZIP_EXTENSION)) {
            extract(new ZipArchiveInputStream(new FileInputStream(path.toFile())), targetDirectory);
        } else {
            throw new TestContainerException("Unknown packaging of distribution; only zip can be handled.");
        }
    }

    /**
     * Extract tar.gz specified by url to target.
     *
     * @param sourceDistribution url of the archive
     * @param targetDirectory    path of the target
     * @throws IOException
     */
    private static void extractTarGzDistribution(URL sourceDistribution, File targetDirectory) throws IOException {
        File uncompressedFile = File.createTempFile(Constants.TEMPFILEPREFIX, "." + Constants.TAR_EXTENSION);
        extractGzArchive(sourceDistribution, uncompressedFile);
        extract(new TarArchiveInputStream(new FileInputStream(uncompressedFile)), targetDirectory);
        FileUtils.forceDelete(uncompressedFile);
    }

    /**
     * Extract zip specified by url to target.
     *
     * @param sourceDistribution url of the archive
     * @param targetDirectory    path of the target
     * @throws IOException
     */
    private static void extractZipDistribution(URL sourceDistribution, File targetDirectory) throws IOException {
        extract(new ZipArchiveInputStream(sourceDistribution.openStream()), targetDirectory);
    }

    private static void extractGzArchive(URL sourceDistribution, File tar) throws IOException {
        try (BufferedInputStream in = new BufferedInputStream(sourceDistribution.openStream());
                FileOutputStream out = new FileOutputStream(tar);
                GzipCompressorInputStream gzIn = new GzipCompressorInputStream(in)) {
            final byte[] buffer = new byte[1000];
            int n;
            while (-1 != (n = gzIn.read(buffer))) {
                out.write(buffer, 0, n);
            }
        }
    }

    /**
     * Extract the file and create directories accordingly.
     *
     * @param is        pass the stream, because the stream is different for various file types
     * @param targetDir target directory
     * @throws IOException
     */
    private static void extract(ArchiveInputStream is, File targetDir) throws IOException {
        try {
            if (targetDir.exists()) {
                FileUtils.forceDelete(targetDir);
            }
            createDirectory(targetDir);
            ArchiveEntry entry = is.getNextEntry();
            while (entry != null) {
                String name = entry.getName();
                name = name.substring(name.indexOf("/") + 1);
                File file = new File(targetDir, name);
                if (entry.isDirectory()) {
                    createDirectory(file);
                } else {
                    createDirectory(file.getParentFile());
                    OutputStream os = new FileOutputStream(file);
                    try {
                        IOUtils.copy(is, os);
                    } finally {
                        IOUtils.closeQuietly(os);
                    }
                }
                entry = is.getNextEntry();
            }
        } finally {
            try {
                is.close();
            } catch (IOException e) {
                logger.warn("Error occurred while closing the stream", e);
            }
        }
    }

    /**
     * Create directory if not exists.
     *
     * @param directory directory object
     */
    private static void createDirectory(File directory) {
        boolean isCreated = true;
        if (!directory.exists()) {
            isCreated = directory.mkdirs();
        }

        if (!isCreated) {
            throw new TestContainerException("Couldn't create the directory: " + directory.toString());
        }
    }
}