com.ruizhan.hadoop.hdfs.FsShell.java Source code

Java tutorial

Introduction

Here is the source code for com.ruizhan.hadoop.hdfs.FsShell.java

Source

package com.ruizhan.hadoop.hdfs;
/**
 * Licensed to the Apache Software Foundation (ASF) 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.
 */

import java.io.IOException;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.classification.InterfaceAudience;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.conf.Configured;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.fs.shell.Command;
import org.apache.hadoop.fs.shell.CommandFactory;
import org.apache.hadoop.fs.shell.FsCommand;
import org.apache.hadoop.util.Tool;
import org.apache.hadoop.util.ToolRunner;

/** Provide command line access to a FileSystem. */
@InterfaceAudience.Private
public class FsShell extends Configured implements Tool {

    static final Log LOG = LogFactory.getLog(FsShell.class);

    private FileSystem fs;
    private Trash trash;
    protected CommandFactory commandFactory;

    private final String usagePrefix = "Usage: hadoop fs [generic options]";

    /**
     * Default ctor with no configuration.  Be sure to invoke
     * {@link #setConf(Configuration)} with a valid configuration prior
     * to running commands.
     */
    public FsShell() {
        this(null);
    }

    /**
     * Construct a FsShell with the given configuration.  Commands can be
     * executed via {@link #run(String[])}
     * @param conf the hadoop configuration
     */
    public FsShell(Configuration conf) {
        super(conf);
    }

    protected FileSystem getFS() throws IOException {
        if (fs == null) {
            fs = FileSystem.get(getConf());
        }
        return fs;
    }

    protected Trash getTrash() throws IOException {
        if (this.trash == null) {
            this.trash = new Trash(getConf());
        }
        return this.trash;
    }

    protected void init() throws IOException {
        getConf().setQuietMode(true);
        if (commandFactory == null) {
            commandFactory = new CommandFactory(getConf());
            commandFactory.addObject(new Help(), "-help");
            commandFactory.addObject(new Usage(), "-usage");
            registerCommands(commandFactory);
        }
    }

    protected void registerCommands(CommandFactory factory) {
        // TODO: DFSAdmin subclasses FsShell so need to protect the command
        // registration.  This class should morph into a base class for
        // commands, and then this method can be abstract
        if (this.getClass().equals(FsShell.class)) {
            factory.registerCommands(FsCommand.class);
        }
    }

    /**
     * Returns the Trash object associated with this shell.
     * @return Path to the trash
     * @throws IOException upon error
     */
    public Path getCurrentTrashDir() throws IOException {
        return getTrash().getCurrentTrashDir();
    }

    // NOTE: Usage/Help are inner classes to allow access to outer methods
    // that access commandFactory

    /**
     *  Display help for commands with their short usage and long description
     */
    protected class Usage extends FsCommand {
        public static final String NAME = "usage";
        public static final String USAGE = "[cmd ...]";
        public static final String DESCRIPTION = "Displays the usage for given command or all commands if none\n"
                + "is specified.";

        @Override
        protected void processRawArguments(LinkedList<String> args) {
            if (args.isEmpty()) {
                printUsage(System.out);
            } else {
                for (String arg : args)
                    printUsage(System.out, arg);
            }
        }
    }

    /**
     * Displays short usage of commands sans the long description
     */
    protected class Help extends FsCommand {
        public static final String NAME = "help";
        public static final String USAGE = "[cmd ...]";
        public static final String DESCRIPTION = "Displays help for given command or all commands if none\n"
                + "is specified.";

        @Override
        protected void processRawArguments(LinkedList<String> args) {
            if (args.isEmpty()) {
                printHelp(System.out);
            } else {
                for (String arg : args)
                    printHelp(System.out, arg);
            }
        }
    }

    /*
     * The following are helper methods for getInfo().  They are defined
     * outside of the scope of the Help/Usage class because the run() method
     * needs to invoke them too. 
     */

    // print all usages
    private void printUsage(PrintStream out) {
        printInfo(out, null, false);
    }

    // print one usage
    private void printUsage(PrintStream out, String cmd) {
        printInfo(out, cmd, false);
    }

    // print all helps
    private void printHelp(PrintStream out) {
        printInfo(out, null, true);
    }

