org.eclipse.thym.core.internal.util.FileUtils.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.thym.core.internal.util.FileUtils.java

Source

/*******************************************************************************
 * Copyright (c) 2013, 2015 Red Hat, Inc. 
 * 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:
 *        Red Hat Inc. - initial API and implementation and/or initial documentation
 *******************************************************************************/
package org.eclipse.thym.core.internal.util;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.channels.Channels;
import java.nio.channels.FileChannel;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Enumeration;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

import org.apache.commons.io.filefilter.TrueFileFilter;
import org.apache.commons.io.filefilter.WildcardFileFilter;
import org.eclipse.core.runtime.FileLocator;

/**
 * Utilities for working with files on the file system and inside bundles.
 * 
 * @author Gorkem Ercan
 *
 */
public final class FileUtils {
    private FileUtils() {
        //No instances
    }

    /**
     * Copies the contents for source directory to destination directory. 
     * Source can be a directory on the file system or a jar file.
     * Destination is a directory on the files system 
     * 
     * @param source - directory on the file system or jar file
     * @param destination - a directory on the file system
     * @throws IllegalArgumentException 
     *       <ul>
     *          <li>source or destination is null or not a file</li>
     *        <li>destination is not a file URL</li>
     *     </ul>
     */
    public static void directoryCopy(URL source, URL destination) throws IOException {
        checkCanCopy(source, destination);

        source = getFileURL(source);
        destination = getFileURL(destination);
        File dstFile = new File(destination.getFile());
        if (!dstFile.exists() && !dstFile.mkdir()) {
            return;
        }

        if ("file".equals(source.getProtocol())) {
            File srcFile = new File(source.getFile());
            copyFile(srcFile, dstFile);

        } else if ("jar".equals(source.getProtocol())) {
            ZipFile zipFile = getZipFile(source);
            String file = source.getFile();
            int exclamation = file.indexOf('!');
            String jarLocation = file.substring(exclamation + 2); // "/some/path/"
            copyFromZip(zipFile, jarLocation, dstFile);
        }

    }

    /**
     * Copies the contents of source file to the destination file.
     * Source can be a file on the file system or a jar file.
     * Destination is a file on the file system. If destination
     * already exists this method does nothing.
     * 
     * @param source - file on the file system or jar file
     * @param destination - a file on the file system
     * @throws IOException
     * @throws IllegalArgumentException 
     *       <ul>
     *          <li>source or destination is null or not a file</li>
     *        <li>destination is not a file URL</li>
     *     </ul>
     */
    public static void fileCopy(URL source, URL destination) throws IOException {
        checkCanCopy(source, destination);

        source = getFileURL(source);
        destination = getFileURL(destination);
        File dstFile = new File(destination.getFile());
        if (dstFile.exists()) {
            return; //already exists
        } else {
            if (!dstFile.getParentFile().exists() && !dstFile.getParentFile().mkdirs()) {
                return;// not able to create parent
            }
            if (!dstFile.createNewFile()) {
                return;// not able to create file
            }
        }

        if ("file".equals(source.getProtocol())) {
            File srcFile = new File(source.getFile());
            copyFile(srcFile, dstFile);

        } else if ("jar".equals(source.getProtocol())) {
            ZipFile zipFile = getZipFile(source);
            String file = source.getFile();
            int exclamation = file.indexOf('!');
            String jarLocation = file.substring(exclamation + 2); // remove jar separator !/ 
            copyFromZip(zipFile, jarLocation, dstFile);
        }

    }

    /**
     * Copies the contents of a source file to the destination file. 
     * It replaces the value pairs passed on the templatesValues while 
     * copying. 
     * 
     * @param source  file on the file system or jar file
     * @param destination file on the file system
     * @param templateValues value pairs to be replaced
     * @throws IOException
     * @throws IllegalArgumentException 
     *       <ul>
     *          <li>source or destination is null or not a file</li>
     *        <li>destination is not a file URL</li>
     *     </ul>    
     */
    public static void templatedFileCopy(URL source, URL destination, Map<String, String> templateValues)
            throws IOException {
        checkCanCopy(source, destination);
        if (templateValues == null)
            throw new IllegalArgumentException("Template values can not be null");

        source = getFileURL(source);
        destination = getFileURL(destination);
        File dstFile = new File(destination.getFile());
        BufferedReader in = null;
        BufferedWriter out = null;
        try {
            out = new BufferedWriter(new FileWriter(dstFile));

            if ("file".equals(source.getProtocol())) {
                File srcFile = new File(source.getFile());
                in = new BufferedReader(new FileReader(srcFile));
            } else if ("jar".equals(source.getProtocol())) {
                ZipFile zipFile = getZipFile(source);
                String file = source.getFile();
                int exclamation = file.indexOf('!');
                String jarLocation = file.substring(exclamation + 2); // remove jar separator !/ 
                ZipEntry zipEntry = zipFile.getEntry(jarLocation);
                if (zipEntry == null) {
                    throw new IllegalArgumentException(source + " can not be found on the zip file");
                }
                InputStream zipStream = zipFile.getInputStream(zipEntry);
                in = new BufferedReader(new InputStreamReader(zipStream));
            }

            String line;
            while ((line = in.readLine()) != null) {
                for (Map.Entry<String, String> entry : templateValues.entrySet()) {
                    line = line.replace(entry.getKey(), entry.getValue());
                }
                out.write(line);
                out.newLine();
            }
        } finally {
            if (out != null)
                out.close();
            if (in != null)
                in.close();
        }

    }

