Package org.rioproject.impl.util

Source Code of org.rioproject.impl.util.DownloadManager

/*
* Copyright 2008 the original author or authors.
*
* 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.rioproject.impl.util;

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.tar.TarArchiveEntry;
import org.apache.commons.compress.utils.IOUtils;
import org.rioproject.deploy.DownloadRecord;
import org.rioproject.deploy.StagedData;
import org.rioproject.deploy.StagedSoftware;
import org.rioproject.deploy.StagedSoftware.PostInstallAttributes;
import org.rioproject.exec.ExecDescriptor;
import org.rioproject.impl.exec.ProcessManager;
import org.rioproject.impl.exec.ServiceExecutor;
import org.rioproject.impl.exec.Util;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.Date;
import java.util.Enumeration;
import java.util.List;
import java.util.zip.GZIPInputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipException;
import java.util.zip.ZipFile;

/**
* The DownloadManager class provides support to manage the download and
* installation of artifacts
*
* @author Dennis Reedy
*/
public class DownloadManager {
    /** The root directory to download the software */
    private String installPath;
    /** The Download */
    private StagedData stagedData;
    /** The DownloadRecord of the downloaded software */
    private DownloadRecord downloadRecord;
    /** The post-install DownloadRecord */
    private DownloadRecord postInstallRecord;
    /** The files extracted during post-install */
    private List<File> postInstallExtractList;
    private boolean showDownloadTo = true;
    /** A suitable Logger */
    private static final Logger logger = LoggerFactory.getLogger(DownloadManager.class.getName());

    /**
     * Create an instance of the DownloadManager
     *
     * @param stagedData The Download
     */
    public DownloadManager(StagedData stagedData) {
        if(stagedData == null)
            throw new IllegalArgumentException("stagedData is null");
        this.stagedData = stagedData;
    }

    /**
     * Create an instance of the DownloadManager
     *
     * @param installPath The root directory to download the software. If the
     * directory does not exist, it will be created. Read and write access
     * permissions are required to the directory
     * @param stagedData The Download
     */
    public DownloadManager(String installPath, StagedData stagedData) {
        if(installPath == null)
            throw new IllegalArgumentException("installPath is null");
        if(stagedData == null)
            throw new IllegalArgumentException("stagedData is null");
        this.installPath = installPath;
        this.stagedData = stagedData;
    }

    /**
     * Performs software download for a Download
     *
     * @return The DownloadRecord based on
     * attributes from the downloaded software
     *
     * @throws IOException if there are errors accessing the file system
     */
    public DownloadRecord download() throws IOException {
        if(downloadRecord != null)
            return (downloadRecord);
        return doDownload(stagedData, false);
    }

    /**
     * Whether to emit logger statements documenting where the data is being
     * downloaded to
     *
     * @param show If true emit (default)
     */
    public void setShowDownloadTo(boolean show) {
        this.showDownloadTo= show;
    }