    // print one help
    private void printHelp(PrintStream out, String cmd) {
        printInfo(out, cmd, true);
    }

    private void printInfo(PrintStream out, String cmd, boolean showHelp) {
        if (cmd != null) {
            // display help or usage for one command
            Command instance = commandFactory.getInstance("-" + cmd);
            if (instance == null) {
                throw new UnknownCommandException(cmd);
            }
            if (showHelp) {
                printInstanceHelp(out, instance);
            } else {
                printInstanceUsage(out, instance);
            }
        } else {
            // display help or usage for all commands 
            out.println(usagePrefix);

            // display list of short usages
            ArrayList<Command> instances = new ArrayList<Command>();
            for (String name : commandFactory.getNames()) {
                Command instance = commandFactory.getInstance(name);
                if (!instance.isDeprecated()) {
                    System.out.println("\t[" + instance.getUsage() + "]");
                    instances.add(instance);
                }
            }
            // display long descriptions for each command
            if (showHelp) {
                for (Command instance : instances) {
                    out.println();
                    printInstanceHelp(out, instance);
                }
            }
            out.println();
            ToolRunner.printGenericCommandUsage(out);
        }
    }

    private void printInstanceUsage(PrintStream out, Command instance) {
        out.println(usagePrefix + " " + instance.getUsage());
    }

    // TODO: will eventually auto-wrap the text, but this matches the expected
    // output for the hdfs tests...
    private void printInstanceHelp(PrintStream out, Command instance) {
        boolean firstLine = true;
        for (String line : instance.getDescription().split("\n")) {
            String prefix;
            if (firstLine) {
                prefix = instance.getUsage() + ":\t";
                firstLine = false;
            } else {
                prefix = "\t\t";
            }
            System.out.println(prefix + line);
        }
    }

    /**
     * run
     */
    public int run(String argv[]) throws Exception {
        // initialize FsShell
        init();

        int exitCode = -1;
        if (argv.length < 1) {
            printUsage(System.err);
        } else {
            String cmd = argv[0];
            Command instance = null;
            try {
                instance = commandFactory.getInstance(cmd);
                if (instance == null) {
                    throw new UnknownCommandException();
                }
                exitCode = instance.run(Arrays.copyOfRange(argv, 1, argv.length));
            } catch (IllegalArgumentException e) {
                displayError(cmd, e.getLocalizedMessage());
                if (instance != null) {
                    printInstanceUsage(System.err, instance);
                }
            } catch (Exception e) {
                // instance.run catches IOE, so something is REALLY wrong if here
                LOG.debug("Error", e);
                displayError(cmd, "Fatal internal error");
                e.printStackTrace(System.err);
            }
        }
        return exitCode;
    }

    private void displayError(String cmd, String message) {
        for (String line : message.split("\n")) {
            System.err.println(cmd + ": " + line);
            if (cmd.charAt(0) != '-') {
                Command instance = null;
                instance = commandFactory.getInstance("-" + cmd);
                if (instance != null) {
                    System.err.println("Did you mean -" + cmd + "?  This command " + "begins with a dash.");
                }
            }
        }
    }

    /**
     *  Performs any necessary cleanup
     * @throws IOException upon error
     */
    public void close() throws IOException {
        if (fs != null) {
            fs.close();
            fs = null;
        }
    }

    /**
     * main() has some simple utility methods
     * @param argv the command and its arguments
     * @throws Exception upon error
     */
    public static void main(String argv[]) throws Exception {
        FsShell shell = newShellInstance();
        int res;
        try {
            res = ToolRunner.run(shell, argv);
        } finally {
            shell.close();
        }
        System.exit(res);
    }

    // TODO: this should be abstract in a base class
    protected static FsShell newShellInstance() {
        return new FsShell();
    }

    /**
     * The default ctor signals that the command being executed does not exist,
     * while other ctor signals that a specific command does not exist.  The
     * latter is used by commands that process other commands, ex. -usage/-help
     */
    @SuppressWarnings("serial")
    static class UnknownCommandException extends IllegalArgumentException {
        private final String cmd;

        UnknownCommandException() {
            this(null);
        }

        UnknownCommandException(String cmd) {
            this.cmd = cmd;
        }

        @Override
        public String getMessage() {
            return ((cmd != null) ? "`" + cmd + "': " : "") + "Unknown command";
        }
    }
}