    public static boolean isNewer(URL file, URL reference) {
        if (file == null || reference == null)
            throw new IllegalArgumentException("null file value");
        file = getFileURL(file);
        reference = getFileURL(reference);
        if (!isFile(file) && !isFile(reference))
            throw new IllegalArgumentException("destination is not a file URL");

        long fileLastModified = 0;
        long referenceLastModified = 0;

        if ("file".equals(file.getProtocol())) {
            File srcFile = new File(file.getFile());
            fileLastModified = srcFile.lastModified();
        }
        if ("file".equals(reference.getProtocol())) {
            File referenceFile = new File(reference.getFile());
            referenceLastModified = referenceFile.lastModified();
        }

        if ("jar".equals(file.getProtocol())) {
            ZipFile zipFile = getZipFile(file);
            ZipEntry zipEntry = getZipEntry(file, zipFile);
            if (zipEntry == null) {
                throw new IllegalArgumentException(file + " can not be found on the zip file");
            }
            fileLastModified = zipEntry.getTime();
        }
        if ("jar".equals(reference.getProtocol())) {
            ZipFile zipFile = getZipFile(reference);
            ZipEntry zipEntry = getZipEntry(reference, zipFile);
            if (zipEntry == null) {
                throw new IllegalArgumentException(reference + " can not be found on the zip file");
            }
            referenceLastModified = zipEntry.getTime();
        }

        return fileLastModified >= referenceLastModified;
    }

    /**
     * Convenience method to turn a file to a URL.
     * May return null if it can not create a URL from the file passed or file is null.
     * 
     * @param file
     * @return
     */
    public static URL toURL(File file) {
        if (file == null)
            return null;
        try {
            return file.toURL();
        } catch (MalformedURLException e) {
            return null;
        }
    }

    /**
     * Resolves a filename including wildcard characters to files in the 
     * given directory tree. This method recurses in the the subdirectories.
     * @param parent a directory
     * @param filename name for file 
     * @return array of files found matching filename or an empty array 
     */
    public static File[] resolveFile(File parent, String filename) {
        if (parent == null) {
            return new File[0];
        }
        if (!parent.isDirectory() || filename == null || filename.isEmpty() || filename.equals(".")) {
            return new File[] { parent };
        }
        File f = new File(parent, filename);
        if (f.exists()) {
            return new File[] { f };
        }
        Collection<File> theFiles = org.apache.commons.io.FileUtils.listFiles(parent,
                new WildcardFileFilter(filename), TrueFileFilter.INSTANCE);
        return theFiles.toArray(new File[theFiles.size()]);
    }

    private static void checkCanCopy(URL source, URL destination) {
        if (source == null || destination == null)
            throw new IllegalArgumentException("null source or destination value");
        getFileURL(source);
        destination = getFileURL(destination);
        if (!isFile(destination))
            throw new IllegalArgumentException("destination is not a file URL");
    }

    private static boolean isFile(URL url) {
        return "file".equals(url.getProtocol());
    }

    private static URL getFileURL(URL url) {
        try {
            url = FileLocator.resolve(url);
            return FileLocator.toFileURL(url);
        } catch (IOException e) {
            return null;
        }
    }

    private static ZipFile getZipFile(URL url) {
        if (!"jar".equals(url.getProtocol()))
            return null;
        String file = url.getFile();
        int exclamation = file.indexOf('!');
        if (exclamation < 0)
            return null;
        URL fileUrl = null;
        try {
            fileUrl = new URL(file.substring(0, exclamation));
        } catch (MalformedURLException mue) {
            return null;
        }
        File pluginJar = new File(fileUrl.getFile());
        if (!pluginJar.exists())
            return null;

        try {
            ZipFile zipFile = new ZipFile(pluginJar);
            return zipFile;
        } catch (IOException e) {
            return null;
        }
    }