    /*
     * Performs software stagedData for StagedData
     *
     * @param dAttrs The StagedData
     * @param postInstall Whether this is for the post-install task
     * @return The DownloadRecord based on
     * attributes from the downloaded software.
     *
     * @throws IOException if there are errors accessing the file system
     */
    private DownloadRecord doDownload(StagedData dAttrs, boolean postInstall) throws IOException {
        String installRoot  ;
        int extractedSize = 0;
        long extractTime = 0;
        boolean unarchived = false;
        boolean createdTargetPath = false;

        if(dAttrs == null)
            throw new IllegalArgumentException("dAttrs is null");

        URL location = dAttrs.getLocationURL();
        String extension = dAttrs.getInstallRoot();
        boolean unarchive = dAttrs.unarchive();
        if(extension.indexOf("/") != -1)
            installRoot = extension.replace('/', File.separatorChar);
        else
            installRoot = extension.replace('\\', File.separatorChar);
        File targetPath = new File(FileUtils.makeFileName(installPath, installRoot));
        if(!targetPath.exists()) {
            if(targetPath.mkdirs()) {
                logger.trace("Created {}", targetPath.getPath());
            }
            if(!targetPath.exists())
                throw new IOException("Failed to create: " + installPath);
            createdTargetPath = true;
        }
        if(!targetPath.canWrite())
            throw new IOException("Can not write to : " + installPath);
        String source = location.toExternalForm();
        int index = source.lastIndexOf("/");
        if(index == -1)
            throw new IllegalArgumentException("Don't know how to install : "+ source);
        String software = source.substring(index + 1);
        String target = FileUtils.getFilePath(targetPath);
        File targetFile = new File(FileUtils.makeFileName(target, software));
        if (targetFile.exists()) {
            if(!dAttrs.overwrite()) {
                logger.warn("{} exists, stagedData attributes indicate to not overwrite file",
                            FileUtils.getFilePath(targetFile));
                return null;
            } else {
                if(showDownloadTo)
                    logger.info("Overwriting {} with {}", FileUtils.getFilePath(targetFile), location);
            }
        } else {
            if(showDownloadTo)
                logger.info("Downloading {} to {}", location, FileUtils.getFilePath(targetFile));
        }
        long t0 = System.currentTimeMillis();
        URLConnection con = location.openConnection();
        int downloadedSize = writeFileFromInputStream(con.getInputStream(),
                                                      targetFile,
                                                      con.getContentLength(),
                                                      System.console()!=null);
        long t1 = System.currentTimeMillis();
        long downloadTime = t1 - t0;
        long downloadSecs = downloadTime/1000;
        Date downloadDate = new Date();
        ExtractResults results;
        logger.info("Wrote {}K in {} seconds", (downloadedSize/1024), (downloadSecs<1?"< 1":downloadSecs));
        String extractedToPath = null;
        if(unarchive) {
            t0 = System.currentTimeMillis();
            results = extract(targetPath, targetFile);
            t1 = System.currentTimeMillis();
            extractedSize = results.extractedSize;
            if(postInstall)
                postInstallExtractList = results.postInstallExtractList;
            extractTime = t1 - t0;
            unarchived = true;
            extractedToPath = results.extractedToPath;
            if(extractedToPath==null) {
                extractedToPath = FileUtils.getFilePath(targetPath);
            }
        }
        downloadRecord = new DownloadRecord(location,
                                            target,
                                            software,
                                            downloadDate,
                                            downloadedSize,
                                            extractedSize,
                                            extractedToPath,
                                            unarchived,
                                            downloadTime,
                                            extractTime);
        downloadRecord.setCreatedParentDirectory(createdTargetPath);
        return (downloadRecord);
    }

    /**
     * Given an InputStream this method will write the contents to the desired
     * File.
     *
     * @param in InputStream
     * @param file The File object to write to
     * @param total The total length
     * @param show Whether to print out progress
     *
     * @return The size of what was written
     *
     * @throws IOException if there are errors accessing the file system
     */
    private static int writeFileFromInputStream(InputStream in, File file, long total, boolean show) throws IOException {
        int totalWrote = 0;
        OutputStream out = null;
        try {
            out = new FileOutputStream(file);
            int read;
            byte[] buf = new byte[2048];
            while((read = in.read(buf)) != -1) {
                out.write(buf, 0, read);
                totalWrote += read;
                if (show)
                    showTransferStatus(total, totalWrote);
            }
            if(show) {
                String l = total >= 1024 ? ( total / 1024 ) + "K" : total + "b";
                logger.info( l + " downloaded ("+file.getName()+")");
            }
        } catch(FileNotFoundException e) {
            // catch so we can delete the file
            if(file.delete()) {
                logger.trace("Deleted {}", file.getName());
            }
            throw e;
        } catch(IOException e) {
            // catch so we can delete the file
            if(file.delete()) {
                logger.trace("Deleted {}", file.getName());
            }
            throw e;
        } finally {
            try {
                if(in != null)
                    in.close();
            } catch(IOException e) {
                e.printStackTrace();
            }
            try {
                if(out != null)
                    out.close();
            } catch(IOException e) {
                e.printStackTrace();
            }
        }
        return (totalWrote);
    }

    private static void showTransferStatus(long total, long complete) {
        if (total >= 1024) {
            System.out.print((complete/1024)+"/"+(total==-1?"?":(total/1024)+"K" )+"\r");
        } else {
            System.out.print(complete+"/"+(total==-1 ?"?":total+"b")+"\r" );
        }
    }

