You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@accumulo.apache.org by kt...@apache.org on 2015/09/03 23:30:39 UTC

[3/3] accumulo git commit: Merge branch '1.6' into 1.7

Merge branch '1.6' into 1.7

Conflicts:
	core/src/main/java/org/apache/accumulo/core/util/shell/commands/CompactCommand.java
	shell/src/main/java/org/apache/accumulo/shell/commands/ScanCommand.java
	shell/src/main/java/org/apache/accumulo/shell/commands/SetScanIterCommand.java
	shell/src/main/java/org/apache/accumulo/shell/commands/SetShellIterCommand.java


Project: http://git-wip-us.apache.org/repos/asf/accumulo/repo
Commit: http://git-wip-us.apache.org/repos/asf/accumulo/commit/6df97b89
Tree: http://git-wip-us.apache.org/repos/asf/accumulo/tree/6df97b89
Diff: http://git-wip-us.apache.org/repos/asf/accumulo/diff/6df97b89

Branch: refs/heads/1.7
Commit: 6df97b8905d07f65d617ec59a2ad4a34afac81f1
Parents: 2033005 e4ffc77
Author: Keith Turner <ke...@deenlo.com>
Authored: Thu Sep 3 17:05:41 2015 -0400
Committer: Keith Turner <ke...@deenlo.com>
Committed: Thu Sep 3 17:05:41 2015 -0400

----------------------------------------------------------------------
 .../java/org/apache/accumulo/shell/Shell.java     |  8 ++++----
 .../accumulo/shell/commands/CompactCommand.java   |  4 ++++
 .../accumulo/shell/commands/ScanCommand.java      | 18 +++++++++++++++++-
 .../accumulo/shell/commands/SetIterCommand.java   | 11 ++++-------
 .../shell/commands/SetScanIterCommand.java        | 15 +--------------
 .../shell/commands/SetShellIterCommand.java       |  7 -------
 6 files changed, 30 insertions(+), 33 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/accumulo/blob/6df97b89/shell/src/main/java/org/apache/accumulo/shell/Shell.java
----------------------------------------------------------------------
diff --cc shell/src/main/java/org/apache/accumulo/shell/Shell.java
index 37856ad,0000000..483edb0
mode 100644,000000..100644
--- a/shell/src/main/java/org/apache/accumulo/shell/Shell.java
+++ b/shell/src/main/java/org/apache/accumulo/shell/Shell.java
@@@ -1,1267 -1,0 +1,1267 @@@
 +/*
 + * 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.
 + */
 +package org.apache.accumulo.shell;
 +
 +import static java.nio.charset.StandardCharsets.ISO_8859_1;
 +import static java.nio.charset.StandardCharsets.UTF_8;
 +
 +import java.io.BufferedWriter;
 +import java.io.File;
 +import java.io.FileNotFoundException;
 +import java.io.FileOutputStream;
 +import java.io.IOException;
 +import java.io.OutputStreamWriter;
 +import java.io.PrintWriter;
 +import java.net.InetAddress;
 +import java.nio.charset.Charset;
 +import java.util.Arrays;
 +import java.util.Collections;
 +import java.util.HashMap;
 +import java.util.HashSet;
 +import java.util.Iterator;
 +import java.util.List;
 +import java.util.Locale;
 +import java.util.Map;
 +import java.util.Map.Entry;
 +import java.util.Set;
 +import java.util.TreeMap;
 +import java.util.UUID;
 +import java.util.concurrent.TimeUnit;
 +
- import jline.console.ConsoleReader;
- import jline.console.UserInterruptException;
- import jline.console.history.FileHistory;
- 
 +import org.apache.accumulo.core.Constants;
 +import org.apache.accumulo.core.client.AccumuloException;
 +import org.apache.accumulo.core.client.AccumuloSecurityException;
 +import org.apache.accumulo.core.client.ClientConfiguration;
 +import org.apache.accumulo.core.client.ClientConfiguration.ClientProperty;
 +import org.apache.accumulo.core.client.Connector;
 +import org.apache.accumulo.core.client.Instance;
 +import org.apache.accumulo.core.client.IteratorSetting;
 +import org.apache.accumulo.core.client.NamespaceNotFoundException;
 +import org.apache.accumulo.core.client.TableNotFoundException;
 +import org.apache.accumulo.core.client.ZooKeeperInstance;
 +import org.apache.accumulo.core.client.impl.ClientContext;
 +import org.apache.accumulo.core.client.impl.Tables;
 +import org.apache.accumulo.core.client.mock.MockInstance;
 +import org.apache.accumulo.core.client.security.tokens.AuthenticationToken;
 +import org.apache.accumulo.core.client.security.tokens.PasswordToken;
 +import org.apache.accumulo.core.conf.AccumuloConfiguration;
 +import org.apache.accumulo.core.conf.Property;
 +import org.apache.accumulo.core.conf.SiteConfiguration;
 +import org.apache.accumulo.core.data.Key;
 +import org.apache.accumulo.core.data.Value;
 +import org.apache.accumulo.core.data.thrift.TConstraintViolationSummary;
 +import org.apache.accumulo.core.tabletserver.thrift.ConstraintViolationException;
 +import org.apache.accumulo.core.trace.DistributedTrace;
 +import org.apache.accumulo.core.util.BadArgumentException;
 +import org.apache.accumulo.core.util.format.BinaryFormatter;
 +import org.apache.accumulo.core.util.format.DefaultFormatter;
 +import org.apache.accumulo.core.util.format.Formatter;
 +import org.apache.accumulo.core.util.format.FormatterFactory;
 +import org.apache.accumulo.core.volume.VolumeConfiguration;
 +import org.apache.accumulo.core.zookeeper.ZooUtil;
 +import org.apache.accumulo.shell.commands.AboutCommand;
 +import org.apache.accumulo.shell.commands.AddAuthsCommand;
 +import org.apache.accumulo.shell.commands.AddSplitsCommand;
 +import org.apache.accumulo.shell.commands.AuthenticateCommand;
 +import org.apache.accumulo.shell.commands.ByeCommand;
 +import org.apache.accumulo.shell.commands.ClasspathCommand;
 +import org.apache.accumulo.shell.commands.ClearCommand;
 +import org.apache.accumulo.shell.commands.CloneTableCommand;
 +import org.apache.accumulo.shell.commands.ClsCommand;
 +import org.apache.accumulo.shell.commands.CompactCommand;
 +import org.apache.accumulo.shell.commands.ConfigCommand;
 +import org.apache.accumulo.shell.commands.ConstraintCommand;
 +import org.apache.accumulo.shell.commands.CreateNamespaceCommand;
 +import org.apache.accumulo.shell.commands.CreateTableCommand;
 +import org.apache.accumulo.shell.commands.CreateUserCommand;
 +import org.apache.accumulo.shell.commands.DUCommand;
 +import org.apache.accumulo.shell.commands.DebugCommand;
 +import org.apache.accumulo.shell.commands.DeleteCommand;
 +import org.apache.accumulo.shell.commands.DeleteIterCommand;
 +import org.apache.accumulo.shell.commands.DeleteManyCommand;
 +import org.apache.accumulo.shell.commands.DeleteNamespaceCommand;
 +import org.apache.accumulo.shell.commands.DeleteRowsCommand;
 +import org.apache.accumulo.shell.commands.DeleteScanIterCommand;
 +import org.apache.accumulo.shell.commands.DeleteShellIterCommand;
 +import org.apache.accumulo.shell.commands.DeleteTableCommand;
 +import org.apache.accumulo.shell.commands.DeleteUserCommand;
 +import org.apache.accumulo.shell.commands.DropTableCommand;
 +import org.apache.accumulo.shell.commands.DropUserCommand;
 +import org.apache.accumulo.shell.commands.EGrepCommand;
 +import org.apache.accumulo.shell.commands.ExecfileCommand;
 +import org.apache.accumulo.shell.commands.ExitCommand;
 +import org.apache.accumulo.shell.commands.ExportTableCommand;
 +import org.apache.accumulo.shell.commands.ExtensionCommand;
 +import org.apache.accumulo.shell.commands.FateCommand;
 +import org.apache.accumulo.shell.commands.FlushCommand;
 +import org.apache.accumulo.shell.commands.FormatterCommand;
 +import org.apache.accumulo.shell.commands.GetAuthsCommand;
 +import org.apache.accumulo.shell.commands.GetGroupsCommand;
 +import org.apache.accumulo.shell.commands.GetSplitsCommand;
 +import org.apache.accumulo.shell.commands.GrantCommand;
 +import org.apache.accumulo.shell.commands.GrepCommand;
 +import org.apache.accumulo.shell.commands.HelpCommand;
 +import org.apache.accumulo.shell.commands.HiddenCommand;
 +import org.apache.accumulo.shell.commands.HistoryCommand;
 +import org.apache.accumulo.shell.commands.ImportDirectoryCommand;
 +import org.apache.accumulo.shell.commands.ImportTableCommand;
 +import org.apache.accumulo.shell.commands.InfoCommand;
 +import org.apache.accumulo.shell.commands.InsertCommand;
 +import org.apache.accumulo.shell.commands.InterpreterCommand;
 +import org.apache.accumulo.shell.commands.ListCompactionsCommand;
 +import org.apache.accumulo.shell.commands.ListIterCommand;
 +import org.apache.accumulo.shell.commands.ListScansCommand;
 +import org.apache.accumulo.shell.commands.ListShellIterCommand;
 +import org.apache.accumulo.shell.commands.MaxRowCommand;
 +import org.apache.accumulo.shell.commands.MergeCommand;
 +import org.apache.accumulo.shell.commands.NamespacePermissionsCommand;
 +import org.apache.accumulo.shell.commands.NamespacesCommand;
 +import org.apache.accumulo.shell.commands.NoTableCommand;
 +import org.apache.accumulo.shell.commands.OfflineCommand;
 +import org.apache.accumulo.shell.commands.OnlineCommand;
 +import org.apache.accumulo.shell.commands.OptUtil;
 +import org.apache.accumulo.shell.commands.PasswdCommand;
 +import org.apache.accumulo.shell.commands.PingCommand;
 +import org.apache.accumulo.shell.commands.QuestionCommand;
 +import org.apache.accumulo.shell.commands.QuitCommand;
 +import org.apache.accumulo.shell.commands.QuotedStringTokenizer;
 +import org.apache.accumulo.shell.commands.RenameNamespaceCommand;
 +import org.apache.accumulo.shell.commands.RenameTableCommand;
 +import org.apache.accumulo.shell.commands.RevokeCommand;
 +import org.apache.accumulo.shell.commands.ScanCommand;
 +import org.apache.accumulo.shell.commands.ScriptCommand;
 +import org.apache.accumulo.shell.commands.SetAuthsCommand;
 +import org.apache.accumulo.shell.commands.SetGroupsCommand;
 +import org.apache.accumulo.shell.commands.SetIterCommand;
 +import org.apache.accumulo.shell.commands.SetScanIterCommand;
 +import org.apache.accumulo.shell.commands.SetShellIterCommand;
 +import org.apache.accumulo.shell.commands.SleepCommand;
 +import org.apache.accumulo.shell.commands.SystemPermissionsCommand;
 +import org.apache.accumulo.shell.commands.TableCommand;
 +import org.apache.accumulo.shell.commands.TablePermissionsCommand;
 +import org.apache.accumulo.shell.commands.TablesCommand;
 +import org.apache.accumulo.shell.commands.TraceCommand;
 +import org.apache.accumulo.shell.commands.UserCommand;
 +import org.apache.accumulo.shell.commands.UserPermissionsCommand;
 +import org.apache.accumulo.shell.commands.UsersCommand;
 +import org.apache.accumulo.shell.commands.WhoAmICommand;
 +import org.apache.accumulo.start.classloader.vfs.AccumuloVFSClassLoader;
 +import org.apache.accumulo.start.classloader.vfs.ContextManager;
 +import org.apache.accumulo.start.spi.KeywordExecutable;
 +import org.apache.commons.cli.BasicParser;
 +import org.apache.commons.cli.CommandLine;
 +import org.apache.commons.cli.HelpFormatter;
 +import org.apache.commons.cli.MissingOptionException;
 +import org.apache.commons.cli.Option;
 +import org.apache.commons.cli.Options;
 +import org.apache.commons.cli.ParseException;
 +import org.apache.commons.vfs2.FileSystemException;
 +import org.apache.hadoop.fs.Path;
 +import org.apache.log4j.Level;
 +import org.apache.log4j.Logger;
 +
 +import com.beust.jcommander.JCommander;
 +import com.beust.jcommander.ParameterException;
 +import com.google.auto.service.AutoService;
 +
