de.ingrid.interfaces.csw.tools.FileUtils.java Source code

Java tutorial

Introduction

Here is the source code for de.ingrid.interfaces.csw.tools.FileUtils.java

Source

/*
 * **************************************************-
 * ingrid-interface-csw
 * ==================================================
 * Copyright (C) 2014 - 2016 wemove digital solutions GmbH
 * ==================================================
 * Licensed under the EUPL, Version 1.1 or  as soon they will be
 * approved by the European Commission - subsequent versions of the
 * EUPL (the "Licence");
 * 
 * You may not use this work except in compliance with the Licence.
 * You may obtain a copy of the Licence at:
 * 
 * http://ec.europa.eu/idabc/eupl5
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the Licence is distributed on an "AS IS" basis,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the Licence for the specific language governing permissions and
 * limitations under the Licence.
 * **************************************************#
 */
/*
 * Copyright (c) 2012 wemove digital solutions. All rights reserved.
 */
package de.ingrid.interfaces.csw.tools;

import static java.nio.file.StandardCopyOption.ATOMIC_MOVE;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.nio.file.FileSystems;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.PathMatcher;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.Scanner;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;

import de.ingrid.interfaces.csw.config.ApplicationProperties;
import de.ingrid.interfaces.csw.domain.constants.ConfigurationKeys;

public class FileUtils {

    final protected static Log log = LogFactory.getLog(FileUtils.class);

    /**
     * Remove all files from a directory and all sub directories
     * 
     * @param src
     *            The start directory
     */
    public static void deleteRecursive(File src) {
        File[] files = src.listFiles();
        if (files != null) {
            for (File file : files) {
                if (file.isDirectory()) {
                    deleteRecursive(file);
                } else {
                    if (!file.delete()) {
                        log.error("Could not delete file: " + file);
                    }
                }
            }
        }
        if (!src.delete()) {
            log.error("Could not delete file: " + src);
        }
    }

    /**
     * Delete a file or directory specified by a {@link Path}. This method uses
     * the new {@link Files} API.
     * 
     * @param path
     * @throws IOException
     */
    public static void deleteRecursive(Path path) throws IOException {
        deleteRecursive(path, ".*");
    }