    /**
     * Extract an archive
     *
     * @param directory the directory to extract to
     * @param archive The archive to extract
     *
     * @return An ExtractResults class detailing what was extracted
     *
     * @throws IOException if there are errors extracting the archive
     */
    @SuppressWarnings("PMD.AvoidReassigningParameters")
    public static ExtractResults extract(File directory, File archive) throws IOException {

        String extractedToPath = null;
        int extractSize = 0;
        ZipFile zipFile = null;
        List<File> extractList = new ArrayList<File>();
        if(archive.getName().endsWith(".gz") ||
           archive.getName().endsWith(".gzip")) {
            archive = dealWithGZIP(archive);
        }
        if(archive.getName().endsWith("tar")) {
            unTar(archive, directory);
            return (new ExtractResults(extractedToPath,
                                       extractSize,
                                       extractList));
        }
        try {
            zipFile = new ZipFile(archive);
            Enumeration zipEntries = zipFile.entries();
            while(zipEntries.hasMoreElements()) {
                ZipEntry zipEntry = (ZipEntry)zipEntries.nextElement();
                if(zipEntry.isDirectory()) {
                    File file = makeChildFile(directory, zipEntry.getName());
                    if(file.mkdirs()) {
                        logger.trace("Created {}", file.getPath());
                    }
                    if(extractedToPath==null) {
                        extractedToPath = getExtractedToPath(file, directory);
                    }
                } else {
                    File file = makeChildFile(directory, zipEntry.getName());
                    //System.out.println("Writing : "+file.getCanonicalPath());
                    extractList.add(file);
                    String fullPath = FileUtils.getFilePath(file);
                    int index = fullPath.lastIndexOf(File.separatorChar);
                    String installPath = fullPath.substring(0, index);
                    File targetPath = new File(installPath);
                    if(!targetPath.exists()) {
                        if(targetPath.mkdirs()) {
                            logger.trace("Created {}", file.getPath());
                        }
                        if(!targetPath.exists())
                            throw new IOException("Failed to create : "+ installPath);
                    }
                    if(!targetPath.canWrite())
                        throw new IOException("Can not write to : "+ installPath);
                    InputStream in = zipFile.getInputStream(zipEntry);
                    extractSize += writeFileFromInputStream(in, file, archive.length(), false);
                }
            }
        } finally {
            if(zipFile != null)
                zipFile.close();
        }
        return (new ExtractResults(extractedToPath, extractSize, extractList));
    }

    @SuppressWarnings("PMD.AvoidReassigningParameters")
    private static String getExtractedToPath(File path, File rootDir) {
        File parent;
        do {
            parent = path.getParentFile();
            if(parent==null) {
                logger.warn("No parent for {}", FileUtils.getFilePath(path));
                break;
            }
            if(!parent.equals(rootDir))
                path = parent;
        } while(!parent.equals(rootDir));

        return FileUtils.getFilePath(path);
    }

    private static File makeChildFile(File parent, String name) {
        return new File(parent, name);
    }

    private static File dealWithGZIP(File gzip) throws IOException {
        int ndx = gzip.getName().lastIndexOf(".");
        File output = new File(gzip.getParentFile().getPath(),
                               gzip.getName().substring(0, ndx));
        GZIPInputStream gzipInputStream = new GZIPInputStream(new FileInputStream(gzip));
        logger.info("Writing {} ...", FileUtils.getFilePath(output));
        long t0 = System.currentTimeMillis();

        int downloadedSize = writeFileFromInputStream(gzipInputStream, output, gzip.length(), System.console()!=null);
        long t1 = System.currentTimeMillis();
        long downloadTime = t1 - t0;
        long downloadSecs = downloadTime/1000;
        logger.info("Wrote {}K in {} millis", (downloadedSize/1024), (downloadSecs<1?"< 1":downloadSecs));

        return output;
    }

    private static void unTar(File tarFile, File target) throws IOException {
        InputStream is = new FileInputStream(tarFile);
        ArchiveInputStream in;
        try {
            in = new ArchiveStreamFactory().createArchiveInputStream("tar", is);
        } catch (ArchiveException e) {
            IOException ioe = new IOException("Unarchving "+tarFile.getName());
            ioe.initCause(e);
            throw ioe;
        }
        try {
            TarArchiveEntry entry;
            while((entry = (TarArchiveEntry)in.getNextEntry())!=null) {
                File f = new File(target, entry.getName());
                if(entry.isDirectory()) {
                    if(f.mkdirs()) {
                        logger.trace("Created directory {}", f.getPath());
                    }
                } else {
                    if(!f.getParentFile().exists()) {
                        if(f.getParentFile().mkdirs()) {
                            logger.trace("Created {}", f.getParentFile().getPath());
                        }
                    }
                    if(f.createNewFile()) {
                        logger.trace("Created {}", f.getName());
                    }
                    OutputStream out = new FileOutputStream(f);
                    IOUtils.copy(in, out);
                    out.close();
                }
                setPerms(f, entry.getMode());
            }
        } finally {
            in.close();
        }
    }