++import jline.console.ConsoleReader;
++import jline.console.UserInterruptException;
++import jline.console.history.FileHistory;
++
 +/**
 + * A convenient console interface to perform basic accumulo functions Includes auto-complete, help, and quoted strings with escape sequences
 + */
 +@AutoService(KeywordExecutable.class)
 +public class Shell extends ShellOptions implements KeywordExecutable {
 +  public static final Logger log = Logger.getLogger(Shell.class);
 +  private static final Logger audit = Logger.getLogger(Shell.class.getName() + ".audit");
 +
 +  public static final Charset CHARSET = ISO_8859_1;
 +  public static final int NO_FIXED_ARG_LENGTH_CHECK = -1;
 +  public static final String COMMENT_PREFIX = "#";
 +  public static final String HISTORY_DIR_NAME = ".accumulo";
 +  public static final String HISTORY_FILE_NAME = "shell_history.txt";
 +  private static final String SHELL_DESCRIPTION = "Shell - Apache Accumulo Interactive Shell";
 +
 +  protected int exitCode = 0;
 +  private String tableName;
 +  protected Instance instance;
 +  private Connector connector;
 +  protected ConsoleReader reader;
 +  private AuthenticationToken token;
 +  private final Class<? extends Formatter> defaultFormatterClass = DefaultFormatter.class;
 +  private final Class<? extends Formatter> binaryFormatterClass = BinaryFormatter.class;
 +  public Map<String,List<IteratorSetting>> scanIteratorOptions = new HashMap<String,List<IteratorSetting>>();
 +  public Map<String,List<IteratorSetting>> iteratorProfiles = new HashMap<String,List<IteratorSetting>>();
 +
 +  private Token rootToken;
 +  public final Map<String,Command> commandFactory = new TreeMap<String,Command>();
 +  public final Map<String,Command[]> commandGrouping = new TreeMap<String,Command[]>();
 +
 +  // exit if true
 +  private boolean exit = false;
 +
 +  // file to execute commands from
 +  protected File execFile = null;
 +  // single command to execute from the command line
 +  protected String execCommand = null;
 +  protected boolean verbose = true;
 +
 +  private boolean tabCompletion;
 +  private boolean disableAuthTimeout;
 +  private long authTimeout;
 +  private long lastUserActivity = System.nanoTime();
 +  private boolean logErrorsToConsole = false;
 +  private PrintWriter writer = null;
 +  private boolean masking = false;
 +
 +  public Shell() throws IOException {
 +    this(new ConsoleReader(), new PrintWriter(new OutputStreamWriter(System.out, System.getProperty("jline.WindowsTerminal.output.encoding",
 +        System.getProperty("file.encoding")))));
 +  }
 +
 +  public Shell(ConsoleReader reader, PrintWriter writer) {
 +    super();
 +    this.reader = reader;
 +    this.writer = writer;
 +  }
 +
 +  /**
 +   * Configures the shell using the provided options. Not for client use.
 +   *
 +   * @return true if the shell was successfully configured, false otherwise.
 +   */
 +  public boolean config(String... args) {
 +    ShellOptionsJC options = new ShellOptionsJC();
 +    JCommander jc = new JCommander();
 +
 +    jc.setProgramName("accumulo shell");
 +    jc.addObject(options);
 +    try {
 +      jc.parse(args);
 +    } catch (ParameterException e) {
 +      jc.usage();
 +      exitCode = 1;
 +      return false;
 +    }
 +
 +    if (options.isHelpEnabled()) {
 +      jc.usage();
 +      // Not an error
 +      exitCode = 0;
 +      return false;
 +    }
 +
 +    if (options.getUnrecognizedOptions() != null) {
 +      logError("Unrecognized Options: " + options.getUnrecognizedOptions().toString());
 +      jc.usage();
 +      exitCode = 1;
 +      return false;
 +    }
 +
 +    setDebugging(options.isDebugEnabled());
 +    authTimeout = TimeUnit.MINUTES.toNanos(options.getAuthTimeout());
 +    disableAuthTimeout = options.isAuthTimeoutDisabled();
 +
 +    ClientConfiguration clientConf;
 +    try {
 +      clientConf = options.getClientConfiguration();
 +    } catch (Exception e) {
 +      printException(e);
 +      return true;
 +    }
 +
 +    if (Boolean.parseBoolean(clientConf.get(ClientProperty.INSTANCE_RPC_SASL_ENABLED))) {
 +      log.debug("SASL is enabled, disabling authorization timeout");
 +      disableAuthTimeout = true;
 +    }
 +
 +    // get the options that were parsed
 +    final String user;
 +    try {
 +      user = options.getUsername();
 +    } catch (Exception e) {
 +      printException(e);
 +      return true;
 +    }
 +    String password = options.getPassword();
 +
 +    tabCompletion = !options.isTabCompletionDisabled();
 +
 +    // Use a fake (Mock), ZK, or HdfsZK Accumulo instance
 +    setInstance(options);
 +
 +    // AuthenticationToken options
 +    try {
 +      token = options.getAuthenticationToken();
 +    } catch (Exception e) {
 +      printException(e);
 +      return true;
 +    }
 +
 +    Map<String,String> loginOptions = options.getTokenProperties();
 +
 +    // process default parameters if unspecified
 +    try {
 +      final boolean hasToken = (token != null);
 +
 +      if (hasToken && password != null) {
 +        throw new ParameterException("Can not supply '--pass' option with '--tokenClass' option");
 +      }
 +
 +      Runtime.getRuntime().addShutdownHook(new Thread() {
 +        @Override
 +        public void run() {
 +          reader.getTerminal().setEchoEnabled(true);
 +        }
 +      });
 +
 +      if (hasToken) { // implied hasTokenOptions
 +        // Fully qualified name so we don't shadow java.util.Properties
 +        org.apache.accumulo.core.client.security.tokens.AuthenticationToken.Properties props;
 +        // and line wrap it because the package name is so long
 +        props = new org.apache.accumulo.core.client.security.tokens.AuthenticationToken.Properties();
 +
 +        if (!loginOptions.isEmpty()) {
 +          props.putAllStrings(loginOptions);
 +        }
 +        token.init(props);
 +      } else {
 +        // Read password if the user explicitly asked for it, or didn't specify anything at all
 +        if ("stdin".equals(password) || password == null) {
 +          password = reader.readLine("Password: ", '*');
 +        }
 +
 +        if (password == null) {
 +          // User cancel, e.g. Ctrl-D pressed
 +          throw new ParameterException("No password or token option supplied");
 +        } else {
 +          this.token = new PasswordToken(password);
 +        }
 +      }
 +
 +      if (!options.isFake()) {
 +        DistributedTrace.enable(InetAddress.getLocalHost().getHostName(), "shell", clientConf);
 +      }
 +
 +      this.setTableName("");
 +      connector = instance.getConnector(user, token);
 +
 +    } catch (Exception e) {
 +      printException(e);
 +      exitCode = 1;
 +      return false;
 +    }
 +
 +    // decide whether to execute commands from a file and quit
 +    if (options.getExecFile() != null) {
 +      execFile = options.getExecFile();
 +      verbose = false;
 +    } else if (options.getExecFileVerbose() != null) {
 +      execFile = options.getExecFileVerbose();
 +      verbose = true;
 +    }
 +    execCommand = options.getExecCommand();
 +    if (execCommand != null) {
 +      verbose = false;
 +    }
 +
 +    rootToken = new Token();
 +
 +    Command[] dataCommands = {new DeleteCommand(), new DeleteManyCommand(), new DeleteRowsCommand(), new EGrepCommand(), new FormatterCommand(),
 +        new InterpreterCommand(), new GrepCommand(), new ImportDirectoryCommand(), new InsertCommand(), new MaxRowCommand(), new ScanCommand()};
 +    Command[] debuggingCommands = {new ClasspathCommand(), new DebugCommand(), new ListScansCommand(), new ListCompactionsCommand(), new TraceCommand(),
 +        new PingCommand()};
 +    Command[] execCommands = {new ExecfileCommand(), new HistoryCommand(), new ExtensionCommand(), new ScriptCommand()};
 +    Command[] exitCommands = {new ByeCommand(), new ExitCommand(), new QuitCommand()};
 +    Command[] helpCommands = {new AboutCommand(), new HelpCommand(), new InfoCommand(), new QuestionCommand()};
 +    Command[] iteratorCommands = {new DeleteIterCommand(), new DeleteScanIterCommand(), new ListIterCommand(), new SetIterCommand(), new SetScanIterCommand(),
 +        new SetShellIterCommand(), new ListShellIterCommand(), new DeleteShellIterCommand()};
 +    Command[] otherCommands = {new HiddenCommand()};
 +    Command[] permissionsCommands = {new GrantCommand(), new RevokeCommand(), new SystemPermissionsCommand(), new TablePermissionsCommand(),
 +        new UserPermissionsCommand(), new NamespacePermissionsCommand()};
 +    Command[] stateCommands = {new AuthenticateCommand(), new ClsCommand(), new ClearCommand(), new FateCommand(), new NoTableCommand(), new SleepCommand(),
 +        new TableCommand(), new UserCommand(), new WhoAmICommand()};
 +    Command[] tableCommands = {new CloneTableCommand(), new ConfigCommand(), new CreateTableCommand(), new DeleteTableCommand(), new DropTableCommand(),
 +        new DUCommand(), new ExportTableCommand(), new ImportTableCommand(), new OfflineCommand(), new OnlineCommand(), new RenameTableCommand(),
 +        new TablesCommand(), new NamespacesCommand(), new CreateNamespaceCommand(), new DeleteNamespaceCommand(), new RenameNamespaceCommand()};
 +    Command[] tableControlCommands = {new AddSplitsCommand(), new CompactCommand(), new ConstraintCommand(), new FlushCommand(), new GetGroupsCommand(),
 +        new GetSplitsCommand(), new MergeCommand(), new SetGroupsCommand()};
 +    Command[] userCommands = {new AddAuthsCommand(), new CreateUserCommand(), new DeleteUserCommand(), new DropUserCommand(), new GetAuthsCommand(),
 +        new PasswdCommand(), new SetAuthsCommand(), new UsersCommand()};
 +    commandGrouping.put("-- Writing, Reading, and Removing Data --", dataCommands);
 +    commandGrouping.put("-- Debugging Commands -------------------", debuggingCommands);
 +    commandGrouping.put("-- Shell Execution Commands -------------", execCommands);
 +    commandGrouping.put("-- Exiting Commands ---------------------", exitCommands);
 +    commandGrouping.put("-- Help Commands ------------------------", helpCommands);
 +    commandGrouping.put("-- Iterator Configuration ---------------", iteratorCommands);
 +    commandGrouping.put("-- Permissions Administration Commands --", permissionsCommands);
 +    commandGrouping.put("-- Shell State Commands -----------------", stateCommands);
 +    commandGrouping.put("-- Table Administration Commands --------", tableCommands);
 +    commandGrouping.put("-- Table Control Commands ---------------", tableControlCommands);
 +    commandGrouping.put("-- User Administration Commands ---------", userCommands);
 +
 +    for (Command[] cmds : commandGrouping.values()) {
 +      for (Command cmd : cmds)
 +        commandFactory.put(cmd.getName(), cmd);
 +    }
 +    for (Command cmd : otherCommands) {
 +      commandFactory.put(cmd.getName(), cmd);
 +    }
 +    return true;
 +  }
 +
 +  /**
 +   * Sets the instance used by the shell based on the given options.
 +   *
 +   * @param options
 +   *          shell options
 +   */
 +  protected void setInstance(ShellOptionsJC options) {
 +    // should only be one set of instance options set
 +    instance = null;
 +    if (options.isFake()) {
 +      instance = new MockInstance("fake");
 +    } else {
 +      String instanceName, hosts;
 +      if (options.isHdfsZooInstance()) {
 +        instanceName = hosts = null;
 +      } else if (options.getZooKeeperInstance().size() > 0) {
 +        List<String> zkOpts = options.getZooKeeperInstance();
 +        instanceName = zkOpts.get(0);
 +        hosts = zkOpts.get(1);
 +      } else {
 +        instanceName = options.getZooKeeperInstanceName();
 +        hosts = options.getZooKeeperHosts();
 +      }
 +      try {
 +        instance = getZooInstance(instanceName, hosts, options.getClientConfiguration());
 +      } catch (Exception e) {
 +        throw new IllegalArgumentException("Unable to load client config from " + options.getClientConfigFile(), e);
 +      }
 +    }
 +  }
 +
 +  /**
 +   * Get the ZooKeepers. Use the value passed in (if there was one), then fall back to the ClientConf, finally trying the accumulo-site.xml.
 +   *
 +   * @param keepers
 +   *          ZooKeepers passed to the shell
 +   * @param clientConfig
 +   *          ClientConfiguration instance
 +   * @return The ZooKeepers to connect to
 +   */
 +  static String getZooKeepers(String keepers, ClientConfiguration clientConfig, AccumuloConfiguration conf) {
 +    if (null != keepers) {
 +      return keepers;
 +    }
 +
 +    if (clientConfig.containsKey(ClientProperty.INSTANCE_ZK_HOST.getKey())) {
 +      return clientConfig.get(ClientProperty.INSTANCE_ZK_HOST);
 +    }
 +
 +    return conf.get(Property.INSTANCE_ZK_HOST);
 +  }
 +
 +  /*
 +   * Takes instanceName and keepers as separate arguments, rather than just packaged into the clientConfig, so that we can fail over to accumulo-site.xml or
 +   * HDFS config if they're unspecified.
 +   */
 +  private static Instance getZooInstance(String instanceName, String keepersOption, ClientConfiguration clientConfig) {
 +    UUID instanceId = null;
 +    if (instanceName == null) {
 +      instanceName = clientConfig.get(ClientProperty.INSTANCE_NAME);
 +    }
 +    AccumuloConfiguration conf = SiteConfiguration.getInstance(ClientContext.convertClientConfig(clientConfig));
 +    String keepers = getZooKeepers(keepersOption, clientConfig, conf);
 +    if (instanceName == null) {
 +      Path instanceDir = new Path(VolumeConfiguration.getVolumeUris(conf)[0], "instance_id");
 +      instanceId = UUID.fromString(ZooUtil.getInstanceIDFromHdfs(instanceDir, conf));
 +    }
 +    if (instanceId != null) {
 +      return new ZooKeeperInstance(clientConfig.withInstance(instanceId).withZkHosts(keepers));
 +    } else {
 +      return new ZooKeeperInstance(clientConfig.withInstance(instanceName).withZkHosts(keepers));
 +    }
 +  }
 +
 +  public Connector getConnector() {
 +    return connector;
 +  }
 +
 +  public Instance getInstance() {
 +    return instance;
 +  }
 +
 +  public ClassLoader getClassLoader(final CommandLine cl, final Shell shellState) throws AccumuloException, TableNotFoundException, AccumuloSecurityException,
 +      IOException, FileSystemException {
 +
 +    boolean tables = cl.hasOption(OptUtil.tableOpt().getOpt()) || !shellState.getTableName().isEmpty();
 +    boolean namespaces = cl.hasOption(OptUtil.namespaceOpt().getOpt());
 +
 +    String classpath = null;
 +    Iterable<Entry<String,String>> tableProps;
 +
 +    if (namespaces) {
 +      try {
 +        tableProps = shellState.getConnector().namespaceOperations().getProperties(OptUtil.getNamespaceOpt(cl, shellState));
 +      } catch (NamespaceNotFoundException e) {
 +        throw new IllegalArgumentException(e);
 +      }
 +    } else if (tables) {
 +      tableProps = shellState.getConnector().tableOperations().getProperties(OptUtil.getTableOpt(cl, shellState));
 +    } else {
 +      throw new IllegalArgumentException("No table or namespace specified");
 +    }
 +    for (Entry<String,String> entry : tableProps) {
 +      if (entry.getKey().equals(Property.TABLE_CLASSPATH.getKey())) {
 +        classpath = entry.getValue();
 +      }
 +    }
 +
 +    ClassLoader classloader;
 +
 +    if (classpath != null && !classpath.equals("")) {
 +      shellState.getConnector().instanceOperations().getSystemConfiguration().get(Property.VFS_CONTEXT_CLASSPATH_PROPERTY.getKey() + classpath);
 +
 +      try {
 +        AccumuloVFSClassLoader.getContextManager().setContextConfig(new ContextManager.DefaultContextsConfig(new Iterable<Map.Entry<String,String>>() {
 +          @Override
 +          public Iterator<Entry<String,String>> iterator() {
 +            try {
 +              return shellState.getConnector().instanceOperations().getSystemConfiguration().entrySet().iterator();
 +            } catch (AccumuloException e) {
 +              throw new RuntimeException(e);
 +            } catch (AccumuloSecurityException e) {
 +              throw new RuntimeException(e);
 +            }
 +          }
 +        }));
 +      } catch (IllegalStateException ise) {}
 +
 +      classloader = AccumuloVFSClassLoader.getContextManager().getClassLoader(classpath);
 +    } else {
 +      classloader = AccumuloVFSClassLoader.getClassLoader();
 +    }
 +    return classloader;
 +  }
 +
 +  @Override
 +  public String keyword() {
 +    return "shell";
 +  }
 +
 +  @Override
 +  public void execute(final String[] args) throws IOException {
 +    try {
 +      if (!config(args)) {
 +        System.exit(getExitCode());
 +      }
 +
 +      System.exit(start());
 +    } finally {
 +      shutdown();
 +      DistributedTrace.disable();
 +    }
 +  }
 +
 +  public static void main(String args[]) throws IOException {
 +    new Shell().execute(args);
 +  }
 +
 +  public int start() throws IOException {
 +    String input;
 +    if (isVerbose())
 +      printInfo();
 +
 +    String home = System.getProperty("HOME");
 +    if (home == null)
 +      home = System.getenv("HOME");
 +    String configDir = home + "/" + HISTORY_DIR_NAME;
 +    String historyPath = configDir + "/" + HISTORY_FILE_NAME;
 +    File accumuloDir = new File(configDir);
 +    if (!accumuloDir.exists() && !accumuloDir.mkdirs())
 +      log.warn("Unable to make directory for history at " + accumuloDir);
 +    try {
 +      final FileHistory history = new FileHistory(new File(historyPath));
 +      reader.setHistory(history);
 +      // Add shutdown hook to flush file history, per jline javadocs
 +      Runtime.getRuntime().addShutdownHook(new Thread() {
 +        @Override
 +        public void run() {
 +          try {
 +            history.flush();
 +          } catch (IOException e) {
 +            log.warn("Could not flush history to file.");
 +          }
 +        }
 +      });
 +    } catch (IOException e) {
 +      log.warn("Unable to load history file at " + historyPath);
 +    }
 +
 +    // Turn Ctrl+C into Exception instead of JVM exit
 +    reader.setHandleUserInterrupt(true);
 +
 +    ShellCompletor userCompletor = null;
 +
 +    if (execFile != null) {
 +      java.util.Scanner scanner = new java.util.Scanner(execFile, UTF_8.name());
 +      try {
 +        while (scanner.hasNextLine() && !hasExited()) {
 +          execCommand(scanner.nextLine(), true, isVerbose());
 +        }
 +      } finally {
 +        scanner.close();
 +      }
 +    } else if (execCommand != null) {
 +      for (String command : execCommand.split("\n")) {
 +        execCommand(command, true, isVerbose());
 +      }
 +      return exitCode;
 +    }
 +
 +    while (true) {
 +      try {
 +        if (hasExited())
 +          return exitCode;
 +
 +        // If tab completion is true we need to reset
 +        if (tabCompletion) {
 +          if (userCompletor != null)
 +            reader.removeCompleter(userCompletor);
 +
 +          userCompletor = setupCompletion();
 +          reader.addCompleter(userCompletor);
 +        }
 +
 +        reader.setPrompt(getDefaultPrompt());
 +        input = reader.readLine();
 +        if (input == null) {
 +          reader.println();
 +          return exitCode;
 +        } // User Canceled (Ctrl+D)
 +
 +        execCommand(input, disableAuthTimeout, false);
 +      } catch (UserInterruptException uie) {
 +        // User Cancelled (Ctrl+C)
 +        reader.println();
 +
 +        String partialLine = uie.getPartialLine();
 +        if (partialLine == null || "".equals(uie.getPartialLine().trim())) {
 +          // No content, actually exit
 +          return exitCode;
 +        }
 +      } finally {
 +        reader.flush();
 +      }
 +    }
 +  }
 +
 +  public void shutdown() {
 +    if (reader != null) {
 +      reader.shutdown();
 +    }
 +  }
 +
 +  public void printInfo() throws IOException {
 +    reader.print("\n" + SHELL_DESCRIPTION + "\n" + "- \n" + "- version: " + Constants.VERSION + "\n" + "- instance name: "
 +        + connector.getInstance().getInstanceName() + "\n" + "- instance id: " + connector.getInstance().getInstanceID() + "\n" + "- \n"
 +        + "- type 'help' for a list of available commands\n" + "- \n");
 +    reader.flush();
 +  }
 +
 +  public void printVerboseInfo() throws IOException {
 +    StringBuilder sb = new StringBuilder("-\n");
 +    sb.append("- Current user: ").append(connector.whoami()).append("\n");
 +    if (execFile != null)
 +      sb.append("- Executing commands from: ").append(execFile).append("\n");
 +    if (disableAuthTimeout)
 +      sb.append("- Authorization timeout: disabled\n");
 +    else
 +      sb.append("- Authorization timeout: ").append(String.format("%ds%n", TimeUnit.NANOSECONDS.toSeconds(authTimeout)));
 +    sb.append("- Debug: ").append(isDebuggingEnabled() ? "on" : "off").append("\n");
 +    if (!scanIteratorOptions.isEmpty()) {
 +      for (Entry<String,List<IteratorSetting>> entry : scanIteratorOptions.entrySet()) {
 +        sb.append("- Session scan iterators for table ").append(entry.getKey()).append(":\n");
 +        for (IteratorSetting setting : entry.getValue()) {
 +          sb.append("-    Iterator ").append(setting.getName()).append(" options:\n");
 +          sb.append("-        ").append("iteratorPriority").append(" = ").append(setting.getPriority()).append("\n");
 +          sb.append("-        ").append("iteratorClassName").append(" = ").append(setting.getIteratorClass()).append("\n");
 +          for (Entry<String,String> optEntry : setting.getOptions().entrySet()) {
 +            sb.append("-        ").append(optEntry.getKey()).append(" = ").append(optEntry.getValue()).append("\n");
 +          }
 +        }
 +      }
 +    }
 +    sb.append("-\n");
 +    reader.print(sb.toString());
 +  }
 +
 +  public String getDefaultPrompt() {
 +    return connector.whoami() + "@" + connector.getInstance().getInstanceName() + (getTableName().isEmpty() ? "" : " ") + getTableName() + "> ";
 +  }
 +
 +  public void execCommand(String input, boolean ignoreAuthTimeout, boolean echoPrompt) throws IOException {
 +    audit.log(Level.INFO, getDefaultPrompt() + input);
 +    if (echoPrompt) {
 +      reader.print(getDefaultPrompt());
 +      reader.println(input);
 +    }
 +
 +    if (input.startsWith(COMMENT_PREFIX)) {
 +      return;
 +    }
 +
 +    String fields[];
 +    try {
 +      fields = new QuotedStringTokenizer(input).getTokens();
 +    } catch (BadArgumentException e) {
 +      printException(e);
 +      ++exitCode;
 +      return;
 +    }
 +    if (fields.length == 0)
 +      return;
 +
 +    String command = fields[0];
 +    fields = fields.length > 1 ? Arrays.copyOfRange(fields, 1, fields.length) : new String[] {};
 +
 +    Command sc = null;
 +    if (command.length() > 0) {
 +      try {
 +        // Obtain the command from the command table
 +        sc = commandFactory.get(command);
 +        if (sc == null) {
 +          reader.println(String.format("Unknown command \"%s\".  Enter \"help\" for a list possible commands.", command));
 +          reader.flush();
 +          return;
 +        }
 +
 +        long duration = System.nanoTime() - lastUserActivity;
 +        if (!(sc instanceof ExitCommand) && !ignoreAuthTimeout && (duration < 0 || duration > authTimeout)) {
 +          reader.println("Shell has been idle for too long. Please re-authenticate.");
 +          boolean authFailed = true;
 +          do {
 +            String pwd = readMaskedLine("Enter current password for '" + connector.whoami() + "': ", '*');
 +            if (pwd == null) {
 +              reader.println();
 +              return;
 +            } // user canceled
 +
 +            try {
 +              authFailed = !connector.securityOperations().authenticateUser(connector.whoami(), new PasswordToken(pwd));
 +            } catch (Exception e) {
 +              ++exitCode;
 +              printException(e);
 +            }
 +
 +            if (authFailed)
 +              reader.print("Invalid password. ");
 +          } while (authFailed);
 +          lastUserActivity = System.nanoTime();
 +        }
 +
 +        // Get the options from the command on how to parse the string
 +        Options parseOpts = sc.getOptionsWithHelp();
 +
 +        // Parse the string using the given options
 +        CommandLine cl = new BasicParser().parse(parseOpts, fields);
 +
 +        int actualArgLen = cl.getArgs().length;
 +        int expectedArgLen = sc.numArgs();
 +        if (cl.hasOption(helpOption)) {
 +          // Display help if asked to; otherwise execute the command
 +          sc.printHelp(this);
 +        } else if (expectedArgLen != NO_FIXED_ARG_LENGTH_CHECK && actualArgLen != expectedArgLen) {
 +          ++exitCode;
 +          // Check for valid number of fixed arguments (if not
 +          // negative; negative means it is not checked, for
 +          // vararg-like commands)
 +          printException(new IllegalArgumentException(String.format("Expected %d argument%s. There %s %d.", expectedArgLen, expectedArgLen == 1 ? "" : "s",
 +              actualArgLen == 1 ? "was" : "were", actualArgLen)));
 +          sc.printHelp(this);
 +        } else {
 +          int tmpCode = sc.execute(input, cl, this);
 +          exitCode += tmpCode;
 +          reader.flush();
 +        }
 +
 +      } catch (ConstraintViolationException e) {
 +        ++exitCode;
 +        printConstraintViolationException(e);
 +      } catch (TableNotFoundException e) {
 +        ++exitCode;
 +        if (getTableName().equals(e.getTableName()))
 +          setTableName("");
 +        printException(e);
 +      } catch (ParseException e) {
 +        // not really an error if the exception is a missing required
 +        // option when the user is asking for help
 +        if (!(e instanceof MissingOptionException && (Arrays.asList(fields).contains("-" + helpOption) || Arrays.asList(fields).contains("--" + helpLongOption)))) {
 +          ++exitCode;
 +          printException(e);
 +        }
 +        if (sc != null)
 +          sc.printHelp(this);
 +      } catch (UserInterruptException e) {
 +        ++exitCode;
 +      } catch (Exception e) {
 +        ++exitCode;
 +        printException(e);
 +      }
 +    } else {
 +      ++exitCode;
 +      printException(new BadArgumentException("Unrecognized empty command", command, -1));
 +    }
 +    reader.flush();
 +  }
 +
 +  /**
 +   * The command tree is built in reverse so that the references are more easily linked up. There is some code in token to allow forward building of the command
 +   * tree.
 +   */
 +  private ShellCompletor setupCompletion() {
 +    rootToken = new Token();
 +
 +    Set<String> tableNames = null;
 +    try {
 +      tableNames = connector.tableOperations().list();
 +    } catch (Exception e) {
 +      log.debug("Unable to obtain list of tables", e);
 +      tableNames = Collections.emptySet();
 +    }
 +
 +    Set<String> userlist = null;
 +    try {
 +      userlist = connector.securityOperations().listLocalUsers();
 +    } catch (Exception e) {
 +      log.debug("Unable to obtain list of users", e);
 +      userlist = Collections.emptySet();
 +    }
 +
 +    Set<String> namespaces = null;
 +    try {
 +      namespaces = connector.namespaceOperations().list();
 +    } catch (Exception e) {
 +      log.debug("Unable to obtain list of namespaces", e);
 +      namespaces = Collections.emptySet();
 +    }
 +
 +    Map<Command.CompletionSet,Set<String>> options = new HashMap<Command.CompletionSet,Set<String>>();
 +
 +    Set<String> commands = new HashSet<String>();
 +    for (String a : commandFactory.keySet())
 +      commands.add(a);
 +
 +    Set<String> modifiedUserlist = new HashSet<String>();
 +    Set<String> modifiedTablenames = new HashSet<String>();
 +    Set<String> modifiedNamespaces = new HashSet<String>();
 +
 +    for (String a : tableNames)
 +      modifiedTablenames.add(a.replaceAll("([\\s'\"])", "\\\\$1"));
 +    for (String a : userlist)
 +      modifiedUserlist.add(a.replaceAll("([\\s'\"])", "\\\\$1"));
 +    for (String a : namespaces) {
 +      String b = a.replaceAll("([\\s'\"])", "\\\\$1");
 +      modifiedNamespaces.add(b.isEmpty() ? "\"\"" : b);
 +    }
 +
 +    options.put(Command.CompletionSet.USERNAMES, modifiedUserlist);
 +    options.put(Command.CompletionSet.TABLENAMES, modifiedTablenames);
 +    options.put(Command.CompletionSet.NAMESPACES, modifiedNamespaces);
 +    options.put(Command.CompletionSet.COMMANDS, commands);
 +
 +    for (Command[] cmdGroup : commandGrouping.values()) {
 +      for (Command c : cmdGroup) {
 +        c.getOptionsWithHelp(); // prep the options for the command
 +        // so that the completion can
 +        // include them
 +        c.registerCompletion(rootToken, options);
 +      }
 +    }
 +    return new ShellCompletor(rootToken, options);
 +  }
 +
 +  /**
 +   * The Command class represents a command to be run in the shell. It contains the methods to execute along with some methods to help tab completion, and
 +   * return the command name, help, and usage.
 +   */
 +  public static abstract class Command {
 +    // Helper methods for completion
 +    public enum CompletionSet {
 +      TABLENAMES, USERNAMES, COMMANDS, NAMESPACES
 +    }
 +
 +    public void registerCompletionGeneral(Token root, Set<String> args, boolean caseSens) {
 +      Token t = new Token(args);
 +      t.setCaseSensitive(caseSens);
 +
 +      Token command = new Token(getName());
 +      command.addSubcommand(t);
 +
 +      root.addSubcommand(command);
 +    }
 +
 +    public void registerCompletionForTables(Token root, Map<CompletionSet,Set<String>> completionSet) {
 +      registerCompletionGeneral(root, completionSet.get(CompletionSet.TABLENAMES), true);
 +    }
 +
 +    public void registerCompletionForUsers(Token root, Map<CompletionSet,Set<String>> completionSet) {
 +      registerCompletionGeneral(root, completionSet.get(CompletionSet.USERNAMES), true);
 +    }
 +
 +    public void registerCompletionForCommands(Token root, Map<CompletionSet,Set<String>> completionSet) {
 +      registerCompletionGeneral(root, completionSet.get(CompletionSet.COMMANDS), false);
 +    }
 +
 +    public void registerCompletionForNamespaces(Token root, Map<CompletionSet,Set<String>> completionSet) {
 +      registerCompletionGeneral(root, completionSet.get(CompletionSet.NAMESPACES), true);
 +    }
 +
 +    // abstract methods to override
 +    public abstract int execute(String fullCommand, CommandLine cl, Shell shellState) throws Exception;
 +
 +    public abstract String description();
 +
 +    /**
 +     * If the number of arguments is not always zero (not including those arguments handled through Options), make sure to override the {@link #usage()} method.
 +     * Otherwise, {@link #usage()} does need to be overridden.
 +     */
 +    public abstract int numArgs();
 +
 +    // OPTIONAL methods to override:
 +
 +    // the general version of getname uses reflection to get the class name
 +    // and then cuts off the suffix -Command to get the name of the command
 +    public String getName() {
 +      String s = this.getClass().getName();
 +      int st = Math.max(s.lastIndexOf('$'), s.lastIndexOf('.'));
 +      int i = s.indexOf("Command");
 +      return i > 0 ? s.substring(st + 1, i).toLowerCase(Locale.ENGLISH) : null;
 +    }
 +
 +    // The general version of this method adds the name
 +    // of the command to the completion tree
 +    public void registerCompletion(Token root, Map<CompletionSet,Set<String>> completion_set) {
 +      root.addSubcommand(new Token(getName()));
 +    }
 +
 +    // The general version of this method uses the HelpFormatter
 +    // that comes with the apache Options package to print out the help
 +    public final void printHelp(Shell shellState) {
 +      shellState.printHelp(usage(), "description: " + this.description(), getOptionsWithHelp());
 +    }
 +
 +    public final void printHelp(Shell shellState, int width) {
 +      shellState.printHelp(usage(), "description: " + this.description(), getOptionsWithHelp(), width);
 +    }
 +
 +    // Get options with help
 +    public final Options getOptionsWithHelp() {
 +      Options opts = getOptions();
 +      opts.addOption(new Option(helpOption, helpLongOption, false, "display this help"));
 +      return opts;
 +    }
 +
 +    // General usage is just the command
 +    public String usage() {
 +      return getName();
 +    }
 +
 +    // General Options are empty
 +    public Options getOptions() {
 +      return new Options();
 +    }
 +  }
 +
 +  public interface PrintLine {
 +    void print(String s);
 +
 +    void close();
 +  }
 +
 +  public static class PrintShell implements PrintLine {
 +    ConsoleReader reader;
 +
 +    public PrintShell(ConsoleReader reader) {
 +      this.reader = reader;
 +    }
 +
 +    @Override
 +    public void print(String s) {
 +      try {
 +        reader.println(s);
 +      } catch (Exception ex) {
 +        throw new RuntimeException(ex);
 +      }
 +    }
 +
 +    @Override
 +    public void close() {}
 +  };
 +
 +  public static class PrintFile implements PrintLine {
 +    PrintWriter writer;
 +
 +    public PrintFile(String filename) throws FileNotFoundException {
 +      writer = new PrintWriter(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(filename), UTF_8)));
 +    }
 +
 +    @Override
 +    public void print(String s) {
 +      writer.println(s);
 +    }
 +
 +    @Override
 +    public void close() {
 +      writer.close();
 +    }
 +  };
 +
 +  public final void printLines(Iterator<String> lines, boolean paginate) throws IOException {
 +    printLines(lines, paginate, null);
 +  }
 +
 +  public final void printLines(Iterator<String> lines, boolean paginate, PrintLine out) throws IOException {
 +    int linesPrinted = 0;
 +    String prompt = "-- hit any key to continue or 'q' to quit --";
 +    int lastPromptLength = prompt.length();
 +    int termWidth = reader.getTerminal().getWidth();
 +    int maxLines = reader.getTerminal().getHeight();
 +
 +    String peek = null;
 +    while (lines.hasNext()) {
 +      String nextLine = lines.next();
 +      if (nextLine == null)
 +        continue;
 +      for (String line : nextLine.split("\\n")) {
 +        if (out == null) {
 +          if (peek != null) {
 +            reader.println(peek);
 +            if (paginate) {
 +              linesPrinted += peek.length() == 0 ? 0 : Math.ceil(peek.length() * 1.0 / termWidth);
 +
 +              // check if displaying the next line would result in
 +              // scrolling off the screen
 +              if (linesPrinted + Math.ceil(lastPromptLength * 1.0 / termWidth) + Math.ceil(prompt.length() * 1.0 / termWidth)
 +                  + Math.ceil(line.length() * 1.0 / termWidth) > maxLines) {
 +                linesPrinted = 0;
 +                int numdashes = (termWidth - prompt.length()) / 2;
 +                String nextPrompt = repeat("-", numdashes) + prompt + repeat("-", numdashes);
 +                lastPromptLength = nextPrompt.length();
 +                reader.print(nextPrompt);
 +                reader.flush();
 +
 +                if (Character.toUpperCase((char) reader.readCharacter()) == 'Q') {
 +                  reader.println();
 +                  return;
 +                }
 +                reader.println();
 +                termWidth = reader.getTerminal().getWidth();
 +                maxLines = reader.getTerminal().getHeight();
 +              }
 +            }
 +          }
 +          peek = line;
 +        } else {
 +          out.print(line);
 +        }
 +      }
 +    }
 +    if (out == null && peek != null) {
 +      reader.println(peek);
 +    }
 +  }
 +
 +  public final void printRecords(Iterable<Entry<Key,Value>> scanner, boolean printTimestamps, boolean paginate, Class<? extends Formatter> formatterClass,
 +      PrintLine outFile) throws IOException {
 +    printLines(FormatterFactory.getFormatter(formatterClass, scanner, printTimestamps), paginate, outFile);
 +  }
 +
 +  public final void printRecords(Iterable<Entry<Key,Value>> scanner, boolean printTimestamps, boolean paginate, Class<? extends Formatter> formatterClass)
 +      throws IOException {
 +    printLines(FormatterFactory.getFormatter(formatterClass, scanner, printTimestamps), paginate);
 +  }
 +
 +  public final void printBinaryRecords(Iterable<Entry<Key,Value>> scanner, boolean printTimestamps, boolean paginate, PrintLine outFile) throws IOException {
 +    printLines(FormatterFactory.getFormatter(binaryFormatterClass, scanner, printTimestamps), paginate, outFile);
 +  }
 +
 +  public final void printBinaryRecords(Iterable<Entry<Key,Value>> scanner, boolean printTimestamps, boolean paginate) throws IOException {
 +    printLines(FormatterFactory.getFormatter(binaryFormatterClass, scanner, printTimestamps), paginate);
 +  }
 +
 +  public static String repeat(String s, int c) {
 +    StringBuilder sb = new StringBuilder();
 +    for (int i = 0; i < c; i++)
 +      sb.append(s);
 +    return sb.toString();
 +  }
 +
 +  public void checkTableState() {
 +    if (getTableName().isEmpty())
 +      throw new IllegalStateException(
 +          "Not in a table context. Please use 'table <tableName>' to switch to a table, or use '-t' to specify a table if option is available.");
 +  }
 +
 +  private final void printConstraintViolationException(ConstraintViolationException cve) {
 +    printException(cve, "");
 +    int COL1 = 50, COL2 = 14;
 +    int col3 = Math.max(1, Math.min(Integer.MAX_VALUE, reader.getTerminal().getWidth() - COL1 - COL2 - 6));
 +    logError(String.format("%" + COL1 + "s-+-%" + COL2 + "s-+-%" + col3 + "s%n", repeat("-", COL1), repeat("-", COL2), repeat("-", col3)));
 +    logError(String.format("%-" + COL1 + "s | %" + COL2 + "s | %-" + col3 + "s%n", "Constraint class", "Violation code", "Violation Description"));
 +    logError(String.format("%" + COL1 + "s-+-%" + COL2 + "s-+-%" + col3 + "s%n", repeat("-", COL1), repeat("-", COL2), repeat("-", col3)));
 +    for (TConstraintViolationSummary cvs : cve.violationSummaries)
 +      logError(String.format("%-" + COL1 + "s | %" + COL2 + "d | %-" + col3 + "s%n", cvs.constrainClass, cvs.violationCode, cvs.violationDescription));
 +    logError(String.format("%" + COL1 + "s-+-%" + COL2 + "s-+-%" + col3 + "s%n", repeat("-", COL1), repeat("-", COL2), repeat("-", col3)));
 +  }
 +
 +  public final void printException(Exception e) {
 +    printException(e, e.getMessage());
 +  }
 +
 +  private final void printException(Exception e, String msg) {
 +    logError(e.getClass().getName() + (msg != null ? ": " + msg : ""));
 +    log.debug(e.getClass().getName() + (msg != null ? ": " + msg : ""), e);
 +  }
 +
 +  public static final void setDebugging(boolean debuggingEnabled) {
 +    Logger.getLogger(Constants.CORE_PACKAGE_NAME).setLevel(debuggingEnabled ? Level.TRACE : Level.INFO);
 +    Logger.getLogger(Shell.class.getPackage().getName()).setLevel(debuggingEnabled ? Level.TRACE : Level.INFO);
 +  }
 +
 +  public static final boolean isDebuggingEnabled() {
 +    return Logger.getLogger(Constants.CORE_PACKAGE_NAME).isTraceEnabled();
 +  }
 +
 +  private final void printHelp(String usage, String description, Options opts) {
 +    printHelp(usage, description, opts, Integer.MAX_VALUE);
 +  }
 +
 +  private final void printHelp(String usage, String description, Options opts, int width) {
 +    // TODO Use the OutputStream from the JLine ConsoleReader if we can ever get access to it
 +    new HelpFormatter().printHelp(writer, width, usage, description, opts, 2, 5, null, true);
 +    writer.flush();
 +  }
 +
 +  public int getExitCode() {
 +    return exitCode;
 +  }
 +
 +  public void resetExitCode() {
 +    exitCode = 0;
 +  }
 +
 +  public void setExit(boolean exit) {
 +    this.exit = exit;
 +  }
 +
 +  public boolean getExit() {
 +    return this.exit;
 +  }
 +
 +  public boolean isVerbose() {
 +    return verbose;
 +  }
 +
 +  public void setTableName(String tableName) {
 +    this.tableName = (tableName == null || tableName.isEmpty()) ? "" : Tables.qualified(tableName);
 +  }
 +
 +  public String getTableName() {
 +    return tableName;
 +  }
 +
 +  public ConsoleReader getReader() {
 +    return reader;
 +  }
 +
 +  public void updateUser(String principal, AuthenticationToken token) throws AccumuloException, AccumuloSecurityException {
 +    connector = instance.getConnector(principal, token);
 +    this.token = token;
 +  }
 +
 +  public String getPrincipal() {
 +    return connector.whoami();
 +  }
 +
 +  public AuthenticationToken getToken() {
 +    return token;
 +  }
 +
 +  /**
 +   * Return the formatter for the current table.
 +   *
 +   * @return the formatter class for the current table
 +   */
 +  public Class<? extends Formatter> getFormatter() {
 +    return getFormatter(this.tableName);
 +  }
 +
 +  /**
 +   * Return the formatter for the given table.
 +   *
 +   * @param tableName
 +   *          the table name
 +   * @return the formatter class for the given table
 +   */
 +  public Class<? extends Formatter> getFormatter(String tableName) {
 +    Class<? extends Formatter> formatter = FormatterCommand.getCurrentFormatter(tableName, this);
 +
 +    if (null == formatter) {
 +      logError("Could not load the specified formatter. Using the DefaultFormatter");
 +      return this.defaultFormatterClass;
 +    } else {
 +      return formatter;
 +    }
 +  }
 +
 +  public void setLogErrorsToConsole() {
 +    this.logErrorsToConsole = true;
 +  }
 +
 +  private void logError(String s) {
 +    log.error(s);
 +    if (logErrorsToConsole) {
 +      try {
 +        reader.println("ERROR: " + s);
 +        reader.flush();
 +      } catch (IOException e) {}
 +    }
 +  }
 +
 +  public String readMaskedLine(String prompt, Character mask) throws IOException {
 +    this.masking = true;
 +    String s = reader.readLine(prompt, mask);
 +    this.masking = false;
 +    return s;
 +  }
 +
 +  public boolean isMasking() {
 +    return masking;
 +  }
 +
 +  public boolean hasExited() {
 +    return exit;
 +  }
 +
 +  public boolean isTabCompletion() {
 +    return tabCompletion;
 +  }
 +
 +}

