org.jboss.windup.util.RecursiveZipMetaFactory.java Source code

Java tutorial

Introduction

Here is the source code for org.jboss.windup.util.RecursiveZipMetaFactory.java

Source

/*
 * Copyright (c) 2013 Red Hat, Inc. and/or its affiliates.
 *  
 *  All rights reserved. This program and the accompanying materials
 *  are made available under the terms of the Eclipse Public License v1.0
 *  which accompanies this distribution, and is available at
 *  http://www.eclipse.org/legal/epl-v10.html
 *  
 *  Contributors:
 *      Brad Davis - bradsdavis@gmail.com - Initial API and implementation
*/
package org.jboss.windup.util;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jboss.windup.metadata.type.archive.ZipMetadata;

/**
 *  Custom implementation of zip archive extraction.
 */
public class RecursiveZipMetaFactory {
    private static final Log LOG = LogFactory.getLog(RecursiveZipMetaFactory.class);

    private static final int BUFFER = 2048;

    /** The directory to extract to. */
    private File startLocation;

    public RecursiveZipMetaFactory(File startLocation, Set<String> extensions) {
        UUID uuidKey = UUID.randomUUID();
        safeExtractKey = "_" + StringUtils.substring(StringUtils.remove(uuidKey.toString(), "-"), 0, 6);

        this.startLocation = new File(
                startLocation.getAbsolutePath() + File.separator + "jboss_windup" + safeExtractKey);
        this.kae = extensions;
    }

    private final String safeExtractKey;
    private Set<String> kae = new HashSet<String>();

    public void releaseTempFiles() {
        LOG.debug("Cleaning up: " + this.startLocation.getAbsolutePath());
        FileUtils.deleteQuietly(this.startLocation);
    }

    public ZipMetadata recursivelyExtract(ZipFile zip) {

        if (LOG.isDebugEnabled()) {
            LOG.debug(zip.getName() + ": " + this.startLocation.getAbsolutePath());
        }
        ZipMetadata archive = generateArchive(null, new File(zip.getName()));
        recursivelyExtract(archive, zip, this.startLocation);

        return archive;
    }

    protected void recursivelyExtract(ZipMetadata parent, ZipFile zip, File outputDirectory) {
        String fileName = StringUtils.substringAfterLast(zip.getName(), File.separator);
        File subOutputDir = new File(outputDirectory.getAbsolutePath() + File.separator + fileName);
        ZipEntry entry;

        Enumeration<?> e = zip.entries();
        while (e.hasMoreElements()) {
            entry = (ZipEntry) e.nextElement();
            // must be a candidate file.
            if (!entry.isDirectory()) {
                if (archiveEndInEntryOfInterest(entry.getName())) {
                    try {
                        File extracted = unzipEntry(parent, entry, zip, subOutputDir);
                        ZipFile zf = new ZipFile(extracted);

                        // we should know it is a valid zip here..
                        ZipMetadata arch = generateArchive(parent, extracted);
                        LOG.info("Prepared ZipMetadata: " + arch.getRelativePath());
                        recursivelyExtract(arch, zf,
                                new File(StringUtils.substringBeforeLast(zf.getName(), File.separator)));
                    } catch (FileNotFoundException e1) {
                        LOG.warn("Skipping invalid zip entry: " + entry);
                    } catch (IOException e1) {
                        LOG.warn("Skipping invalid zip entry: " + entry);
                    }
                }
            }
        }
        try {
            zip.close();
        } catch (IOException e1) {
            LOG.error("Exception closing zip.", e1);
        }
    }

    protected File unzipEntry(ZipMetadata parent, ZipEntry entry, ZipFile zipfile, File archiveOutputDirectory) {
        BufferedOutputStream dest = null;
        BufferedInputStream is = null;
        String pathOutput = null;
        if (StringUtils.contains(entry.toString(), "/")) {
            pathOutput = StringUtils.substringBeforeLast(entry.toString(), "/");
        } else {
            pathOutput = File.separator;
        }
        File entryPathOutput = new File(
                archiveOutputDirectory.getAbsolutePath() + safeExtractKey + File.separator + pathOutput);
        File entryOutput = new File(
                archiveOutputDirectory.getAbsolutePath() + safeExtractKey + File.separator + entry);
        if (!entryOutput.exists()) {
            try {
                FileUtils.forceMkdir(entryPathOutput);
                is = new BufferedInputStream(zipfile.getInputStream(entry));
                if (LOG.isDebugEnabled()) {
                    LOG.debug("Unzipping: " + entryOutput.getAbsolutePath());
                }

                int count;
                byte data[] = new byte[BUFFER];
                FileOutputStream fos = new FileOutputStream(entryOutput);
                dest = new BufferedOutputStream(fos, BUFFER);

                while ((count = is.read(data, 0, BUFFER)) != -1) {
                    dest.write(data, 0, count);
                }
                dest.flush();

                return entryOutput;
            } catch (IOException e) {
                LOG.error(e);
            } finally {
                IOUtils.closeQuietly(is);
                IOUtils.closeQuietly(dest);
            }
        } else {
            LOG.warn("Entry: " + entry.toString() + " is a duplicate.  Returning the first entry.");
            return entryOutput;
        }

        return null;

    }

    private boolean archiveEndInEntryOfInterest(String entryName) {
        for (String extension : kae) {
            if (StringUtils.endsWith(entryName, extension)) {
                return true;
            }
        }
        return false;
    }

    private ZipMetadata generateArchive(ZipMetadata parent, File entryOutput) {
        String relativePath = StringUtils.removeStart(entryOutput.getAbsolutePath(),
                this.startLocation.getAbsolutePath().toString());

        if (LOG.isTraceEnabled()) {
            LOG.trace("RE Relative Path: " + relativePath);
            LOG.trace("SafeKey: " + safeExtractKey);
        }

        relativePath = StringUtils.replace(relativePath, "\\", "/");
        relativePath = StringUtils.removeStart(relativePath, "/");

        if (StringUtils.contains(relativePath, this.safeExtractKey)) {
            // all subarchives of the target archive will get copied to a location with the safeExtractKey.
            relativePath = StringUtils.remove(relativePath, this.safeExtractKey);
        } else {
            // otherwise, we know it is the original file...
            relativePath = StringUtils.substringAfterLast(relativePath, "/");
        }

        String archiveName = relativePath;
        if (StringUtils.contains(archiveName, "/")) {
            archiveName = StringUtils.substringAfterLast(relativePath, "/");
        }

        ZipMetadata archive = new ZipMetadata();
        archive.setName(archiveName);
        archive.setFilePointer(entryOutput);
        archive.setRelativePath(relativePath);

        if (parent != null) {
            parent.getNestedArchives().add(archive);
        }

        archive.setArchiveMeta(parent);

        if (LOG.isTraceEnabled()) {
            LOG.trace("Created archive: " + archive.toString());
        }
        return archive;
    }
}