    private static void setPerms(File f, int mode) {
        String jvmVersion = System.getProperty("java.version");
        if(jvmVersion.contains("1.5"))
            return;
       
        int ownerPerm = mode >> 6 & 007;
        int groupPerm = mode >> 3 & 007;
        int userPerm = mode & 007;

        /* Check read */
        boolean ownerOnly = true;
        if(userPerm>=4) {
            userPerm-=4;
            ownerOnly = false;
        }
        if(groupPerm>=4) {
            groupPerm-=4;
            ownerOnly = false;
        }
        if(ownerPerm>=4) {
            ownerPerm-=4;
            setFileAccess(f, "setReadable", true, ownerOnly);
        }
        /* Check write */
        ownerOnly = true;
        if(userPerm>=2) {
            userPerm-=2;
            ownerOnly = false;
        }
        if(groupPerm>=2) {
            groupPerm-=2;
            ownerOnly = false;
        }
        if(ownerPerm>=2) {
            ownerPerm-=2;
            setFileAccess(f, "setWritable", true, ownerOnly);
        }
        /* Check execute */
        ownerOnly = true;
        if(userPerm==1 || groupPerm==1)
            ownerOnly = false;
        if(ownerPerm==1) {
            setFileAccess(f, "setExecutable", true, ownerOnly);
        }       
    }