http://git-wip-us.apache.org/repos/asf/accumulo/blob/6df97b89/shell/src/main/java/org/apache/accumulo/shell/commands/CompactCommand.java
----------------------------------------------------------------------
diff --cc shell/src/main/java/org/apache/accumulo/shell/commands/CompactCommand.java
index 33a8d45,0000000..f183b25
mode 100644,000000..100644
--- a/shell/src/main/java/org/apache/accumulo/shell/commands/CompactCommand.java
+++ b/shell/src/main/java/org/apache/accumulo/shell/commands/CompactCommand.java
@@@ -1,219 -1,0 +1,223 @@@
 +/*
 + * 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.
 + */
 +package org.apache.accumulo.shell.commands;
 +
 +import java.util.ArrayList;
 +import java.util.HashMap;
 +import java.util.List;
 +import java.util.Map;
 +
 +import org.apache.accumulo.core.client.AccumuloException;
 +import org.apache.accumulo.core.client.AccumuloSecurityException;
 +import org.apache.accumulo.core.client.IteratorSetting;
 +import org.apache.accumulo.core.client.TableNotFoundException;
 +import org.apache.accumulo.core.client.admin.CompactionConfig;
 +import org.apache.accumulo.core.client.admin.CompactionStrategyConfig;
 +import org.apache.accumulo.core.compaction.CompactionSettings;
 +import org.apache.accumulo.shell.Shell;
 +import org.apache.commons.cli.CommandLine;
 +import org.apache.commons.cli.Option;
 +import org.apache.commons.cli.Options;
 +
 +public class CompactCommand extends TableOperation {
 +  private Option noFlushOption, waitOpt, profileOpt, cancelOpt, strategyOpt, strategyConfigOpt;
 +
 +  // file selection and file output options
 +  private Option enameOption, epathOption, sizeLtOption, sizeGtOption, minFilesOption, outBlockSizeOpt, outHdfsBlockSizeOpt, outIndexBlockSizeOpt,
 +      outCompressionOpt, outReplication;
 +
 +  private CompactionConfig compactionConfig = null;
 +
 +  private boolean cancel = false;
 +
 +  @Override
 +  public String description() {
 +    return "Initiates a major compaction on tablets within the specified range that have one or more files.  If no file selection options are specified, then "
 +        + "all files will be compacted.  Options that configure output settings are only applied to this compaction and not later compactions.  If multiple "
 +        + "concurrent user initiated compactions specify iterators or a compaction strategy, then all but one will fail to start.";
 +  }
 +
 +  @Override
 +  protected void doTableOp(final Shell shellState, final String tableName) throws AccumuloException, AccumuloSecurityException {
 +    // compact the tables
 +
 +    if (cancel) {
 +      try {
 +        shellState.getConnector().tableOperations().cancelCompaction(tableName);
 +        Shell.log.info("Compaction canceled for table " + tableName);
 +      } catch (TableNotFoundException e) {
 +        throw new AccumuloException(e);
 +      }
 +    } else {
 +      try {
 +        if (compactionConfig.getWait()) {
 +          Shell.log.info("Compacting table ...");
 +        }
 +
++        for (IteratorSetting iteratorSetting : compactionConfig.getIterators()) {
++          ScanCommand.ensureTserversCanLoadIterator(shellState, tableName, iteratorSetting.getIteratorClass());
++        }
++
 +        shellState.getConnector().tableOperations().compact(tableName, compactionConfig);
 +
 +        Shell.log.info("Compaction of table " + tableName + " " + (compactionConfig.getWait() ? "completed" : "started") + " for given range");
 +      } catch (Exception ex) {
 +        throw new AccumuloException(ex);
 +      }
 +    }
 +  }
 +
 +  private void put(CommandLine cl, Map<String,String> opts, Option opt, CompactionSettings setting) {
 +    if (cl.hasOption(opt.getLongOpt()))
 +      setting.put(opts, cl.getOptionValue(opt.getLongOpt()));
 +  }
 +
 +  private Map<String,String> getConfigurableCompactionStrategyOpts(CommandLine cl) {
 +    Map<String,String> opts = new HashMap<>();
 +
 +    put(cl, opts, enameOption, CompactionSettings.SF_NAME_RE_OPT);
 +    put(cl, opts, epathOption, CompactionSettings.SF_PATH_RE_OPT);
 +    put(cl, opts, sizeLtOption, CompactionSettings.SF_LT_ESIZE_OPT);
 +    put(cl, opts, sizeGtOption, CompactionSettings.SF_GT_ESIZE_OPT);
 +    put(cl, opts, minFilesOption, CompactionSettings.MIN_FILES_OPT);
 +    put(cl, opts, outCompressionOpt, CompactionSettings.OUTPUT_COMPRESSION_OPT);
 +    put(cl, opts, outBlockSizeOpt, CompactionSettings.OUTPUT_BLOCK_SIZE_OPT);
 +    put(cl, opts, outHdfsBlockSizeOpt, CompactionSettings.OUTPUT_HDFS_BLOCK_SIZE_OPT);
 +    put(cl, opts, outIndexBlockSizeOpt, CompactionSettings.OUTPUT_INDEX_BLOCK_SIZE_OPT);
 +    put(cl, opts, outReplication, CompactionSettings.OUTPUT_REPLICATION_OPT);
 +
 +    return opts;
 +  }
 +
 +  @Override
 +  public int execute(final String fullCommand, final CommandLine cl, final Shell shellState) throws Exception {
 +
 +    if (cl.hasOption(cancelOpt.getLongOpt())) {
 +      cancel = true;
 +
 +      if (cl.getOptions().length > 2) {
 +        throw new IllegalArgumentException("Can not specify other options with cancel");
 +      }
 +    } else {
 +      cancel = false;
 +    }
 +
 +    compactionConfig = new CompactionConfig();
 +
 +    compactionConfig.setFlush(!cl.hasOption(noFlushOption.getOpt()));
 +    compactionConfig.setWait(cl.hasOption(waitOpt.getOpt()));
 +    compactionConfig.setStartRow(OptUtil.getStartRow(cl));
 +    compactionConfig.setEndRow(OptUtil.getEndRow(cl));
 +
 +    if (cl.hasOption(profileOpt.getOpt())) {
 +      List<IteratorSetting> iterators = shellState.iteratorProfiles.get(cl.getOptionValue(profileOpt.getOpt()));
 +      if (iterators == null) {
 +        Shell.log.error("Profile " + cl.getOptionValue(profileOpt.getOpt()) + " does not exist");
 +        return -1;
 +      }
 +
 +      compactionConfig.setIterators(new ArrayList<>(iterators));
 +    }
 +
 +    Map<String,String> configurableCompactOpt = getConfigurableCompactionStrategyOpts(cl);
 +
 +    if (cl.hasOption(strategyOpt.getOpt())) {
 +      if (configurableCompactOpt.size() > 0)
 +        throw new IllegalArgumentException("Can not specify compaction strategy with file selection and file output options.");
 +
 +      CompactionStrategyConfig csc = new CompactionStrategyConfig(cl.getOptionValue(strategyOpt.getOpt()));
 +      if (cl.hasOption(strategyConfigOpt.getOpt())) {
 +        Map<String,String> props = new HashMap<>();
 +        String[] keyVals = cl.getOptionValue(strategyConfigOpt.getOpt()).split(",");
 +        for (String keyVal : keyVals) {
 +          String[] sa = keyVal.split("=");
 +          props.put(sa[0], sa[1]);
 +        }
 +
 +        csc.setOptions(props);
 +      }
 +
 +      compactionConfig.setCompactionStrategy(csc);
 +    }
 +
 +    if (configurableCompactOpt.size() > 0) {
 +      CompactionStrategyConfig csc = new CompactionStrategyConfig("org.apache.accumulo.tserver.compaction.strategies.ConfigurableCompactionStrategy");
 +      csc.setOptions(configurableCompactOpt);
 +      compactionConfig.setCompactionStrategy(csc);
 +    }
 +
 +    return super.execute(fullCommand, cl, shellState);
 +  }
 +
 +  private Option newLAO(String lopt, String desc) {
 +    return new Option(null, lopt, true, desc);
 +  }
 +
 +  @Override
 +  public Options getOptions() {
 +    final Options opts = super.getOptions();
 +
 +    opts.addOption(OptUtil.startRowOpt());
 +    opts.addOption(OptUtil.endRowOpt());
 +    noFlushOption = new Option("nf", "noFlush", false, "do not flush table data in memory before compacting.");
 +    opts.addOption(noFlushOption);
 +    waitOpt = new Option("w", "wait", false, "wait for compact to finish");
 +    opts.addOption(waitOpt);
 +
 +    profileOpt = new Option("pn", "profile", true, "Iterator profile name.");
 +    profileOpt.setArgName("profile");
 +    opts.addOption(profileOpt);
 +
 +    strategyOpt = new Option("s", "strategy", true, "compaction strategy class name");
 +    opts.addOption(strategyOpt);
 +    strategyConfigOpt = new Option("sc", "strategyConfig", true, "Key value options for compaction strategy.  Expects <prop>=<value>{,<prop>=<value>}");
 +    opts.addOption(strategyConfigOpt);
 +
 +    cancelOpt = new Option(null, "cancel", false, "cancel user initiated compactions");
 +    opts.addOption(cancelOpt);
 +
 +    enameOption = newLAO("sf-ename", "Select files using regular expression to match file names. Only matches against last part of path.");
 +    opts.addOption(enameOption);
 +    epathOption = newLAO("sf-epath", "Select files using regular expression to match file paths to compact. Matches against full path.");
 +    opts.addOption(epathOption);
 +    sizeLtOption = newLAO("sf-lt-esize",
 +        "Selects files less than specified size.  Uses the estimated size of file in metadata table.  Can use K,M, and G suffixes");
 +    opts.addOption(sizeLtOption);
 +    sizeGtOption = newLAO("sf-gt-esize",
 +        "Selects files greater than specified size.  Uses the estimated size of file in metadata table.  Can use K,M, and G suffixes");
 +    opts.addOption(sizeGtOption);
 +    minFilesOption = newLAO("min-files",
 +        "Only compacts if at least the specified number of files are selected.  When no file selection criteria are given, all files are selected.");
 +    opts.addOption(minFilesOption);
 +    outBlockSizeOpt = newLAO("out-data-bs",
 +        "Rfile data block size to use for compaction output file.  Can use K,M, and G suffixes. Uses table settings if not specified.");
 +    opts.addOption(outBlockSizeOpt);
 +    outHdfsBlockSizeOpt = newLAO("out-hdfs-bs",
 +        "HDFS block size to use for compaction output file.  Can use K,M, and G suffixes. Uses table settings if not specified.");
 +    opts.addOption(outHdfsBlockSizeOpt);
 +    outIndexBlockSizeOpt = newLAO("out-index-bs",
 +        "Rfile index block size to use for compaction output file.  Can use K,M, and G suffixes. Uses table settings if not specified.");
 +    opts.addOption(outIndexBlockSizeOpt);
 +    outCompressionOpt = newLAO("out-compress",
 +        "Compression to use for compaction output file. Either snappy, gz, lzo, or none. Uses table settings if not specified.");
 +    opts.addOption(outCompressionOpt);
 +    outReplication = newLAO("out-replication", "HDFS replication to use for compaction output file. Uses table settings if not specified.");
 +    opts.addOption(outReplication);
 +
 +    return opts;
 +  }
 +}