    /**
     * Delete a file or directory specified by a {@link Path}. This method uses
     * the new {@link Files} API and allows to specify a regular expression to
     * remove only files that match that expression.
     * 
     * @param path
     * @param pattern
     * @throws IOException
     */
    public static void deleteRecursive(Path path, final String pattern) throws IOException {

        final PathMatcher matcher = FileSystems.getDefault().getPathMatcher("regex:" + pattern);

        if (!Files.exists(path))
            return;

        Files.walkFileTree(path, new SimpleFileVisitor<Path>() {
            @Override
            public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
                if (pattern != null && matcher.matches(file.getFileName())) {
                    Files.delete(file);
                }
                return FileVisitResult.CONTINUE;
            }

            @Override
            public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException {
                // try to delete the file anyway, even if its attributes
                // could not be read, since delete-only access is
                // theoretically possible
                if (pattern != null && matcher.matches(file.getFileName())) {
                    Files.delete(file);
                }
                return FileVisitResult.CONTINUE;
            }

            @Override
            public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
                if (exc == null) {
                    if (matcher.matches(dir.getFileName())) {
                        if (dir.toFile().list().length > 0) {
                            // remove even if not empty
                            FileUtils.deleteRecursive(dir);
                        } else {
                            Files.delete(dir);
                        }
                    }
                    return FileVisitResult.CONTINUE;
                } else {
                    // directory iteration failed; propagate exception
                    throw exc;
                }
            }

        });
    }

    /**
     * Moves a path, retries for timeout ms if moving fails.
     * 
     * @param src
     * @param dest
     * @param timeout
     * @throws IOException
     */
    public static void waitAndMove(Path src, Path dest, long timeout) throws IOException {
        long time = 0;
        boolean isMoved = false;
        long pause = ApplicationProperties.getInteger(ConfigurationKeys.FILE_OPERATION_RETRY_TIMEOUT, 1000);
        while (time < timeout && !isMoved) {
            try {
                Files.move(src, dest, ATOMIC_MOVE);
                isMoved = true;
            } catch (IOException e) {
                log.warn("Move " + src + " to " + dest + " failed.", e);
                log.warn("Sleep " + pause + "ms and retry.");
                try {
                    Thread.sleep(pause);
                } catch (InterruptedException e1) {
                    log.error("Waiting for moving " + src + " to " + dest + " failed. Got iterrupted", e1);
                    throw new IOException(e1);
                }
                time += pause;
                if (time >= timeout) {
                    throw new IOException("Move " + src + " to " + dest + " failed after " + timeout + "ms.");
                }
            }
        }
    }

    /**
     * Deleted a Path recursivly, retries for timeout if it fails.
     * 
     * @param path
     * @param timeout
     * @throws IOException
     */
    public static void waitAndDelete(Path path, long timeout) throws IOException {
        long time = 0;
        boolean isDeleted = false;
        long pause = ApplicationProperties.getInteger(ConfigurationKeys.FILE_OPERATION_RETRY_TIMEOUT, 1000);
        while (time < timeout && !isDeleted) {
            try {
                deleteRecursive(path);
                isDeleted = true;
            } catch (IOException e) {
                log.warn("Deleting " + path + " failed.", e);
                log.warn("Sleep " + pause + "ms and retry.");
                try {
                    Thread.sleep(pause);
                } catch (InterruptedException e1) {
                    log.error("Waiting for deleting " + path + " failed. Got iterrupted", e1);
                    throw new IOException(e1);
                }
                time += pause;
                if (time >= timeout) {
                    throw new IOException("Deleting " + path + " failed after " + timeout + "ms.");
                }
            }
        }
    }

    /**
     * This function will copy files or directories from one location to
     * another. note that the source and the destination must be mutually
     * exclusive. This function can not be used to copy a directory to a sub
     * directory of itself. The function will also have problems if the
     * destination files already exist.
     * 
     * @param src
     *            -- A File object that represents the source for the copy
     * @param dest
     *            -- A File object that represnts the destination for the copy.
     * @throws IOException
     *             if unable to copy.
     * 
     *             Source: http://www.dreamincode.net/code/snippet1443.htm
     */
    public static void copyRecursive(File src, File dest) throws IOException {
        // Check to ensure that the source is valid...
        if (!src.exists()) {
            throw new IOException("copyFiles: Can not find source: " + src.getAbsolutePath() + ".");
        } else if (!src.canRead()) { // check to ensure we have rights to the
            // source...
            throw new IOException("copyFiles: No right to source: " + src.getAbsolutePath() + ".");
        }
        // is this a directory copy?
        if (src.isDirectory()) {
            if (!dest.exists()) { // does the destination already exist?
                // if not we need to make it exist if possible (note this is
                // mkdirs not mkdir)
                if (!dest.mkdirs()) {
                    throw new IOException("copyFiles: Could not create direcotry: " + dest.getAbsolutePath() + ".");
                }
            }
            // get a listing of files...
            String list[] = src.list();
            // copy all the files in the list.
            for (String element : list) {
                File dest1 = new File(dest, element);
                File src1 = new File(src, element);
                copyRecursive(src1, dest1);
            }
        } else {
            // This was not a directory, so lets just copy the file
            FileInputStream fin = null;
            FileOutputStream fout = null;
            byte[] buffer = new byte[4096]; // Buffer 4K at a time (you can
            // change this).
            int bytesRead;
            try {
                // open the files for input and output
                fin = new FileInputStream(src);
                fout = new FileOutputStream(dest);
                // while bytesRead indicates a successful read, lets write...
                while ((bytesRead = fin.read(buffer)) >= 0) {
                    fout.write(buffer, 0, bytesRead);
                }
                fin.close();
                fout.close();
                fin = null;
                fout = null;
            } catch (IOException e) { // Error copying file...
                IOException wrapper = new IOException("copyFiles: Unable to copy file: " + src.getAbsolutePath()
                        + "to" + dest.getAbsolutePath() + ".");
                wrapper.initCause(e);
                wrapper.setStackTrace(e.getStackTrace());
                throw wrapper;
            } finally { // Ensure that the files are closed (if they were open).
                if (fin != null) {
                    fin.close();
                }
                if (fout != null) {
                    fin.close();
                }
            }
        }
    }

    /**
     * Encode Filename to prevent invalid characters in file name. The encoding
     * is reversible (url encoding (UTF-8) is used).
     * 
     * @param s
     * @return
     */
    public static String encodeFileName(String s) {
        try {
            return URLEncoder.encode(s, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            log.error("Unable to encode using UTF-8.", e);
            return s;
        }
    }

    /**
     * Decode Filename coded with <code>encodeFileName</code>.
     * 
     * @param s
     * @return
     */
    public static String decodeFileName(String s) {
        try {
            return URLDecoder.decode(s, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            log.error("Unable to decode using UTF-8.", e);
            return s;
        }
    }

    /**
     * Get the document id from a cache filename
     * 
     * @param filename
     *            The filename without the path
     * @return String
     */
    public static String getIdFromFilename(String filename) {
        String id = decodeId(filename.substring(0, filename.lastIndexOf(".")));
        return id;
    }

    /**
     * Encode an id to be used in a filename.
     * 
     * @return String
     */
    public static String encodeId(Serializable id) {
        if (id != null) {
            return encodeFileName(id.toString());
        } else {
            throw new IllegalArgumentException("Null is not allowed as id value.");
        }
    }

    /**
     * Decode an id that was used in a filename.
     * 
     * @return String
     */
    public static String decodeId(Serializable id) {
        if (id != null) {
            return decodeFileName(id.toString());
        } else {
            throw new IllegalArgumentException("Null is not allowed as id value.");
        }
    }

    /**
     * Get all resources specified by pattern. For pattern syntax see (@link
     * PathMatchingResourcePatternResolver).
     * 
     * @param packageName
     * @return
     * @throws IOException
     */
    public static Resource[] getPackageContent(String pattern) throws IOException {
        PathMatchingResourcePatternResolver pmrpr = new PathMatchingResourcePatternResolver();
        Resource[] resources = pmrpr.getResources(pattern);
        return resources;
    }

    /**
     * Convert stream to string.
     * 
     * @param is
     * @return
     */
    public static String convertStreamToString(java.io.InputStream is) {
        Scanner scanner = null;
        try {
            scanner = new Scanner(is);
            scanner.useDelimiter("\\A");
            String content = scanner.next();
            scanner.close();
            return content;
        } catch (java.util.NoSuchElementException e) {
            return "";
        } finally {
            if (scanner != null) {
                scanner.close();
            }
        }
    }

    /**
     * Read a file into a string.
     * 
     * @param path
     * @param encoding
     * @return
     * @throws IOException
     */
    public static String readFile(Path path, Charset encoding) throws IOException {
        byte[] encoded = Files.readAllBytes(path);
        return new String(encoded, encoding);
    }

    /**
     * Write a string to a file.
     * 
     * @param path
     * @param content
     * @param encoding
     * @throws IOException
     */
    public static void writeFile(Path path, String content, Charset encoding) throws IOException {
        Files.write(path, content.getBytes(encoding));
    }

}