    private static ZipEntry getZipEntry(URL file, ZipFile zipFile) {
        String fileString = file.getFile();
        int exclamation = fileString.indexOf('!');
        String jarLocation = fileString.substring(exclamation + 2); // remove jar separator !/ 
        return zipFile.getEntry(jarLocation);
    }

    private static void copyFromZip(ZipFile zipFile, String locationInBundle, File destination) throws IOException {

        Enumeration<? extends ZipEntry> entries = zipFile.entries();
        while (entries.hasMoreElements()) {
            ZipEntry zipEntry = entries.nextElement();
            if (zipEntry.getName().startsWith(locationInBundle)) {

                String path = zipEntry.getName().substring(locationInBundle.length());
                File file = new File(destination, path);

                if (!zipEntry.isDirectory()) {
                    createFileFromZipFile(file, zipFile, zipEntry);
                } else {
                    if (!file.exists()) {
                        file.mkdir();
                    }
                }
            }
        }

    }

    private static void createFileFromZipFile(File file, ZipFile zipFile, ZipEntry zipEntry) throws IOException {
        if (!file.getParentFile().exists() && !file.getParentFile().mkdirs()) {
            throw new IOException("Can not create parent directory for " + file.toString());
        }
        file.createNewFile();
        FileOutputStream fout = null;
        FileChannel out = null;
        InputStream in = null;
        try {
            fout = new FileOutputStream(file);
            out = fout.getChannel();
            in = zipFile.getInputStream(zipEntry);
            out.transferFrom(Channels.newChannel(in), 0, Integer.MAX_VALUE);
        } finally {
            if (out != null)
                out.close();
            if (in != null)
                in.close();
            if (fout != null)
                fout.close();
        }
    }

    private static void copyFile(File source, File target) throws IOException {

        File file = null;
        if (source.isDirectory() && source.exists() && target.isDirectory() && target.exists()) {

            File[] children = source.listFiles();
            for (File child : children) {
                file = target;
                if (child.isDirectory()) {
                    file = new File(target, child.getName());
                    if (!file.exists())
                        file.mkdir();
                }
                copyFile(child, file);
            }
        } else {// source is a file
            if (target.isFile()) {
                file = target;
            } else {
                file = new File(target, source.getName());
            }

            FileChannel out = null;
            FileChannel in = null;
            try {
                if (!file.exists()) {
                    file.createNewFile();
                }

                out = new FileOutputStream(file).getChannel();
                in = new FileInputStream(source).getChannel();
                in.transferTo(0, in.size(), out);
            } catch (IOException e) {
                e.printStackTrace();
                throw e;
            } finally {
                if (out != null)
                    out.close();
                if (in != null)
                    in.close();
            }
        }
    }

    public static File[] untarFile(File source, File outputDir) throws IOException, TarException {
        TarFile tarFile = new TarFile(source);
        List<File> untarredFiles = new ArrayList<File>();
        try {
            for (Enumeration<TarEntry> e = tarFile.entries(); e.hasMoreElements();) {
                TarEntry entry = e.nextElement();
                InputStream input = tarFile.getInputStream(entry);
                try {
                    File outFile = new File(outputDir, entry.getName());
                    outFile = outFile.getCanonicalFile(); //bug 266844
                    untarredFiles.add(outFile);
                    if (entry.getFileType() == TarEntry.DIRECTORY) {
                        outFile.mkdirs();
                    } else {
                        if (outFile.exists())
                            outFile.delete();
                        else
                            outFile.getParentFile().mkdirs();
                        try {
                            copyStream(input, false, new FileOutputStream(outFile), true);
                        } catch (FileNotFoundException e1) {
                            // TEMP: ignore this for now in case we're trying to replace
                            // a running eclipse.exe
                        }
                        outFile.setLastModified(entry.getTime());
                    }
                } finally {
                    input.close();
                }
            }
        } finally {
            tarFile.close();
        }
        return untarredFiles.toArray(new File[untarredFiles.size()]);
    }

    public static int copyStream(InputStream in, boolean closeIn, OutputStream out, boolean closeOut)
            throws IOException {
        try {
            int written = 0;
            byte[] buffer = new byte[16 * 1024];
            int len;
            while ((len = in.read(buffer)) != -1) {
                out.write(buffer, 0, len);
                written += len;
            }
            return written;
        } finally {
            try {
                if (closeIn) {
                    in.close();
                }
            } finally {
                if (closeOut) {
                    out.close();
                }
            }
        }
    }

}