    /*
     * Use reflection so this can be compiled using 1.5
     */
    private static void setFileAccess(File f,
                                      String setter,
                                      boolean allow,
                                      boolean ownerOnly) {
        try {
            Method m = f.getClass().getMethod(setter, boolean.class, boolean.class);
            m.invoke(f, allow, ownerOnly);
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    private static void removeExtractedTarFiles(File root, File tarFile) throws IOException {
        InputStream is = new FileInputStream(tarFile);
        ArchiveInputStream in;
        try {
            in = new ArchiveStreamFactory().createArchiveInputStream("tar", is);
        } catch (ArchiveException e) {
            IOException ioe = new IOException("Removing "+tarFile.getName());
            ioe.initCause(e);
            throw ioe;
        }
        File parent = null;
        try {
            TarArchiveEntry entry;
            while((entry = (TarArchiveEntry)in.getNextEntry())!=null) {
                File f = new File(root, entry.getName());
                if(parent==null) {
                    parent = new File(getExtractedToPath(f, root));
                }
                FileUtils.remove(f);

            }
        } finally {
            in.close();
        }
        FileUtils.remove(parent);
    }

    /*
     * Container class holding results of the extract
     */
    public static class ExtractResults {
        String extractedToPath;
        int extractedSize;
        List<File> postInstallExtractList;

        ExtractResults(String extractedToPath,
                       int extractedSize,
                       List<File>postInstallExtractList) {
            this.extractedToPath = extractedToPath;
            this.extractedSize = extractedSize;
            this.postInstallExtractList = postInstallExtractList;
        }
    }

    /**
     * Perform post-install task(s) as described by the StagedSoftware object
     *
     * @return A DownloadRecord for the post
     * install if software was downloaded to perform the post install task(s).
     * If no software was downloaded to perform the task(s), return null
     *
     * @throws IOException if there are errors accessing the file system
     */
    public DownloadRecord postInstall() throws IOException {
        if(downloadRecord == null)
            throw new IllegalStateException("software has not been downloaded");
        if(!(stagedData instanceof StagedSoftware))
            return null;
        PostInstallAttributes postInstall =
            ((StagedSoftware) stagedData).getPostInstallAttributes();
        if(postInstall == null)
            return (null);
        String path = downloadRecord.getPath();
        try {
            StagedData dAttrs = postInstall.getStagedData();
            if(dAttrs != null) {
                postInstallRecord = doDownload(dAttrs, true);
                path = postInstallRecord.getPath();
            }
            ExecDescriptor execDesc = postInstall.getExecDescriptor();
            if(execDesc != null) {
                if(!execDesc.getCommandLine().startsWith(File.separator))
                    execDesc = Util.extendCommandLine(path, execDesc);
                ServiceExecutor svcExecutor = new ServiceExecutor();
                ProcessManager manager = svcExecutor.exec(execDesc);
                manager.manage();
                //manager.waitFor();
                manager.destroy(false);
            }
            if(postInstall.getStagedData()!=null &&
               postInstall.getStagedData().removeOnDestroy()) {
                if(postInstallRecord != null) {
                    FileUtils.remove(new File(FileUtils.makeFileName(postInstallRecord.getPath(),
                                                 postInstallRecord.getName())));
                }
                if(postInstallExtractList != null) {
                    for (File file : postInstallExtractList)
                        FileUtils.remove(file);
                }
            }
        } catch(IOException e) {
            if(postInstallRecord != null)
                remove(postInstallRecord);
            throw e;
        }
        return (postInstallRecord);
    }

    /**
     * Remove installed software
     */
    public void remove() {
        if(downloadRecord == null)
            throw new IllegalStateException("software has not been downloaded");
        remove(downloadRecord);
        if(postInstallRecord != null)
            remove(postInstallRecord);
    }

    /**
     * Remove installed software
     *
     * @param record The DownloadRecord to remove
     *
     * @return the top-most directory/file that was removed
     */
    public static String remove(DownloadRecord record) {
        if(record == null)
            throw new IllegalArgumentException("record is null");
        File software = new File(FileUtils.makeFileName(record.getPath(),
                                                        record.getName()));
        if(!software.exists()) {
            logger.debug("Software recorded at [{}] does not exist or has already been removed "+
                            "from the file system, removal aborted", FileUtils.getFilePath(software));
            return null;
        }
        String removed;
        if(record.unarchived()) {
            if(software.getName().endsWith(".gz") || software.getName().endsWith(".gzip")) {
                FileUtils.remove(software);
                /* Strip off the extension and see if we still have
                 * something to remove */
                int ndx = software.getName().lastIndexOf(".");
                if(ndx!=-1) {
                    String newName = software.getName().substring(0, ndx);
                    software = new File(FileUtils.makeFileName(record.getPath(), newName));
                }
            }
            if(software.getName().endsWith("tar")) {
                try {
                    File root = new File(record.getPath());
                    removeExtractedTarFiles(root, software);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            } else {
                ZipFile zipFile = null;
                try {
                    zipFile = new ZipFile(software);
                    Enumeration zipEntries = zipFile.entries();
                    while(zipEntries.hasMoreElements()) {
                        ZipEntry zipEntry = (ZipEntry)zipEntries.nextElement();
                        File file = new File(record.getPath() + File.separator
                                             + zipEntry.getName());
                        FileUtils.remove(file);
                    }
                } catch (ZipException e) {
                    logger.error("Error in opening zip file {}", FileUtils.getFilePath(software), e);
                } catch(Exception e) {
                    e.printStackTrace();
                } finally {
                    if(zipFile!=null) {
                        try {
                            zipFile.close();
                        } catch (IOException e) {
                            logger.error("Could not close zip file", e);
                        }
                    }
                }
            }
            removed = FileUtils.getFilePath(software);
            FileUtils.remove(software);
            File softwareDirectory = new File(record.getPath());
            String[] list = softwareDirectory.list();
            if(list.length == 0
                    && !softwareDirectory.getName().equals("native"))
                FileUtils.remove(softwareDirectory);
        } else {
            if(record.createdParentDirectory()) {
                removed = record.getPath();
                FileUtils.remove(new File(record.getPath()));
            } else {
                removed = FileUtils.getFilePath(software);
                FileUtils.remove(software);
            }
        }

        return removed;
    }

    public static void main(String args[]) {
        try {
            if(args.length < 2) {
                System.out.println(
                    "Usage: org.rioproject.impl.util.DownloadManager " +
                    "download-URL install-root");
                System.exit(-1);
            }
            String downloadFrom = args[0];
            String installPath = args[1];
            System.setSecurityManager(new java.rmi.RMISecurityManager());
            StagedSoftware download = new StagedSoftware();
            download.setLocation(downloadFrom);
            download.setInstallRoot(installPath);
            download.setUnarchive(true);
            DownloadManager slm = new DownloadManager(installPath, download);
            DownloadRecord record = slm.download();
            System.out.println("Details");
            System.out.println("-------");
            System.out.println(record.toString());
            //DownloadManager.remove(record);
        } catch(Throwable throwable) {
            throwable.printStackTrace();
        }
    }
}
TOP

Related Classes of org.rioproject.impl.util.DownloadManager

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.