http://git-wip-us.apache.org/repos/asf/accumulo/blob/6df97b89/shell/src/main/java/org/apache/accumulo/shell/commands/ScanCommand.java
----------------------------------------------------------------------
diff --cc shell/src/main/java/org/apache/accumulo/shell/commands/ScanCommand.java
index 334ca56,0000000..3531fe9
mode 100644,000000..100644
--- a/shell/src/main/java/org/apache/accumulo/shell/commands/ScanCommand.java
+++ b/shell/src/main/java/org/apache/accumulo/shell/commands/ScanCommand.java
@@@ -1,324 -1,0 +1,340 @@@
 +/*
 + * 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.
 + */
 +package org.apache.accumulo.shell.commands;
 +
 +import java.io.FileNotFoundException;
 +import java.io.IOException;
 +import java.io.UnsupportedEncodingException;
 +import java.util.List;
 +import java.util.Map.Entry;
 +import java.util.concurrent.TimeUnit;
 +
 +import org.apache.accumulo.core.client.AccumuloException;
 +import org.apache.accumulo.core.client.AccumuloSecurityException;
 +import org.apache.accumulo.core.client.IteratorSetting;
 +import org.apache.accumulo.core.client.Scanner;
 +import org.apache.accumulo.core.client.ScannerBase;
