    001/*
    002 * Licensed to the Apache Software Foundation (ASF) under one or more
    003 * contributor license agreements.  See the NOTICE file distributed with
    004 * this work for additional information regarding copyright ownership.
    005 * The ASF licenses this file to You under the Apache License, Version 2.0
    006 * (the "License"); you may not use this file except in compliance with
    007 * the License.  You may obtain a copy of the License at
    008 *
    009 *      http://www.apache.org/licenses/LICENSE-2.0
    010 *
    011 * Unless required by applicable law or agreed to in writing, software
    012 * distributed under the License is distributed on an "AS IS" BASIS,
    013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    014 * See the License for the specific language governing permissions and
    015 * limitations under the License.
    016 */
    017
    018package org.apache.commons.io.file;
    019
    020import java.io.IOException;
    021import java.nio.file.CopyOption;
    022import java.nio.file.FileVisitResult;
    023import java.nio.file.Files;
    024import java.nio.file.Path;
    025import java.nio.file.attribute.BasicFileAttributes;
    026import java.util.Arrays;
    027import java.util.Objects;
    028
    029import org.apache.commons.io.file.Counters.PathCounters;
    030
    031/**
    032 * Copies a source directory to a target directory.
    033 *
    034 * @since 2.7
    035 */
    036public class CopyDirectoryVisitor extends CountingPathVisitor {
    037
    038    private static final CopyOption[] EMPTY_COPY_OPTIONS = new CopyOption[0];
    039
    040    private final CopyOption[] copyOptions;
    041    private final Path sourceDirectory;
    042    private final Path targetDirectory;
    043
    044    /**
    045     * Constructs a new visitor that deletes files except for the files and directories explicitly given.
    046     *
    047     * @param pathCounter How to count visits.
    048     * @param sourceDirectory The source directory
    049     * @param targetDirectory The target directory
    050     * @param copyOptions Specifies how the copying should be done.
    051     */
    052    public CopyDirectoryVisitor(final PathCounters pathCounter, final Path sourceDirectory, final Path targetDirectory,
    053        final CopyOption... copyOptions) {
    054        super(pathCounter);
    055        this.sourceDirectory = sourceDirectory;
    056        this.targetDirectory = targetDirectory;
    057        this.copyOptions = copyOptions == null ? EMPTY_COPY_OPTIONS : copyOptions.clone();
    058    }
    059
    060    /**
    061     * Copies the sourceFile to the targetFile.
    062     *
    063     * @param sourceFile the source file.
    064     * @param targetFile the target file.
    065     * @throws IOException if an I/O error occurs.
    066     * @since 2.8.0
    067     */
    068    protected void copy(final Path sourceFile, final Path targetFile) throws IOException {
    069        Files.copy(sourceFile, targetFile, copyOptions);
    070    }
    071
    072    @Override
    073    public boolean equals(final Object obj) {
    074        if (this == obj) {
    075            return true;
    076        }
    077        if (!super.equals(obj)) {
    078            return false;
    079        }
    080        if (getClass() != obj.getClass()) {
    081            return false;
    082        }
    083        final CopyDirectoryVisitor other = (CopyDirectoryVisitor) obj;
    084        return Arrays.equals(copyOptions, other.copyOptions) && Objects.equals(sourceDirectory, other.sourceDirectory)
    085                && Objects.equals(targetDirectory, other.targetDirectory);
    086    }
    087
    088    /**
    089     * Gets the copy options.
    090     *
    091     * @return the copy options.
    092     * @since 2.8.0
    093     */
    094    public CopyOption[] getCopyOptions() {
    095        return copyOptions.clone();
    096    }
    097
    098    /**
    099     * Gets the source directory.
    100     *
    101     * @return the source directory.
    102     * @since 2.8.0
    103     */
    104    public Path getSourceDirectory() {
    105        return sourceDirectory;
    106    }
    107
    108    /**
    109     * Gets the target directory.
    110     *
    111     * @return the target directory.
    112     * @since 2.8.0
    113     */
    114    public Path getTargetDirectory() {
    115        return targetDirectory;
    116    }
    117
    118    @Override
    119    public int hashCode() {
    120        final int prime = 31;
    121        int result = super.hashCode();
    122        result = prime * result + Arrays.hashCode(copyOptions);
    123        result = prime * result + Objects.hash(sourceDirectory, targetDirectory);
    124        return result;
    125    }
    126
    127    @Override
    128    public FileVisitResult preVisitDirectory(final Path directory, final BasicFileAttributes attributes)
    129        throws IOException {
    130        final Path newTargetDir = targetDirectory.resolve(sourceDirectory.relativize(directory));
    131        if (Files.notExists(newTargetDir)) {
    132            Files.createDirectory(newTargetDir);
    133        }
    134        return super.preVisitDirectory(directory, attributes);
    135    }
    136
    137    @Override
    138    public FileVisitResult visitFile(final Path sourceFile, final BasicFileAttributes attributes) throws IOException {
    139        final Path targetFile = targetDirectory.resolve(sourceDirectory.relativize(sourceFile));
    140        copy(sourceFile, targetFile);
    141        return super.visitFile(targetFile, attributes);
    142    }
    143
    144}