Package com.xebialabs.overthere.util

Source Code of com.xebialabs.overthere.util.OverthereFileCopier

/*
* Copyright (c) 2008-2014, XebiaLabs B.V., All rights reserved.
*
*
* Overthere is licensed under the terms of the GPLv2
* <http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most XebiaLabs Libraries.
* There are special exceptions to the terms and conditions of the GPLv2 as it is applied to
* this software, see the FLOSS License Exception
* <http://github.com/xebialabs/overthere/blob/master/LICENSE>.
*
* This program is free software; you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Foundation; version 2
* of the License.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this
* program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth
* Floor, Boston, MA 02110-1301  USA
*/
package com.xebialabs.overthere.util;

import com.xebialabs.overthere.OverthereFile;
import com.xebialabs.overthere.RuntimeIOException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Stack;

import static com.xebialabs.overthere.util.OverthereUtils.closeQuietly;

/**
* OverthereFile copy utility that uses only the input and output streams exposed by the OverthereFile to perform the
* copying action.
* <p/>
* FIXME: Move to its proper place
*/
public final class OverthereFileCopier extends OverthereFileDirectoryWalker {

    private static final String SOURCE = "Source";
    private static final String DESTINATION = "Destination";

    private Stack<OverthereFile> dstDirStack = new Stack<OverthereFile>();
    private OverthereFile srcDir;

    private OverthereFileCopier(OverthereFile srcDir, OverthereFile dstDir) {
        dstDirStack.push(dstDir);
        this.srcDir = srcDir;
        OverthereFileCopier.checkDirectoryExists(srcDir, SOURCE);
    }

    @Override
    protected void handleDirectoryStart(OverthereFile scrDir, int depth) throws IOException {
        OverthereFile dstDir = getCurrentDestinationDir();
        if (depth != ROOT) {
            dstDir = createSubdirectoryAndMakeCurrent(dstDir, scrDir.getName());
        }

        if (dstDir.exists()) {
            OverthereFileCopier.checkReallyIsADirectory(dstDir, DESTINATION);
            logger.debug("About to copy files into existing directory {}", dstDir);
        } else {
            logger.debug("Creating destination directory {}", dstDir);
            dstDir.mkdir();
        }
    }

    private OverthereFile createSubdirectoryAndMakeCurrent(OverthereFile parentDir, String subdirName) {
        OverthereFile subdir = parentDir.getFile(subdirName);
        dstDirStack.push(subdir);
        return subdir;
    }

    private void startCopy() {
        walk(srcDir);
    }

    private OverthereFile getCurrentDestinationDir() {
        return dstDirStack.peek();
    }

    @Override
    protected void handleFile(OverthereFile srcFile, int depth) throws IOException {
        OverthereFile dstFile = getCurrentDestinationDir().getFile(srcFile.getName());
        OverthereFileCopier.copyFile(srcFile, dstFile);
    }

    @Override
    protected void handleDirectoryEnd(OverthereFile directory, int depth) throws IOException {
        if (depth != ROOT) {
            dstDirStack.pop();
        }
    }

    /**
     * Copies a file or directory.
     *
     * @param src the source file or directory.
     * @param dst the destination file or directory. If it exists it must be of the same type as the source. Its parent
     *            directory must exist.
     * @throws RuntimeIOException if an I/O error occurred
     */
    public static void copy(OverthereFile src, OverthereFile dst) {
        if (src.isDirectory()) {
            copyDirectory(src, dst);
        } else {
            copyFile(src, dst);
        }
    }

    /**
     * Copies a directory recursively.
     *
     * @param srcDir the source directory. Must exist and must not be a directory.
     * @param dstDir the destination directory. May exists but must a directory. Its parent directory must exist.
     * @throws RuntimeIOException if an I/O error occurred
     */
    private static void copyDirectory(OverthereFile srcDir, OverthereFile dstDir) throws RuntimeIOException {
        OverthereFileCopier dirCopier = new OverthereFileCopier(srcDir, dstDir);
        dirCopier.startCopy();
    }

    /**
     * Copies a regular file.
     *
     * @param srcFile the source file. Must exists and must not be a directory.
     * @param dstFile the destination file. May exists but must not be a directory. Its parent directory must exist.
     * @throws RuntimeIOException if an I/O error occurred
     */
    private static void copyFile(final OverthereFile srcFile, final OverthereFile dstFile) throws RuntimeIOException {
        checkFileExists(srcFile, SOURCE);
        checkReallyIsAFile(dstFile, DESTINATION);

        if (dstFile.exists())
            logger.debug("About to overwrite existing file {}", dstFile);

        try {
            InputStream is = srcFile.getInputStream();
            try {
                OutputStream os = dstFile.getOutputStream();
                try {
                    byte[] bytes = new byte[1024];
                    int nRead;
                    while ((nRead = is.read(bytes, 0, bytes.length)) != -1) {
                        os.write(bytes, 0, nRead);
                    }
                } finally {
                    closeQuietly(os);
                }
            } finally {
                closeQuietly(is);
            }
        } catch (IOException exc) {
            throw new RuntimeIOException("Cannot copy " + srcFile + " to " + dstFile, exc);
        }
    }

    /**
     * Assert that the file must exist and it is not a directory.
     *
     * @param file              to check.
     * @param sourceDescription to prepend to error message.
     * @throws RuntimeIOException if file does not exist or is a directory.
     */
    private static void checkFileExists(OverthereFile file, String sourceDescription) {
        if (!file.exists()) {
            throw new RuntimeIOException(sourceDescription + " file " + file + " does not exist");
        }
        checkReallyIsAFile(file, sourceDescription);
    }

    /**
     * Assert that if a file exists, it is not a directory.
     *
     * @param file            to check.
     * @param fileDescription to prepend to error message.
     * @throws RuntimeIOException if file is a directory.
     */
    private static void checkReallyIsAFile(OverthereFile file, String fileDescription) {
        if (file.exists() && file.isDirectory()) {
            throw new RuntimeIOException(fileDescription + " file " + file + " exists but is a directory");
        }
    }

    /**
     * Assert that the directory exists.
     *
     * @param dir            is the directory to check.
     * @param dirDescription to prepend to error message.
     * @throws RuntimeIOException if directory does not exist or if it a flat file.
     */
    private static void checkDirectoryExists(OverthereFile dir, String dirDescription) {
        if (!dir.exists()) {
            throw new RuntimeIOException(dirDescription + " directory " + dir + " does not exist");
        }
        checkReallyIsADirectory(dir, dirDescription);
    }

    /**
     * Assert that if a file exists, it must be a directory.
     *
     * @param dir            is the directory to check.
     * @param dirDescription to prepend to error message.
     * @throws RuntimeIOException if file is not a directory.
     */
    private static void checkReallyIsADirectory(OverthereFile dir, String dirDescription) {
        if (dir.exists() && !dir.isDirectory()) {
            throw new RuntimeIOException(dirDescription + " directory " + dir + " exists but is not a directory");
        }
    }

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

}
TOP

Related Classes of com.xebialabs.overthere.util.OverthereFileCopier

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.