++import org.apache.accumulo.core.client.TableNotFoundException;
 +import org.apache.accumulo.core.conf.AccumuloConfiguration;
 +import org.apache.accumulo.core.data.Key;
 +import org.apache.accumulo.core.data.Range;
 +import org.apache.accumulo.core.data.Value;
++import org.apache.accumulo.core.iterators.SortedKeyValueIterator;
 +import org.apache.accumulo.core.security.Authorizations;
 +import org.apache.accumulo.core.util.format.BinaryFormatter;
 +import org.apache.accumulo.core.util.format.Formatter;
 +import org.apache.accumulo.core.util.interpret.DefaultScanInterpreter;
 +import org.apache.accumulo.core.util.interpret.ScanInterpreter;
 +import org.apache.accumulo.shell.Shell;
 +import org.apache.accumulo.shell.Shell.Command;
 +import org.apache.accumulo.shell.Shell.PrintFile;
++import org.apache.accumulo.shell.ShellCommandException;
++import org.apache.accumulo.shell.ShellCommandException.ErrorCode;
 +import org.apache.accumulo.start.classloader.vfs.AccumuloVFSClassLoader;
 +import org.apache.commons.cli.CommandLine;
 +import org.apache.commons.cli.Option;
 +import org.apache.commons.cli.Options;
 +import org.apache.hadoop.io.Text;
 +
 +public class ScanCommand extends Command {
 +
 +  private Option scanOptAuths, scanOptRow, scanOptColumns, disablePaginationOpt, showFewOpt, formatterOpt, interpreterOpt, formatterInterpeterOpt,
 +      outputFileOpt;
 +
 +  protected Option timestampOpt;
 +  private Option optStartRowExclusive;
 +  private Option optEndRowExclusive;
 +  private Option timeoutOption;
 +  private Option profileOpt;
 +
 +  @Override
 +  public int execute(final String fullCommand, final CommandLine cl, final Shell shellState) throws Exception {
 +    final PrintFile printFile = getOutputFile(cl);
 +    final String tableName = OptUtil.getTableOpt(cl, shellState);
 +
 +    final Class<? extends Formatter> formatter = getFormatter(cl, tableName, shellState);
 +    final ScanInterpreter interpeter = getInterpreter(cl, tableName, shellState);
 +
 +    // handle first argument, if present, the authorizations list to
 +    // scan with
 +    final Authorizations auths = getAuths(cl, shellState);
 +    final Scanner scanner = shellState.getConnector().createScanner(tableName, auths);
 +
 +    // handle session-specific scan iterators
 +    addScanIterators(shellState, cl, scanner, tableName);
 +
 +    // handle remaining optional arguments
 +    scanner.setRange(getRange(cl, interpeter));
 +
 +    // handle columns
 +    fetchColumns(cl, scanner, interpeter);
 +
 +    // set timeout
 +    scanner.setTimeout(getTimeout(cl), TimeUnit.MILLISECONDS);
 +
 +    // output the records
 +    if (cl.hasOption(showFewOpt.getOpt())) {
 +      final String showLength = cl.getOptionValue(showFewOpt.getOpt());
 +      try {
 +        final int length = Integer.parseInt(showLength);
 +        if (length < 1) {
 +          throw new IllegalArgumentException();
 +        }
 +        BinaryFormatter.getlength(length);
 +        printBinaryRecords(cl, shellState, scanner, printFile);
 +      } catch (NumberFormatException nfe) {
 +        shellState.getReader().println("Arg must be an integer.");
 +      } catch (IllegalArgumentException iae) {
 +        shellState.getReader().println("Arg must be greater than one.");
 +      }
 +
 +    } else {
 +      printRecords(cl, shellState, scanner, formatter, printFile);
 +    }
 +    if (printFile != null) {
 +      printFile.close();
 +    }
 +
 +    return 0;
 +  }
 +
 +  protected long getTimeout(final CommandLine cl) {
 +    if (cl.hasOption(timeoutOption.getLongOpt())) {
 +      return AccumuloConfiguration.getTimeInMillis(cl.getOptionValue(timeoutOption.getLongOpt()));
 +    }
 +
 +    return Long.MAX_VALUE;
 +  }
 +
-   protected void addScanIterators(final Shell shellState, CommandLine cl, final Scanner scanner, final String tableName) {
++  static void ensureTserversCanLoadIterator(final Shell shellState, String tableName, String classname) throws AccumuloException, AccumuloSecurityException,
++      TableNotFoundException, ShellCommandException {
++    if (!shellState.getConnector().tableOperations().testClassLoad(tableName, classname, SortedKeyValueIterator.class.getName())) {
++      throw new ShellCommandException(ErrorCode.INITIALIZATION_FAILURE, "Servers are unable to load " + classname + " as type "
++          + SortedKeyValueIterator.class.getName());
++    }
++  }
++
++  protected void addScanIterators(final Shell shellState, CommandLine cl, final Scanner scanner, final String tableName) throws Exception {
 +
 +    List<IteratorSetting> tableScanIterators;
 +    if (cl.hasOption(profileOpt.getOpt())) {
 +      String profile = cl.getOptionValue(profileOpt.getOpt());
 +      tableScanIterators = shellState.iteratorProfiles.get(profile);
 +
 +      if (tableScanIterators == null) {
 +        throw new IllegalArgumentException("Profile " + profile + " does not exist");
 +      }
++
++      for (IteratorSetting iteratorSetting : tableScanIterators) {
++        ensureTserversCanLoadIterator(shellState, tableName, iteratorSetting.getIteratorClass());
++      }
 +    } else {
 +      tableScanIterators = shellState.scanIteratorOptions.get(tableName);
 +      if (tableScanIterators == null) {
 +        Shell.log.debug("Found no scan iterators to set");
 +        return;
 +      }
 +    }
 +
 +    Shell.log.debug("Found " + tableScanIterators.size() + " scan iterators to set");
 +
 +    for (IteratorSetting setting : tableScanIterators) {
 +      Shell.log.debug("Setting scan iterator " + setting.getName() + " at priority " + setting.getPriority() + " using class name "
 +          + setting.getIteratorClass());
 +      for (Entry<String,String> option : setting.getOptions().entrySet()) {
 +        Shell.log.debug("Setting option for " + setting.getName() + ": " + option.getKey() + "=" + option.getValue());
 +      }
 +      scanner.addScanIterator(setting);
 +    }
 +  }
 +
 +  protected void printRecords(final CommandLine cl, final Shell shellState, final Iterable<Entry<Key,Value>> scanner,
 +      final Class<? extends Formatter> formatter, PrintFile outFile) throws IOException {
 +    if (outFile == null) {
 +      shellState.printRecords(scanner, cl.hasOption(timestampOpt.getOpt()), !cl.hasOption(disablePaginationOpt.getOpt()), formatter);
 +    } else {
 +      shellState.printRecords(scanner, cl.hasOption(timestampOpt.getOpt()), !cl.hasOption(disablePaginationOpt.getOpt()), formatter, outFile);
 +    }
 +  }
 +
 +  protected void printBinaryRecords(final CommandLine cl, final Shell shellState, final Iterable<Entry<Key,Value>> scanner, PrintFile outFile)
 +      throws IOException {
 +    if (outFile == null) {
 +      shellState.printBinaryRecords(scanner, cl.hasOption(timestampOpt.getOpt()), !cl.hasOption(disablePaginationOpt.getOpt()));
 +    } else {
 +      shellState.printBinaryRecords(scanner, cl.hasOption(timestampOpt.getOpt()), !cl.hasOption(disablePaginationOpt.getOpt()), outFile);
 +    }
 +  }
 +
 +  protected ScanInterpreter getInterpreter(final CommandLine cl, final String tableName, final Shell shellState) throws Exception {
 +
 +    Class<? extends ScanInterpreter> clazz = null;
 +    try {
 +      if (cl.hasOption(interpreterOpt.getOpt())) {
 +        clazz = AccumuloVFSClassLoader.loadClass(cl.getOptionValue(interpreterOpt.getOpt()), ScanInterpreter.class);
 +      } else if (cl.hasOption(formatterInterpeterOpt.getOpt())) {
 +        clazz = AccumuloVFSClassLoader.loadClass(cl.getOptionValue(formatterInterpeterOpt.getOpt()), ScanInterpreter.class);
 +      }
 +    } catch (ClassNotFoundException e) {
 +      shellState.getReader().println("Interpreter class could not be loaded.\n" + e.getMessage());
 +    }
 +
 +    if (clazz == null)
 +      clazz = InterpreterCommand.getCurrentInterpreter(tableName, shellState);
 +
 +    if (clazz == null)
 +      clazz = DefaultScanInterpreter.class;
 +
 +    return clazz.newInstance();
 +  }
 +
 +  protected Class<? extends Formatter> getFormatter(final CommandLine cl, final String tableName, final Shell shellState) throws IOException {
 +
 +    try {
 +      if (cl.hasOption(formatterOpt.getOpt())) {
 +        return shellState.getClassLoader(cl, shellState).loadClass(cl.getOptionValue(formatterOpt.getOpt())).asSubclass(Formatter.class);
 +      } else if (cl.hasOption(formatterInterpeterOpt.getOpt())) {
 +        return shellState.getClassLoader(cl, shellState).loadClass(cl.getOptionValue(formatterInterpeterOpt.getOpt())).asSubclass(Formatter.class);
 +      }
 +    } catch (Exception e) {
 +      shellState.getReader().println("Formatter class could not be loaded.\n" + e.getMessage());
 +    }
 +
 +    return shellState.getFormatter(tableName);
 +  }
 +
 +  protected void fetchColumns(final CommandLine cl, final ScannerBase scanner, final ScanInterpreter formatter) throws UnsupportedEncodingException {
 +    if (cl.hasOption(scanOptColumns.getOpt())) {
 +      for (String a : cl.getOptionValue(scanOptColumns.getOpt()).split(",")) {
 +        final String sa[] = a.split(":", 2);
 +        if (sa.length == 1) {
 +          scanner.fetchColumnFamily(formatter.interpretColumnFamily(new Text(a.getBytes(Shell.CHARSET))));
 +        } else {
 +          scanner.fetchColumn(formatter.interpretColumnFamily(new Text(sa[0].getBytes(Shell.CHARSET))),
 +              formatter.interpretColumnQualifier(new Text(sa[1].getBytes(Shell.CHARSET))));
 +        }
 +      }
 +    }
 +  }
 +
 +  protected Range getRange(final CommandLine cl, final ScanInterpreter formatter) throws UnsupportedEncodingException {
 +    if ((cl.hasOption(OptUtil.START_ROW_OPT) || cl.hasOption(OptUtil.END_ROW_OPT)) && cl.hasOption(scanOptRow.getOpt())) {
 +      // did not see a way to make commons cli do this check... it has mutually exclusive options but does not support the or
 +      throw new IllegalArgumentException("Options -" + scanOptRow.getOpt() + " AND (-" + OptUtil.START_ROW_OPT + " OR -" + OptUtil.END_ROW_OPT
 +          + ") are mutally exclusive ");
 +    }
 +
 +    if (cl.hasOption(scanOptRow.getOpt())) {
 +      return new Range(formatter.interpretRow(new Text(cl.getOptionValue(scanOptRow.getOpt()).getBytes(Shell.CHARSET))));
 +    } else {
 +      Text startRow = OptUtil.getStartRow(cl);
 +      if (startRow != null)
 +        startRow = formatter.interpretBeginRow(startRow);
 +      Text endRow = OptUtil.getEndRow(cl);
 +      if (endRow != null)
 +        endRow = formatter.interpretEndRow(endRow);
 +      final boolean startInclusive = !cl.hasOption(optStartRowExclusive.getOpt());
 +      final boolean endInclusive = !cl.hasOption(optEndRowExclusive.getOpt());
 +      return new Range(startRow, startInclusive, endRow, endInclusive);
 +    }
 +  }
 +
 +  protected Authorizations getAuths(final CommandLine cl, final Shell shellState) throws AccumuloSecurityException, AccumuloException {
 +    final String user = shellState.getConnector().whoami();
 +    Authorizations auths = shellState.getConnector().securityOperations().getUserAuthorizations(user);
 +    if (cl.hasOption(scanOptAuths.getOpt())) {
 +      auths = ScanCommand.parseAuthorizations(cl.getOptionValue(scanOptAuths.getOpt()));
 +    }
 +    return auths;
 +  }
 +
 +  static Authorizations parseAuthorizations(final String field) {
 +    if (field == null || field.isEmpty()) {
 +      return Authorizations.EMPTY;
 +    }
 +    return new Authorizations(field.split(","));
 +  }
 +
 +  @Override
 +  public String description() {
 +    return "scans the table, and displays the resulting records";
 +  }
 +
 +  @Override
 +  public Options getOptions() {
 +    final Options o = new Options();
 +
 +    scanOptAuths = new Option("s", "scan-authorizations", true, "scan authorizations (all user auths are used if this argument is not specified)");
 +    optStartRowExclusive = new Option("be", "begin-exclusive", false, "make start row exclusive (by default it's inclusive)");
 +    optStartRowExclusive.setArgName("begin-exclusive");
 +    optEndRowExclusive = new Option("ee", "end-exclusive", false, "make end row exclusive (by default it's inclusive)");
 +    optEndRowExclusive.setArgName("end-exclusive");
 +    scanOptRow = new Option("r", "row", true, "row to scan");
 +    scanOptColumns = new Option("c", "columns", true, "comma-separated columns");
 +    timestampOpt = new Option("st", "show-timestamps", false, "display timestamps");
 +    disablePaginationOpt = new Option("np", "no-pagination", false, "disable pagination of output");
 +    showFewOpt = new Option("f", "show-few", true, "show only a specified number of characters");
 +    formatterOpt = new Option("fm", "formatter", true, "fully qualified name of the formatter class to use");
 +    interpreterOpt = new Option("i", "interpreter", true, "fully qualified name of the interpreter class to use");
 +    formatterInterpeterOpt = new Option("fi", "fmt-interpreter", true, "fully qualified name of a class that is a formatter and interpreter");
 +    timeoutOption = new Option(null, "timeout", true,
 +        "time before scan should fail if no data is returned. If no unit is given assumes seconds.  Units d,h,m,s,and ms are supported.  e.g. 30s or 100ms");
 +    outputFileOpt = new Option("o", "output", true, "local file to write the scan output to");
 +
 +    scanOptAuths.setArgName("comma-separated-authorizations");
 +    scanOptRow.setArgName("row");
 +    scanOptColumns.setArgName("<columnfamily>[:<columnqualifier>]{,<columnfamily>[:<columnqualifier>]}");
 +    showFewOpt.setRequired(false);
 +    showFewOpt.setArgName("int");
 +    formatterOpt.setArgName("className");
 +    timeoutOption.setArgName("timeout");
 +    outputFileOpt.setArgName("file");
 +
 +    profileOpt = new Option("pn", "profile", true, "iterator profile name");
 +    profileOpt.setArgName("profile");
 +
 +    o.addOption(scanOptAuths);
 +    o.addOption(scanOptRow);
 +    o.addOption(OptUtil.startRowOpt());
 +    o.addOption(OptUtil.endRowOpt());
 +    o.addOption(optStartRowExclusive);
 +    o.addOption(optEndRowExclusive);
 +    o.addOption(scanOptColumns);
 +    o.addOption(timestampOpt);
 +    o.addOption(disablePaginationOpt);
 +    o.addOption(OptUtil.tableOpt("table to be scanned"));
 +    o.addOption(showFewOpt);
 +    o.addOption(formatterOpt);
 +    o.addOption(interpreterOpt);
 +    o.addOption(formatterInterpeterOpt);
 +    o.addOption(timeoutOption);
 +    o.addOption(outputFileOpt);
 +    o.addOption(profileOpt);
 +
 +    return o;
 +  }
 +
 +  @Override
 +  public int numArgs() {
 +    return 0;
 +  }
 +
 +  protected PrintFile getOutputFile(final CommandLine cl) throws FileNotFoundException {
 +    final String outputFile = cl.getOptionValue(outputFileOpt.getOpt());
 +    return (outputFile == null ? null : new PrintFile(outputFile));
 +  }
 +}