tachyon.shell.command.CopyFromLocalCommand.java Source code

Java tutorial

Introduction

Here is the source code for tachyon.shell.command.CopyFromLocalCommand.java

Source

/*
 * Licensed to the University of California, Berkeley under one or more contributor license
 * agreements. See the NOTICE file distributed with this work for additional information regarding
 * copyright ownership. The ASF licenses this file to You 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 tachyon.shell.command;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.util.List;

import javax.annotation.concurrent.ThreadSafe;

import com.google.common.base.Joiner;
import com.google.common.collect.Lists;
import com.google.common.io.Closer;

import org.apache.commons.cli.CommandLine;

import tachyon.Constants;
import tachyon.TachyonURI;
import tachyon.client.file.FileOutStream;
import tachyon.client.file.FileSystem;
import tachyon.client.file.URIStatus;
import tachyon.conf.TachyonConf;
import tachyon.exception.ExceptionMessage;
import tachyon.exception.FileAlreadyExistsException;
import tachyon.exception.TachyonException;
import tachyon.shell.TfsShellUtils;
import tachyon.util.io.PathUtils;

/**
 * Copies the specified file specified by "source path" to the path specified by "remote path".
 * This command will fail if "remote path" already exists.
 */
@ThreadSafe
public final class CopyFromLocalCommand extends AbstractTfsShellCommand {

    /**
     * @param conf the configuration for Tachyon
     * @param fs the filesystem of Tachyon
     */
    public CopyFromLocalCommand(TachyonConf conf, FileSystem fs) {
        super(conf, fs);
    }

    @Override
    public String getCommandName() {
        return "copyFromLocal";
    }

    @Override
    protected int getNumOfArgs() {
        return 2;
    }

    @Override
    public void run(CommandLine cl) throws IOException {
        String[] args = cl.getArgs();
        String srcPath = args[0];
        TachyonURI dstPath = new TachyonURI(args[1]);
        List<File> srcFiles = TfsShellUtils.getFiles(srcPath);
        if (srcFiles.size() == 0) {
            throw new IOException("Local path " + srcPath + " does not exist.");
        }

        if (srcPath.contains(TachyonURI.WILDCARD)) {
            copyFromLocalWildcard(srcFiles, dstPath);
        } else {
            copyFromLocal(new File(srcPath), dstPath);
        }
    }

    /**
     * Copies a list of files or directories specified by srcFiles from the local filesystem to
     * dstPath in the Tachyon filesystem space. This method is used when the input path contains
     * wildcards.
     *
     * @param srcFiles The list of files in the local filesystem
     * @param dstPath The {@link TachyonURI} of the destination
     * @throws IOException if a non-Tachyon related exception occurs
     */
    private void copyFromLocalWildcard(List<File> srcFiles, TachyonURI dstPath) throws IOException {
        try {
            mFileSystem.createDirectory(dstPath);
        } catch (FileAlreadyExistsException e) {
            // it's fine if the directory already exists
        } catch (TachyonException e) {
            throw new IOException(e.getMessage());
        }

        URIStatus dstStatus;
        try {
            dstStatus = mFileSystem.getStatus(dstPath);
        } catch (TachyonException e) {
            throw new IOException(e.getMessage());
        }
        if (!dstStatus.isFolder()) {
            throw new IOException(ExceptionMessage.DESTINATION_FILE_CANNOT_EXIST_WITH_WILDCARD_SOURCE.getMessage());
        }

        List<String> errorMessages = Lists.newArrayList();
        for (File srcFile : srcFiles) {
            try {
                copyFromLocal(srcFile, new TachyonURI(PathUtils.concatPath(dstPath.getPath(), srcFile.getName())));
            } catch (IOException e) {
                errorMessages.add(e.getMessage());
            }
        }
        if (errorMessages.size() != 0) {
            throw new IOException(Joiner.on('\n').join(errorMessages));
        }
    }

    /**
     * Copies a file or directory specified by srcPath from the local filesystem to dstPath in the
     * Tachyon filesystem space. Will fail if the path given already exists in the filesystem.
     *
     * @param srcFile The source file in the local filesystem
     * @param dstPath The {@link TachyonURI} of the destination
     * @throws IOException if a non-Tachyon related exception occurs
     */
    private void copyFromLocal(File srcFile, TachyonURI dstPath) throws IOException {
        copyPath(srcFile, dstPath);
        System.out.println("Copied " + srcFile.getPath() + " to " + dstPath);
    }

    private void copyPath(File src, TachyonURI dstPath) throws IOException {
        try {
            if (!src.isDirectory()) {
                // If the dstPath is a directory, then it should be updated to be the path of the file where
                // src will be copied to
                if (mFileSystem.exists(dstPath) && mFileSystem.getStatus(dstPath).isFolder()) {
                    dstPath = dstPath.join(src.getName());
                }

                Closer closer = Closer.create();
                FileOutStream os = null;
                try {
                    os = closer.register(mFileSystem.createFile(dstPath));
                    FileInputStream in = closer.register(new FileInputStream(src));
                    FileChannel channel = closer.register(in.getChannel());
                    ByteBuffer buf = ByteBuffer.allocate(8 * Constants.MB);
                    while (channel.read(buf) != -1) {
                        buf.flip();
                        os.write(buf.array(), 0, buf.limit());
                    }
                } catch (IOException e) {
                    // Close the out stream and delete the file, so we don't have an incomplete file lying
                    // around
                    if (os != null) {
                        os.cancel();
                        if (mFileSystem.exists(dstPath)) {
                            mFileSystem.delete(dstPath);
                        }
                    }
                    throw e;
                } finally {
                    closer.close();
                }
            } else {
                mFileSystem.createDirectory(dstPath);
                List<String> errorMessages = Lists.newArrayList();
                String[] fileList = src.list();
                for (String file : fileList) {
                    TachyonURI newPath = new TachyonURI(dstPath, new TachyonURI(file));
                    File srcFile = new File(src, file);
                    try {
                        copyPath(srcFile, newPath);
                    } catch (IOException e) {
                        errorMessages.add(e.getMessage());
                    }
                }
                if (errorMessages.size() != 0) {
                    if (errorMessages.size() == fileList.length) {
                        // If no files were created, then delete the directory
                        if (mFileSystem.exists(dstPath)) {
                            mFileSystem.delete(dstPath);
                        }
                    }
                    throw new IOException(Joiner.on('\n').join(errorMessages));
                }
            }
        } catch (TachyonException e) {
            throw new IOException(e.getMessage());
        }
    }

    @Override
    public String getUsage() {
        return "copyFromLocal <src> <remoteDst>";
    }

    @Override
    public String getDescription() {
        return "Copies a file or a directory from local filesystem to Tachyon filesystem.";
    }
}