accumulo-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ctubb...@apache.org
Subject [05/61] [abbrv] [partial] accumulo git commit: ACCUMULO-722 put trunk in my sandbox
Date Thu, 03 Mar 2016 21:59:30 GMT
http://git-wip-us.apache.org/repos/asf/accumulo/blob/7bdbfccb/1.5/core/src/main/java/org/apache/accumulo/core/util/shell/Shell.java
----------------------------------------------------------------------
diff --git a/1.5/core/src/main/java/org/apache/accumulo/core/util/shell/Shell.java b/1.5/core/src/main/java/org/apache/accumulo/core/util/shell/Shell.java
new file mode 100644
index 0000000..babd61e
--- /dev/null
+++ b/1.5/core/src/main/java/org/apache/accumulo/core/util/shell/Shell.java
@@ -0,0 +1,978 @@
+/*
+ * 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.core.util.shell;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.net.InetAddress;
+import java.nio.ByteBuffer;
+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 jline.ConsoleReader;
+import jline.History;
+
+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.Connector;
+import org.apache.accumulo.core.client.Instance;
+import org.apache.accumulo.core.client.IteratorSetting;
+import org.apache.accumulo.core.client.TableNotFoundException;
+import org.apache.accumulo.core.client.ZooKeeperInstance;
+import org.apache.accumulo.core.client.mock.MockInstance;
+import org.apache.accumulo.core.conf.AccumuloConfiguration;
+import org.apache.accumulo.core.conf.Property;
+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.security.AuditLevel;
+import org.apache.accumulo.core.security.thrift.AuthInfo;
+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.util.shell.commands.AboutCommand;
+import org.apache.accumulo.core.util.shell.commands.AddSplitsCommand;
+import org.apache.accumulo.core.util.shell.commands.AuthenticateCommand;
+import org.apache.accumulo.core.util.shell.commands.ByeCommand;
+import org.apache.accumulo.core.util.shell.commands.ClasspathCommand;
+import org.apache.accumulo.core.util.shell.commands.ClearCommand;
+import org.apache.accumulo.core.util.shell.commands.CloneTableCommand;
+import org.apache.accumulo.core.util.shell.commands.ClsCommand;
+import org.apache.accumulo.core.util.shell.commands.CompactCommand;
+import org.apache.accumulo.core.util.shell.commands.ConfigCommand;
+import org.apache.accumulo.core.util.shell.commands.ConstraintCommand;
+import org.apache.accumulo.core.util.shell.commands.CreateTableCommand;
+import org.apache.accumulo.core.util.shell.commands.CreateUserCommand;
+import org.apache.accumulo.core.util.shell.commands.DUCommand;
+import org.apache.accumulo.core.util.shell.commands.DebugCommand;
+import org.apache.accumulo.core.util.shell.commands.DeleteCommand;
+import org.apache.accumulo.core.util.shell.commands.DeleteIterCommand;
+import org.apache.accumulo.core.util.shell.commands.DeleteManyCommand;
+import org.apache.accumulo.core.util.shell.commands.DeleteRowsCommand;
+import org.apache.accumulo.core.util.shell.commands.DeleteScanIterCommand;
+import org.apache.accumulo.core.util.shell.commands.DeleteTableCommand;
+import org.apache.accumulo.core.util.shell.commands.DeleteUserCommand;
+import org.apache.accumulo.core.util.shell.commands.DropTableCommand;
+import org.apache.accumulo.core.util.shell.commands.DropUserCommand;
+import org.apache.accumulo.core.util.shell.commands.EGrepCommand;
+import org.apache.accumulo.core.util.shell.commands.ExecfileCommand;
+import org.apache.accumulo.core.util.shell.commands.ExitCommand;
+import org.apache.accumulo.core.util.shell.commands.ExportTableCommand;
+import org.apache.accumulo.core.util.shell.commands.FlushCommand;
+import org.apache.accumulo.core.util.shell.commands.FormatterCommand;
+import org.apache.accumulo.core.util.shell.commands.GetAuthsCommand;
+import org.apache.accumulo.core.util.shell.commands.GetGroupsCommand;
+import org.apache.accumulo.core.util.shell.commands.GetSplitsCommand;
+import org.apache.accumulo.core.util.shell.commands.GrantCommand;
+import org.apache.accumulo.core.util.shell.commands.GrepCommand;
+import org.apache.accumulo.core.util.shell.commands.HelpCommand;
+import org.apache.accumulo.core.util.shell.commands.HiddenCommand;
+import org.apache.accumulo.core.util.shell.commands.HistoryCommand;
+import org.apache.accumulo.core.util.shell.commands.ImportDirectoryCommand;
+import org.apache.accumulo.core.util.shell.commands.ImportTableCommand;
+import org.apache.accumulo.core.util.shell.commands.InfoCommand;
+import org.apache.accumulo.core.util.shell.commands.InsertCommand;
+import org.apache.accumulo.core.util.shell.commands.ListIterCommand;
+import org.apache.accumulo.core.util.shell.commands.ListScansCommand;
+import org.apache.accumulo.core.util.shell.commands.MaxRowCommand;
+import org.apache.accumulo.core.util.shell.commands.MergeCommand;
+import org.apache.accumulo.core.util.shell.commands.NoTableCommand;
+import org.apache.accumulo.core.util.shell.commands.OfflineCommand;
+import org.apache.accumulo.core.util.shell.commands.OnlineCommand;
+import org.apache.accumulo.core.util.shell.commands.PasswdCommand;
+import org.apache.accumulo.core.util.shell.commands.QuestionCommand;
+import org.apache.accumulo.core.util.shell.commands.QuitCommand;
+import org.apache.accumulo.core.util.shell.commands.QuotedStringTokenizer;
+import org.apache.accumulo.core.util.shell.commands.RenameTableCommand;
+import org.apache.accumulo.core.util.shell.commands.RevokeCommand;
+import org.apache.accumulo.core.util.shell.commands.ScanCommand;
+import org.apache.accumulo.core.util.shell.commands.SetAuthsCommand;
+import org.apache.accumulo.core.util.shell.commands.SetGroupsCommand;
+import org.apache.accumulo.core.util.shell.commands.SetIterCommand;
+import org.apache.accumulo.core.util.shell.commands.SetScanIterCommand;
+import org.apache.accumulo.core.util.shell.commands.SleepCommand;
+import org.apache.accumulo.core.util.shell.commands.SystemPermissionsCommand;
+import org.apache.accumulo.core.util.shell.commands.TableCommand;
+import org.apache.accumulo.core.util.shell.commands.TablePermissionsCommand;
+import org.apache.accumulo.core.util.shell.commands.TablesCommand;
+import org.apache.accumulo.core.util.shell.commands.TraceCommand;
+import org.apache.accumulo.core.util.shell.commands.UserCommand;
+import org.apache.accumulo.core.util.shell.commands.UserPermissionsCommand;
+import org.apache.accumulo.core.util.shell.commands.UsersCommand;
+import org.apache.accumulo.core.util.shell.commands.WhoAmICommand;
+import org.apache.accumulo.fate.zookeeper.ZooReader;
+import org.apache.commons.cli.BasicParser;
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.HelpFormatter;
+import org.apache.commons.cli.MissingArgumentException;
+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.hadoop.fs.Path;
+import org.apache.log4j.Level;
+import org.apache.log4j.Logger;
+
+/**
+ * A convenient console interface to perform basic accumulo functions Includes auto-complete, help, and quoted strings with escape sequences
+ */
+public class Shell extends ShellOptions {
+  public static final Logger log = Logger.getLogger(Shell.class);
+  private static final Logger audit = Logger.getLogger(Shell.class.getName() + ".audit");
+  
+  public static final String CHARSET = "ISO-8859-1";
+  public static final int NO_FIXED_ARG_LENGTH_CHECK = -1;
+  private static final String SHELL_DESCRIPTION = "Shell - Apache Accumulo Interactive Shell";
+  private static final String DEFAULT_AUTH_TIMEOUT = "60"; // in minutes
+  
+  protected int exitCode = 0;
+  private String tableName;
+  protected Instance instance;
+  private Connector connector;
+  protected ConsoleReader reader;
+  private AuthInfo credentials;
+  private Class<? extends Formatter> defaultFormatterClass = DefaultFormatter.class;
+  private Class<? extends Formatter> binaryFormatterClass = BinaryFormatter.class;
+  public Map<String,List<IteratorSetting>> scanIteratorOptions = 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[]>();
+  protected boolean configError = false;
+  
+  // exit if true
+  private boolean exit = false;
+  
+  // file to execute commands from
+  protected String 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.currentTimeMillis();
+  private boolean logErrorsToConsole = false;
+  private PrintWriter writer = null;
+  private boolean masking = false;
+  
+  public Shell() throws IOException {
+    this(new ConsoleReader());
+  }
+  
+  public Shell(ConsoleReader reader) {
+    super();
+    this.reader = reader;
+  }
+  
+  public Shell(ConsoleReader reader, PrintWriter writer) {
+    this(reader);
+    this.writer = writer;
+  }
+  
+  // Not for client use
+  public boolean config(String... args) {
+    
+    CommandLine cl;
+    try {
+      cl = new BasicParser().parse(opts, args);
+      if (cl.getArgs().length > 0)
+        throw new ParseException("Unrecognized arguments: " + cl.getArgList());
+      
+      if (cl.hasOption(helpOpt.getOpt())) {
+        configError = true;
+        printHelp("shell", SHELL_DESCRIPTION, opts);
+        return true;
+      }
+      
+      setDebugging(cl.hasOption(debugOption.getLongOpt()));
+      authTimeout = Integer.parseInt(cl.getOptionValue(authTimeoutOpt.getLongOpt(), DEFAULT_AUTH_TIMEOUT)) * 60 * 1000;
+      disableAuthTimeout = cl.hasOption(disableAuthTimeoutOpt.getLongOpt());
+      
+      if (cl.hasOption(zooKeeperInstance.getOpt()) && cl.getOptionValues(zooKeeperInstance.getOpt()).length != 2)
+        throw new MissingArgumentException(zooKeeperInstance);
+      
+    } catch (Exception e) {
+      configError = true;
+      printException(e);
+      printHelp("shell", SHELL_DESCRIPTION, opts);
+      return true;
+    }
+    
+    // get the options that were parsed
+    String sysUser = System.getProperty("user.name");
+    if (sysUser == null)
+      sysUser = "root";
+    String user = cl.getOptionValue(usernameOption.getOpt(), sysUser);
+    
+    String passw = cl.getOptionValue(passwOption.getOpt(), null);
+    tabCompletion = !cl.hasOption(tabCompleteOption.getLongOpt());
+    
+    // Use a fake (Mock), ZK, or HdfsZK Accumulo instance
+    setInstance(cl);
+    
+    // process default parameters if unspecified
+    byte[] pass;
+    try {
+      if (!cl.hasOption(fakeOption.getLongOpt())) {
+        DistributedTrace.enable(instance, new ZooReader(instance.getZooKeepers(), instance.getZooKeepersSessionTimeOut()), "shell", InetAddress.getLocalHost()
+            .getHostName());
+      }
+      
+      Runtime.getRuntime().addShutdownHook(new Thread() {
+        @Override
+        public void start() {
+          reader.getTerminal().enableEcho();
+        }
+      });
+      
+      if (passw == null)
+        passw = readMaskedLine("Enter current password for '" + user + "'@'" + instance.getInstanceName() + "': ", '*');
+      if (passw == null) {
+        reader.printNewline();
+        configError = true;
+        return true;
+      } // user canceled
+      
+      pass = passw.getBytes();
+      this.setTableName("");
+      connector = instance.getConnector(user, pass);
+      this.credentials = new AuthInfo(user, ByteBuffer.wrap(pass), connector.getInstance().getInstanceID());
+      
+    } catch (Exception e) {
+      printException(e);
+      configError = true;
+    }
+    
+    // decide whether to execute commands from a file and quit
+    if (cl.hasOption(execfileOption.getOpt())) {
+      execFile = cl.getOptionValue(execfileOption.getOpt());
+      verbose = false;
+    } else if (cl.hasOption(execfileVerboseOption.getOpt())) {
+      execFile = cl.getOptionValue(execfileVerboseOption.getOpt());
+    }
+    if (cl.hasOption(execCommandOpt.getOpt())) {
+      execCommand = cl.getOptionValue(execCommandOpt.getOpt());
+      verbose = false;
+    }
+    
+    rootToken = new Token();
+    
+    Command[] dataCommands = {new DeleteCommand(), new DeleteManyCommand(), new DeleteRowsCommand(), new EGrepCommand(), new FormatterCommand(),
+        new GrepCommand(), new ImportDirectoryCommand(), new InsertCommand(), new MaxRowCommand(), new ScanCommand()};
+    Command[] debuggingCommands = {new ClasspathCommand(), new DebugCommand(), new ListScansCommand(), new TraceCommand()};
+    Command[] execCommands = {new ExecfileCommand(), new HistoryCommand()};
+    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()};
+    Command[] otherCommands = {new HiddenCommand()};
+    Command[] permissionsCommands = {new GrantCommand(), new RevokeCommand(), new SystemPermissionsCommand(), new TablePermissionsCommand(),
+        new UserPermissionsCommand()};
+    Command[] stateCommands = {new AuthenticateCommand(), new ClsCommand(), new ClearCommand(), 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()};
+    Command[] tableControlCommands = {new AddSplitsCommand(), new CompactCommand(), new ConstraintCommand(), new FlushCommand(), new GetGroupsCommand(),
+        new GetSplitsCommand(), new MergeCommand(), new SetGroupsCommand()};
+    Command[] userCommands = {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 configError;
+  }
+  
+  @SuppressWarnings("deprecation")
+  protected void setInstance(CommandLine cl) {
+    // should only be one instance option set
+    instance = null;
+    if (cl.hasOption(fakeOption.getLongOpt())) {
+      instance = new MockInstance("fake");
+    } else if (cl.hasOption(hdfsZooInstance.getOpt())) {
+      instance = getDefaultInstance(AccumuloConfiguration.getSiteConfiguration());
+    } else if (cl.hasOption(zooKeeperInstance.getOpt())) {
+      String[] zkOpts = cl.getOptionValues(zooKeeperInstance.getOpt());
+      instance = new ZooKeeperInstance(zkOpts[0], zkOpts[1]);
+    } else {
+      instance = getDefaultInstance(AccumuloConfiguration.getSiteConfiguration());
+    }
+  }
+  
+  /**
+   * @deprecated Not for client use
+   */
+  private static Instance getDefaultInstance(AccumuloConfiguration conf) {
+    String keepers = conf.get(Property.INSTANCE_ZK_HOST);
+    Path instanceDir = new Path(conf.get(Property.INSTANCE_DFS_DIR), "instance_id");
+    return new ZooKeeperInstance(UUID.fromString(ZooKeeperInstance.getInstanceIDFromHdfs(instanceDir)), keepers);
+  }
+  
+  public Connector getConnector() {
+    return connector;
+  }
+  
+  public static void main(String args[]) throws IOException {
+    Shell shell = new Shell();
+    shell.config(args);
+    
+    System.exit(shell.start());
+  }
+  
+  public int start() throws IOException {
+    if (configError)
+      return 1;
+    
+    String input;
+    if (isVerbose())
+      printInfo();
+    
+    String configDir = System.getenv("HOME") + "/.accumulo";
+    String historyPath = configDir + "/shell_history.txt";
+    File accumuloDir = new File(configDir);
+    if (!accumuloDir.exists() && !accumuloDir.mkdirs())
+      log.warn("Unable to make directory for history at " + accumuloDir);
+    try {
+      History history = new History();
+      history.setHistoryFile(new File(historyPath));
+      reader.setHistory(history);
+    } catch (IOException e) {
+      log.warn("Unable to load history file at " + historyPath);
+    }
+    
+    ShellCompletor userCompletor = null;
+    
+    if (execFile != null) {
+      java.util.Scanner scanner = new java.util.Scanner(new File(execFile));
+      while (scanner.hasNextLine())
+        execCommand(scanner.nextLine(), true, isVerbose());
+    } else if (execCommand != null) {
+      for (String command : execCommand.split("\n")) {
+        execCommand(command, true, isVerbose());
+      }
+      return exitCode;
+    }
+    
+    while (true) {
+      if (hasExited())
+        return exitCode;
+      
+      // If tab completion is true we need to reset
+      if (tabCompletion) {
+        if (userCompletor != null)
+          reader.removeCompletor(userCompletor);
+        
+        userCompletor = setupCompletion();
+        reader.addCompletor(userCompletor);
+      }
+      
+      reader.setDefaultPrompt(getDefaultPrompt());
+      input = reader.readLine();
+      if (input == null) {
+        reader.printNewline();
+        return exitCode;
+      } // user canceled
+      
+      execCommand(input, disableAuthTimeout, false);
+    }
+  }
+  
+  public void printInfo() throws IOException {
+    reader.printString("\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.flushConsole();
+  }
+  
+  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("%.2fs\n", authTimeout / 1000.0));
+    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.printString(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(AuditLevel.AUDIT, getDefaultPrompt() + input);
+    if (echoPrompt) {
+      reader.printString(getDefaultPrompt());
+      reader.printString(input);
+      reader.printNewline();
+    }
+    
+    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.printString(String.format("Unknown command \"%s\".  Enter \"help\" for a list possible commands.\n", command));
+          reader.flushConsole();
+          return;
+        }
+        
+        if (!(sc instanceof ExitCommand) && !ignoreAuthTimeout && System.currentTimeMillis() - lastUserActivity > authTimeout) {
+          reader.printString("Shell has been idle for too long. Please re-authenticate.\n");
+          boolean authFailed = true;
+          do {
+            String pwd = readMaskedLine("Enter current password for '" + connector.whoami() + "': ", '*');
+            if (pwd == null) {
+              reader.printNewline();
+              return;
+            } // user canceled
+            
+            try {
+              authFailed = !connector.securityOperations().authenticateUser(connector.whoami(), pwd.getBytes());
+            } catch (Exception e) {
+              ++exitCode;
+              printException(e);
+            }
+            
+            if (authFailed)
+              reader.printString("Invalid password. ");
+          } while (authFailed);
+          lastUserActivity = System.currentTimeMillis();
+        }
+        
+        // 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.flushConsole();
+        }
+        
+      } 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 (Exception e) {
+        ++exitCode;
+        printException(e);
+      }
+    } else {
+      ++exitCode;
+      printException(new BadArgumentException("Unrecognized empty command", command, -1));
+    }
+    reader.flushConsole();
+  }
+  
+  /**
+   * 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().listUsers();
+    } catch (Exception e) {
+      log.debug("Unable to obtain list of users", e);
+      userlist = 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>();
+    
+    for (String a : tableNames)
+      modifiedTablenames.add(a.replaceAll("([\\s'\"])", "\\\\$1"));
+    for (String a : userlist)
+      modifiedUserlist.add(a.replaceAll("([\\s'\"])", "\\\\$1"));
+    
+    options.put(Command.CompletionSet.USERNAMES, modifiedUserlist);
+    options.put(Command.CompletionSet.TABLENAMES, modifiedTablenames);
+    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
+    }
+    
+    static Set<String> getCommandNames(Map<CompletionSet,Set<String>> objects) {
+      return objects.get(CompletionSet.COMMANDS);
+    }
+    
+    static Set<String> getTableNames(Map<CompletionSet,Set<String>> objects) {
+      return objects.get(CompletionSet.TABLENAMES);
+    }
+    
+    static Set<String> getUserNames(Map<CompletionSet,Set<String>> objects) {
+      return objects.get(CompletionSet.USERNAMES);
+    }
+    
+    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);
+    }
+    
+    // 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 {
+    public void print(String s);
+    
+    public void close();
+  }
+  
+  public static class PrintShell implements PrintLine {
+    ConsoleReader reader;
+    
+    public PrintShell(ConsoleReader reader) {
+      this.reader = reader;
+    }
+    
+    public void print(String s) {
+      try {
+        reader.printString(s + "\n");
+      } catch (Exception ex) {
+        throw new RuntimeException(ex);
+      }
+    }
+    
+    public void close() {}
+  };
+  
+  public static class PrintFile implements PrintLine {
+    PrintWriter writer;
+    
+    public PrintFile(String filename) throws FileNotFoundException {
+      writer = new PrintWriter(filename);
+    }
+    
+    public void print(String s) {
+      writer.println(s);
+    }
+    
+    public void close() {
+      writer.close();
+    }
+  };
+  
+  public final void printLines(Iterator<String> lines, boolean paginate) throws IOException {
+    int linesPrinted = 0;
+    String prompt = "-- hit any key to continue or 'q' to quit --";
+    int lastPromptLength = prompt.length();
+    int termWidth = reader.getTermwidth();
+    int maxLines = reader.getTermheight();
+    
+    String peek = null;
+    while (lines.hasNext()) {
+      String nextLine = lines.next();
+      if (nextLine == null)
+        continue;
+      for (String line : nextLine.split("\\n")) {
+        if (peek != null) {
+          reader.printString(peek);
+          reader.printNewline();
+          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.printString(nextPrompt);
+              reader.flushConsole();
+              if (Character.toUpperCase((char) reader.readVirtualKey()) == 'Q') {
+                reader.printNewline();
+                return;
+              }
+              reader.printNewline();
+              termWidth = reader.getTermwidth();
+              maxLines = reader.getTermheight();
+            }
+          }
+        }
+        peek = line;
+      }
+    }
+    if (peek != null) {
+      reader.printString(peek);
+      reader.printNewline();
+    }
+  }
+  
+  public final void printRecords(Iterable<Entry<Key,Value>> scanner, boolean printTimestamps, boolean paginate) throws IOException {
+    Class<? extends Formatter> formatterClass = getFormatter();
+    
+    printRecords(scanner, printTimestamps, paginate, formatterClass);
+  }
+  
+  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) 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.getTermwidth() - 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);
+  }
+  
+  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) {
+    PrintWriter pw = new PrintWriter(System.err);
+    new HelpFormatter().printHelp(pw, width, usage, description, opts, 2, 5, null, true);
+    pw.flush();
+    if (logErrorsToConsole && writer != null) {
+      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 isVerbose() {
+    return verbose;
+  }
+  
+  public void setTableName(String tableName) {
+    this.tableName = tableName;
+  }
+  
+  public String getTableName() {
+    return tableName;
+  }
+  
+  public ConsoleReader getReader() {
+    return reader;
+  }
+  
+  public void updateUser(AuthInfo authInfo) throws AccumuloException, AccumuloSecurityException {
+    connector = instance.getConnector(authInfo);
+    credentials = authInfo;
+  }
+  
+  public AuthInfo getCredentials() {
+    return credentials;
+  }
+  
+  /**
+   * 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.printString("ERROR: " + s + "\n");
+        reader.flushConsole();
+      } 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;
+  }
+}

http://git-wip-us.apache.org/repos/asf/accumulo/blob/7bdbfccb/1.5/core/src/main/java/org/apache/accumulo/core/util/shell/ShellCommandException.java
----------------------------------------------------------------------
diff --git a/1.5/core/src/main/java/org/apache/accumulo/core/util/shell/ShellCommandException.java b/1.5/core/src/main/java/org/apache/accumulo/core/util/shell/ShellCommandException.java
new file mode 100644
index 0000000..6bef379
--- /dev/null
+++ b/1.5/core/src/main/java/org/apache/accumulo/core/util/shell/ShellCommandException.java
@@ -0,0 +1,59 @@
+/*
+ * 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.core.util.shell;
+
+public class ShellCommandException extends Exception {
+  private static final long serialVersionUID = 1L;
+  
+  public enum ErrorCode {
+    UNKNOWN_ERROR("Unknown error"),
+    UNSUPPORTED_LANGUAGE("Programming language used is not supported"),
+    UNRECOGNIZED_COMMAND("Command is not supported"),
+    INITIALIZATION_FAILURE("Command could not be initialized"),
+    XML_PARSING_ERROR("Failed to parse the XML file");
+    
+    private String description;
+    
+    private ErrorCode(String description) {
+      this.description = description;
+    }
+    
+    public String getDescription() {
+      return this.description;
+    }
+    
+    public String toString() {
+      return getDescription();
+    }
+  }
+  
+  private ErrorCode code;
+  private String command;
+  
+  public ShellCommandException(ErrorCode code) {
+    this(code, null);
+  }
+  
+  public ShellCommandException(ErrorCode code, String command) {
+    this.code = code;
+    this.command = command;
+  }
+  
+  public String getMessage() {
+    return code + (command != null ? " (" + command + ")" : "");
+  }
+}

http://git-wip-us.apache.org/repos/asf/accumulo/blob/7bdbfccb/1.5/core/src/main/java/org/apache/accumulo/core/util/shell/ShellCompletor.java
----------------------------------------------------------------------
diff --git a/1.5/core/src/main/java/org/apache/accumulo/core/util/shell/ShellCompletor.java b/1.5/core/src/main/java/org/apache/accumulo/core/util/shell/ShellCompletor.java
new file mode 100644
index 0000000..17ce228
--- /dev/null
+++ b/1.5/core/src/main/java/org/apache/accumulo/core/util/shell/ShellCompletor.java
@@ -0,0 +1,152 @@
+/*
+ * 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.core.util.shell;
+
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import jline.Completor;
+
+import org.apache.accumulo.core.util.shell.Shell.Command.CompletionSet;
+import org.apache.accumulo.core.util.shell.commands.QuotedStringTokenizer;
+
+public class ShellCompletor implements Completor {
+  
+  // private static final Logger log = Logger.getLogger(ShellCompletor.class);
+  
+  Map<CompletionSet,Set<String>> options;
+  Token root = null;
+  
+  public ShellCompletor() {}
+  
+  public ShellCompletor(Token root) {
+    this.root = root;
+  }
+  
+  public ShellCompletor(Token rootToken, Map<CompletionSet,Set<String>> options) {
+    this.root = rootToken;
+    this.options = options;
+  }
+  
+  @SuppressWarnings({"unchecked", "rawtypes"})
+  public int complete(String buffer, int cursor, List candidates) {
+    try {
+      return _complete(buffer, cursor, candidates);
+    } catch (Exception e) {
+      candidates.add("");
+      candidates.add(e.getMessage());
+      return cursor;
+    }
+  }
+  
+  private int _complete(String fullBuffer, int cursor, List<String> candidates) {
+    boolean inTableFlag = false, inUserFlag = false;
+    // Only want to grab the buffer up to the cursor because
+    // the user could be trying to tab complete in the middle
+    // of the line
+    String buffer = fullBuffer.substring(0, cursor);
+    
+    Token current_command_token = root;
+    String current_string_token = null;
+    boolean end_space = buffer.endsWith(" ");
+    
+    // tabbing with no text
+    if (buffer.length() == 0) {
+      candidates.addAll(root.getSubcommandNames());
+      return 0;
+    }
+    
+    String prefix = "";
+    
+    QuotedStringTokenizer qst = new QuotedStringTokenizer(buffer);
+    
+    Iterator<String> iter = qst.iterator();
+    while (iter.hasNext()) {
+      current_string_token = iter.next();
+      current_string_token = current_string_token.replaceAll("([\\s'\"])", "\\\\$1");
+      
+      if (!iter.hasNext()) {
+        // if we end in a space and that space isn't part of the last token
+        // (which would be the case at the start of a quote) OR the buffer
+        // ends with a " indicating that we need to start on the next command
+        // and not complete the current command.
+        if (end_space && !current_string_token.endsWith(" ") || buffer.endsWith("\"")) {
+          // match subcommands
+          
+          // we're in a subcommand so try to match the universal
+          // option flags if we're there
+          if (current_string_token.trim().equals("-" + Shell.tableOption)) {
+            candidates.addAll(options.get(Shell.Command.CompletionSet.TABLENAMES));
+            prefix += "-" + Shell.tableOption + " ";
+          } else if (current_string_token.trim().equals("-" + Shell.userOption)) {
+            candidates.addAll(options.get(Shell.Command.CompletionSet.USERNAMES));
+            prefix += "-" + Shell.userOption + " ";
+          } else if (current_command_token != null) {
+            Token next = current_command_token.getSubcommand(current_string_token);
+            if (next != null) {
+              current_command_token = next;
+              
+              if (current_command_token.getCaseSensitive())
+                prefix += current_string_token + " ";
+              else
+                prefix += current_string_token.toUpperCase() + " ";
+              
+              candidates.addAll(current_command_token.getSubcommandNames());
+            }
+          }
+          Collections.sort(candidates);
+          return (prefix.length());
+        }
+        // need to match current command
+        // if we're in -t <table> or -u <user> complete those
+        if (inTableFlag) {
+          for (String a : options.get(Shell.Command.CompletionSet.TABLENAMES))
+            if (a.startsWith(current_string_token))
+              candidates.add(a);
+        } else if (inUserFlag) {
+          for (String a : options.get(Shell.Command.CompletionSet.USERNAMES))
+            if (a.startsWith(current_string_token))
+              candidates.add(a);
+        } else if (current_command_token != null)
+          candidates.addAll(current_command_token.getSubcommandNames(current_string_token));
+        
+        Collections.sort(candidates);
+        return (prefix.length());
+      }
+      
+      if (current_string_token.trim().equals("-" + Shell.tableOption))
+        inTableFlag = true;
+      else if (current_string_token.trim().equals("-" + Shell.userOption))
+        inUserFlag = true;
+      else
+        inUserFlag = inTableFlag = false;
+      
+      if (current_command_token != null && current_command_token.getCaseSensitive())
+        prefix += current_string_token + " ";
+      else
+        prefix += current_string_token.toUpperCase() + " ";
+      
+      if (current_command_token != null && current_command_token.getSubcommandNames().contains(current_string_token))
+        current_command_token = current_command_token.getSubcommand(current_string_token);
+      
+    }
+    return 0;
+  }
+}

http://git-wip-us.apache.org/repos/asf/accumulo/blob/7bdbfccb/1.5/core/src/main/java/org/apache/accumulo/core/util/shell/ShellOptions.java
----------------------------------------------------------------------
diff --git a/1.5/core/src/main/java/org/apache/accumulo/core/util/shell/ShellOptions.java b/1.5/core/src/main/java/org/apache/accumulo/core/util/shell/ShellOptions.java
new file mode 100644
index 0000000..20c26ed
--- /dev/null
+++ b/1.5/core/src/main/java/org/apache/accumulo/core/util/shell/ShellOptions.java
@@ -0,0 +1,96 @@
+/**
+ * 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.core.util.shell;
+
+import org.apache.commons.cli.Option;
+import org.apache.commons.cli.OptionGroup;
+import org.apache.commons.cli.Options;
+
+/**
+ * Abstract class to encompass the Options available on the Accumulo Shell
+ */
+public abstract class ShellOptions {
+  protected static final String DEFAULT_AUTH_TIMEOUT = "60"; // in minutes
+  
+  // Global options flags
+  public static final String userOption = "u";
+  public static final String tableOption = "t";
+  public static final String helpOption = "?";
+  public static final String helpLongOption = "help";
+  
+  final Options opts = new Options();
+  final Option usernameOption = new Option("u", "user", true, "username (defaults to your OS user)");
+  final Option passwOption = new Option("p", "password", true, "password (prompt for password if this option is missing)");
+  final Option tabCompleteOption = new Option(null, "disable-tab-completion", false, "disables tab completion (for less overhead when scripting)");
+  final Option debugOption = new Option(null, "debug", false, "enables client debugging");
+  final Option fakeOption = new Option(null, "fake", false, "fake a connection to accumulo");
+  final Option helpOpt = new Option(helpOption, helpLongOption, false, "display this help");
+  final Option execCommandOpt = new Option("e", "execute-command", true, "executes a command, and then exits");
+  final OptionGroup execFileGroup = new OptionGroup();
+  final Option execfileOption = new Option("f", "execute-file", true, "executes commands from a file at startup");
+  final Option execfileVerboseOption = new Option("fv", "execute-file-verbose", true, "executes commands from a file at startup, with commands shown");
+  final OptionGroup instanceOptions = new OptionGroup();
+  final Option hdfsZooInstance = new Option("h", "hdfsZooInstance", false, "use hdfs zoo instance");
+  final Option zooKeeperInstance = new Option("z", "zooKeeperInstance", true, "use a zookeeper instance with the given instance name and list of zoo hosts");
+  final OptionGroup authTimeoutOptions = new OptionGroup();
+  final Option authTimeoutOpt = new Option(null, "auth-timeout", true, "minutes the shell can be idle without re-entering a password (default "
+      + DEFAULT_AUTH_TIMEOUT + " min)");
+  final Option disableAuthTimeoutOpt = new Option(null, "disable-auth-timeout", false, "disables requiring the user to re-type a password after being idle");
+
+  public ShellOptions() {
+    usernameOption.setArgName("user");
+    opts.addOption(usernameOption);
+    
+    passwOption.setArgName("pass");
+    opts.addOption(passwOption);
+    
+    opts.addOption(tabCompleteOption);
+    
+    opts.addOption(debugOption);
+    
+    opts.addOption(fakeOption);
+    
+    opts.addOption(helpOpt);
+    
+    opts.addOption(execCommandOpt);
+    
+    
+    execfileOption.setArgName("file");
+    execFileGroup.addOption(execfileOption);
+    
+    execfileVerboseOption.setArgName("file");
+    execFileGroup.addOption(execfileVerboseOption);
+    
+    opts.addOptionGroup(execFileGroup);
+    
+    
+    instanceOptions.addOption(hdfsZooInstance);
+    
+    zooKeeperInstance.setArgName("name hosts");
+    zooKeeperInstance.setArgs(2);
+    instanceOptions.addOption(zooKeeperInstance);
+    
+    opts.addOptionGroup(instanceOptions);
+    
+    authTimeoutOpt.setArgName("minutes");
+    authTimeoutOptions.addOption(authTimeoutOpt);
+    
+    authTimeoutOptions.addOption(disableAuthTimeoutOpt);
+    
+    opts.addOptionGroup(authTimeoutOptions);
+  }
+}

http://git-wip-us.apache.org/repos/asf/accumulo/blob/7bdbfccb/1.5/core/src/main/java/org/apache/accumulo/core/util/shell/Token.java
----------------------------------------------------------------------
diff --git a/1.5/core/src/main/java/org/apache/accumulo/core/util/shell/Token.java b/1.5/core/src/main/java/org/apache/accumulo/core/util/shell/Token.java
new file mode 100644
index 0000000..b6c5869
--- /dev/null
+++ b/1.5/core/src/main/java/org/apache/accumulo/core/util/shell/Token.java
@@ -0,0 +1,137 @@
+/*
+ * 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.core.util.shell;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+/*
+ * A token is a word in a command in the shell.  The tree that this builds is used for
+ * tab-completion of tables, users, commands and certain other parts of the shell that
+ * can be realistically and quickly gathered. Tokens can have multiple commands grouped 
+ * together and many possible subcommands, although they are stored in a set so duplicates
+ * aren't allowed.
+ */
+
+public class Token {
+  private Set<String> command = new HashSet<String>();
+  private Set<Token> subcommands = new HashSet<Token>();
+  private boolean caseSensitive = false;
+  
+  public Token() {}
+  
+  public Token(String commandName) {
+    this();
+    command.add(commandName);
+  }
+  
+  public Token(Collection<String> commandNames) {
+    this();
+    command.addAll(commandNames);
+  }
+  
+  public Token(Set<String> commandNames, Set<Token> subCommandNames) {
+    this();
+    command.addAll(commandNames);
+    subcommands.addAll(subCommandNames);
+  }
+  
+  public void setCaseSensitive(boolean cs) {
+    caseSensitive = cs;
+  }
+  
+  public boolean getCaseSensitive() {
+    return caseSensitive;
+  }
+  
+  public Set<String> getCommandNames() {
+    return command;
+  }
+  
+  public Set<Token> getSubcommandList() {
+    return subcommands;
+  }
+  
+  public Token getSubcommand(String name) {
+    Iterator<Token> iter = subcommands.iterator();
+    while (iter.hasNext()) {
+      Token t = iter.next();
+      if (t.containsCommand(name))
+        return t;
+    }
+    return null;
+  }
+  
+  public Set<String> getSubcommandNames() {
+    HashSet<String> set = new HashSet<String>();
+    for (Token t : subcommands)
+      set.addAll(t.getCommandNames());
+    return set;
+  }
+  
+  public Set<String> getSubcommandNames(String startsWith) {
+    Iterator<Token> iter = subcommands.iterator();
+    HashSet<String> set = new HashSet<String>();
+    while (iter.hasNext()) {
+      Token t = iter.next();
+      Set<String> subset = t.getCommandNames();
+      for (String s : subset) {
+        if (!t.getCaseSensitive()) {
+          if (s.toLowerCase().startsWith(startsWith.toLowerCase())) {
+            set.add(s);
+          }
+        } else {
+          if (s.startsWith(startsWith)) {
+            set.add(s);
+          }
+        }
+      }
+    }
+    return set;
+  }
+  
+  public boolean containsCommand(String match) {
+    Iterator<String> iter = command.iterator();
+    while (iter.hasNext()) {
+      String t = iter.next();
+      if (caseSensitive) {
+        if (t.equals(match))
+          return true;
+      } else {
+        if (t.equalsIgnoreCase(match))
+          return true;
+      }
+    }
+    return false;
+  }
+  
+  public void addSubcommand(Token t) {
+    subcommands.add(t);
+  }
+  
+  public void addSubcommand(Collection<String> t) {
+    for (String a : t) {
+      addSubcommand(new Token(a));
+    }
+  }
+  
+  public String toString() {
+    return this.command.toString();
+  }
+}

http://git-wip-us.apache.org/repos/asf/accumulo/blob/7bdbfccb/1.5/core/src/main/java/org/apache/accumulo/core/util/shell/commands/AboutCommand.java
----------------------------------------------------------------------
diff --git a/1.5/core/src/main/java/org/apache/accumulo/core/util/shell/commands/AboutCommand.java b/1.5/core/src/main/java/org/apache/accumulo/core/util/shell/commands/AboutCommand.java
new file mode 100644
index 0000000..16971f4
--- /dev/null
+++ b/1.5/core/src/main/java/org/apache/accumulo/core/util/shell/commands/AboutCommand.java
@@ -0,0 +1,55 @@
+/*
+ * 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.core.util.shell.commands;
+
+import java.io.IOException;
+
+import org.apache.accumulo.core.util.shell.Shell;
+import org.apache.accumulo.core.util.shell.Shell.Command;
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.Option;
+import org.apache.commons.cli.Options;
+
+public class AboutCommand extends Command {
+  private Option verboseOption;
+  
+  @Override
+  public String description() {
+    return "displays information about this program";
+  }
+  
+  @Override
+  public int execute(String fullCommand, CommandLine cl, Shell shellState) throws IOException {
+    shellState.printInfo();
+    if (cl.hasOption(verboseOption.getOpt()))
+      shellState.printVerboseInfo();
+    return 0;
+  }
+  
+  @Override
+  public int numArgs() {
+    return 0;
+  }
+  
+  @Override
+  public Options getOptions() {
+    Options opts = new Options();
+    verboseOption = new Option("v", "verbose", false, "display detailed session information");
+    opts.addOption(verboseOption);
+    return opts;
+  }
+}

http://git-wip-us.apache.org/repos/asf/accumulo/blob/7bdbfccb/1.5/core/src/main/java/org/apache/accumulo/core/util/shell/commands/ActiveScanIterator.java
----------------------------------------------------------------------
diff --git a/1.5/core/src/main/java/org/apache/accumulo/core/util/shell/commands/ActiveScanIterator.java b/1.5/core/src/main/java/org/apache/accumulo/core/util/shell/commands/ActiveScanIterator.java
new file mode 100644
index 0000000..baed8d1
--- /dev/null
+++ b/1.5/core/src/main/java/org/apache/accumulo/core/util/shell/commands/ActiveScanIterator.java
@@ -0,0 +1,90 @@
+/*
+ * 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.core.util.shell.commands;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.accumulo.core.client.admin.ActiveScan;
+import org.apache.accumulo.core.client.admin.InstanceOperations;
+import org.apache.accumulo.core.client.admin.ScanType;
+import org.apache.accumulo.core.util.Duration;
+
+class ActiveScanIterator implements Iterator<String> {
+  
+  private InstanceOperations instanceOps;
+  private Iterator<String> tsIter;
+  private Iterator<String> scansIter;
+  
+  private void readNext() {
+    List<String> scans = new ArrayList<String>();
+    
+    while (tsIter.hasNext()) {
+      
+      String tserver = tsIter.next();
+      try {
+        List<ActiveScan> asl = instanceOps.getActiveScans(tserver);
+        
+        for (ActiveScan as : asl)
+          scans.add(String.format("%21s |%21s |%9s |%9s |%7s |%6s |%8s |%8s |%10s |%10s |%10s | %s", tserver, as.getClient(),
+              Duration.format(as.getAge(), "", "-"), Duration.format(as.getLastContactTime(), "", "-"), as.getState(), as.getType(), as.getUser(),
+              as.getTable(), as.getColumns(), (as.getType() == ScanType.SINGLE ? as.getExtent() : "N/A"), as.getSsiList(), as.getSsio()));
+        
+      } catch (Exception e) {
+        scans.add(tserver + " ERROR " + e.getMessage());
+      }
+      
+      if (scans.size() > 0)
+        break;
+    }
+    
+    scansIter = scans.iterator();
+  }
+  
+  ActiveScanIterator(List<String> tservers, InstanceOperations instanceOps) {
+    this.instanceOps = instanceOps;
+    this.tsIter = tservers.iterator();
+    
+    String header = String.format(" %-21s| %-21s| %-9s| %-9s| %-7s| %-6s| %-8s| %-8s| %-10s| %-10s| %-10s | %s", "TABLET SERVER", "CLIENT", "AGE", "LAST",
+        "STATE", "TYPE", "USER", "TABLE", "COLUMNS", "TABLET", "ITERATORS", "ITERATOR OPTIONS");
+    
+    scansIter = Collections.singletonList(header).iterator();
+  }
+  
+  @Override
+  public boolean hasNext() {
+    return scansIter.hasNext();
+  }
+  
+  @Override
+  public String next() {
+    String next = scansIter.next();
+    
+    if (!scansIter.hasNext())
+      readNext();
+    
+    return next;
+  }
+  
+  @Override
+  public void remove() {
+    throw new UnsupportedOperationException();
+  }
+  
+}

http://git-wip-us.apache.org/repos/asf/accumulo/blob/7bdbfccb/1.5/core/src/main/java/org/apache/accumulo/core/util/shell/commands/AddSplitsCommand.java
----------------------------------------------------------------------
diff --git a/1.5/core/src/main/java/org/apache/accumulo/core/util/shell/commands/AddSplitsCommand.java b/1.5/core/src/main/java/org/apache/accumulo/core/util/shell/commands/AddSplitsCommand.java
new file mode 100644
index 0000000..b4864e2
--- /dev/null
+++ b/1.5/core/src/main/java/org/apache/accumulo/core/util/shell/commands/AddSplitsCommand.java
@@ -0,0 +1,96 @@
+/*
+ * 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.core.util.shell.commands;
+
+import java.io.File;
+import java.util.TreeSet;
+
+import org.apache.accumulo.core.client.TableNotFoundException;
+import org.apache.accumulo.core.util.shell.Shell;
+import org.apache.accumulo.core.util.shell.Shell.Command;
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.MissingArgumentException;
+import org.apache.commons.cli.Option;
+import org.apache.commons.cli.Options;
+import org.apache.commons.codec.binary.Base64;
+import org.apache.hadoop.io.Text;
+
+public class AddSplitsCommand extends Command {
+  private Option optSplitsFile, base64Opt;
+  
+  public int execute(String fullCommand, CommandLine cl, Shell shellState) throws Exception {
+    String tableName = OptUtil.getTableOpt(cl, shellState);
+    boolean decode = cl.hasOption(base64Opt.getOpt());
+    
+    TreeSet<Text> splits = new TreeSet<Text>();
+    
+    if (cl.hasOption(optSplitsFile.getOpt())) {
+      String f = cl.getOptionValue(optSplitsFile.getOpt());
+      
+      String line;
+      java.util.Scanner file = new java.util.Scanner(new File(f));
+      while (file.hasNextLine()) {
+        line = file.nextLine();
+        if (!line.isEmpty())
+          splits.add(decode ? new Text(Base64.decodeBase64(line.getBytes())) : new Text(line));
+      }
+    } else {
+      if (cl.getArgList().isEmpty())
+        throw new MissingArgumentException("No split points specified");
+      
+      for (String s : cl.getArgs()) {
+        splits.add(new Text(s.getBytes(Shell.CHARSET)));
+      }
+    }
+    
+    if (!shellState.getConnector().tableOperations().exists(tableName))
+      throw new TableNotFoundException(null, tableName, null);
+    shellState.getConnector().tableOperations().addSplits(tableName, splits);
+    
+    return 0;
+  }
+  
+  @Override
+  public String description() {
+    return "adds split points to an existing table";
+  }
+  
+  @Override
+  public Options getOptions() {
+    Options o = new Options();
+    
+    optSplitsFile = new Option("sf", "splits-file", true, "file with a newline-separated list of rows to split the table with");
+    optSplitsFile.setArgName("filename");
+    
+    base64Opt = new Option("b64", "base64encoded", false, "decode encoded split points (splits file only)");
+    
+    o.addOption(OptUtil.tableOpt("name of the table to add split points to"));
+    o.addOption(optSplitsFile);
+    o.addOption(base64Opt);
+    return o;
+  }
+  
+  @Override
+  public String usage() {
+    return getName() + " [<split>{ <split>} ]";
+  }
+  
+  @Override
+  public int numArgs() {
+    return Shell.NO_FIXED_ARG_LENGTH_CHECK;
+  }
+}

http://git-wip-us.apache.org/repos/asf/accumulo/blob/7bdbfccb/1.5/core/src/main/java/org/apache/accumulo/core/util/shell/commands/AuthenticateCommand.java
----------------------------------------------------------------------
diff --git a/1.5/core/src/main/java/org/apache/accumulo/core/util/shell/commands/AuthenticateCommand.java b/1.5/core/src/main/java/org/apache/accumulo/core/util/shell/commands/AuthenticateCommand.java
new file mode 100644
index 0000000..4c93b52
--- /dev/null
+++ b/1.5/core/src/main/java/org/apache/accumulo/core/util/shell/commands/AuthenticateCommand.java
@@ -0,0 +1,64 @@
+/*
+ * 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.core.util.shell.commands;
+
+import java.io.IOException;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.accumulo.core.client.AccumuloException;
+import org.apache.accumulo.core.client.AccumuloSecurityException;
+import org.apache.accumulo.core.util.shell.Shell;
+import org.apache.accumulo.core.util.shell.Shell.Command;
+import org.apache.accumulo.core.util.shell.Token;
+import org.apache.commons.cli.CommandLine;
+
+public class AuthenticateCommand extends Command {
+  @Override
+  public int execute(String fullCommand, CommandLine cl, Shell shellState) throws AccumuloException, AccumuloSecurityException, IOException {
+    String user = cl.getArgs()[0];
+    String p = shellState.readMaskedLine("Enter current password for '" + user + "': ", '*');
+    if (p == null) {
+      shellState.getReader().printNewline();
+      return 0;
+    } // user canceled
+    byte[] password = p.getBytes();
+    boolean valid = shellState.getConnector().securityOperations().authenticateUser(user, password);
+    shellState.getReader().printString((valid ? "V" : "Not v") + "alid\n");
+    return 0;
+  }
+  
+  @Override
+  public String description() {
+    return "verifies a user's credentials";
+  }
+  
+  @Override
+  public String usage() {
+    return getName() + " <username>";
+  }
+  
+  @Override
+  public void registerCompletion(Token root, Map<Command.CompletionSet,Set<String>> completionSet) {
+    registerCompletionForUsers(root, completionSet);
+  }
+  
+  @Override
+  public int numArgs() {
+    return 1;
+  }
+}

http://git-wip-us.apache.org/repos/asf/accumulo/blob/7bdbfccb/1.5/core/src/main/java/org/apache/accumulo/core/util/shell/commands/ByeCommand.java
----------------------------------------------------------------------
diff --git a/1.5/core/src/main/java/org/apache/accumulo/core/util/shell/commands/ByeCommand.java b/1.5/core/src/main/java/org/apache/accumulo/core/util/shell/commands/ByeCommand.java
new file mode 100644
index 0000000..f0c9d24
--- /dev/null
+++ b/1.5/core/src/main/java/org/apache/accumulo/core/util/shell/commands/ByeCommand.java
@@ -0,0 +1,19 @@
+/*
+ * 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.core.util.shell.commands;
+
+public class ByeCommand extends ExitCommand {}

http://git-wip-us.apache.org/repos/asf/accumulo/blob/7bdbfccb/1.5/core/src/main/java/org/apache/accumulo/core/util/shell/commands/ClasspathCommand.java
----------------------------------------------------------------------
diff --git a/1.5/core/src/main/java/org/apache/accumulo/core/util/shell/commands/ClasspathCommand.java b/1.5/core/src/main/java/org/apache/accumulo/core/util/shell/commands/ClasspathCommand.java
new file mode 100644
index 0000000..a39e8a4
--- /dev/null
+++ b/1.5/core/src/main/java/org/apache/accumulo/core/util/shell/commands/ClasspathCommand.java
@@ -0,0 +1,40 @@
+/*
+ * 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.core.util.shell.commands;
+
+import org.apache.accumulo.core.util.shell.Shell;
+import org.apache.accumulo.core.util.shell.Shell.Command;
+import org.apache.accumulo.start.classloader.AccumuloClassLoader;
+import org.apache.commons.cli.CommandLine;
+
+public class ClasspathCommand extends Command {
+  @Override
+  public int execute(String fullCommand, CommandLine cl, Shell shellState) {
+    AccumuloClassLoader.printClassPath();
+    return 0;
+  }
+  
+  @Override
+  public String description() {
+    return "lists the current files on the classpath";
+  }
+  
+  @Override
+  public int numArgs() {
+    return 0;
+  }
+}

http://git-wip-us.apache.org/repos/asf/accumulo/blob/7bdbfccb/1.5/core/src/main/java/org/apache/accumulo/core/util/shell/commands/ClearCommand.java
----------------------------------------------------------------------
diff --git a/1.5/core/src/main/java/org/apache/accumulo/core/util/shell/commands/ClearCommand.java b/1.5/core/src/main/java/org/apache/accumulo/core/util/shell/commands/ClearCommand.java
new file mode 100644
index 0000000..efdb0a6
--- /dev/null
+++ b/1.5/core/src/main/java/org/apache/accumulo/core/util/shell/commands/ClearCommand.java
@@ -0,0 +1,52 @@
+/*
+ * 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.core.util.shell.commands;
+
+import java.io.IOException;
+
+import org.apache.accumulo.core.util.shell.Shell;
+import org.apache.accumulo.core.util.shell.Shell.Command;
+import org.apache.commons.cli.CommandLine;
+
+public class ClearCommand extends Command {
+  @Override
+  public String description() {
+    return "clears the screen";
+  }
+  
+  @Override
+  public int execute(String fullCommand, CommandLine cl, Shell shellState) throws IOException {
+    // custom clear screen, so I don't have to redraw the prompt twice
+    if (!shellState.getReader().getTerminal().isANSISupported())
+      throw new IOException("Terminal does not support ANSI commands");
+    
+    // send the ANSI code to clear the screen
+    shellState.getReader().printString(((char) 27) + "[2J");
+    shellState.getReader().flushConsole();
+    
+    // then send the ANSI code to go to position 1,1
+    shellState.getReader().printString(((char) 27) + "[1;1H");
+    shellState.getReader().flushConsole();
+    
+    return 0;
+  }
+  
+  @Override
+  public int numArgs() {
+    return 0;
+  }
+}

http://git-wip-us.apache.org/repos/asf/accumulo/blob/7bdbfccb/1.5/core/src/main/java/org/apache/accumulo/core/util/shell/commands/CloneTableCommand.java
----------------------------------------------------------------------
diff --git a/1.5/core/src/main/java/org/apache/accumulo/core/util/shell/commands/CloneTableCommand.java b/1.5/core/src/main/java/org/apache/accumulo/core/util/shell/commands/CloneTableCommand.java
new file mode 100644
index 0000000..4593b48
--- /dev/null
+++ b/1.5/core/src/main/java/org/apache/accumulo/core/util/shell/commands/CloneTableCommand.java
@@ -0,0 +1,101 @@
+/*
+ * 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.core.util.shell.commands;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.accumulo.core.client.AccumuloException;
+import org.apache.accumulo.core.client.AccumuloSecurityException;
+import org.apache.accumulo.core.client.TableExistsException;
+import org.apache.accumulo.core.client.TableNotFoundException;
+import org.apache.accumulo.core.util.shell.Shell;
+import org.apache.accumulo.core.util.shell.Shell.Command;
+import org.apache.accumulo.core.util.shell.Token;
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.Option;
+import org.apache.commons.cli.Options;
+
+public class CloneTableCommand extends Command {
+  
+  private Option setPropsOption;
+  private Option excludePropsOption;
+  private Option noFlushOption;
+  
+  @Override
+  public int execute(String fullCommand, CommandLine cl, Shell shellState) throws AccumuloException, AccumuloSecurityException, TableNotFoundException,
+      TableExistsException {
+    
+    HashMap<String,String> props = new HashMap<String,String>();
+    HashSet<String> exclude = new HashSet<String>();
+    boolean flush = true;
+    
+    if (cl.hasOption(setPropsOption.getOpt())) {
+      String[] keyVals = cl.getOptionValue(setPropsOption.getOpt()).split(",");
+      for (String keyVal : keyVals) {
+        String[] sa = keyVal.split("=");
+        props.put(sa[0], sa[1]);
+      }
+    }
+    
+    if (cl.hasOption(excludePropsOption.getOpt())) {
+      String[] keys = cl.getOptionValue(excludePropsOption.getOpt()).split(",");
+      for (String key : keys)
+        exclude.add(key);
+    }
+    
+    if (cl.hasOption(noFlushOption.getOpt())) {
+      flush = false;
+    }
+    
+    shellState.getConnector().tableOperations().clone(cl.getArgs()[0], cl.getArgs()[1], flush, props, exclude);
+    return 0;
+  }
+  
+  @Override
+  public String usage() {
+    return getName() + " <current table name> <new table name>";
+  }
+  
+  @Override
+  public String description() {
+    return "clones a table";
+  }
+  
+  public void registerCompletion(Token root, Map<Command.CompletionSet,Set<String>> completionSet) {
+    registerCompletionForTables(root, completionSet);
+  }
+  
+  @Override
+  public Options getOptions() {
+    Options o = new Options();
+    setPropsOption = new Option("s", "set", true, "set initial properties before the table comes online. Expects <prop>=<value>{,<prop>=<value>}");
+    o.addOption(setPropsOption);
+    excludePropsOption = new Option("e", "exclude", true, "exclude properties that should not be copied from source table. Expects <prop>{,<prop>}");
+    o.addOption(excludePropsOption);
+    noFlushOption = new Option("nf", "noFlush", false, "do not flush table data in memory before cloning.");
+    o.addOption(noFlushOption);
+    return o;
+  }
+  
+  @Override
+  public int numArgs() {
+    return 2;
+  }
+}

http://git-wip-us.apache.org/repos/asf/accumulo/blob/7bdbfccb/1.5/core/src/main/java/org/apache/accumulo/core/util/shell/commands/ClsCommand.java
----------------------------------------------------------------------
diff --git a/1.5/core/src/main/java/org/apache/accumulo/core/util/shell/commands/ClsCommand.java b/1.5/core/src/main/java/org/apache/accumulo/core/util/shell/commands/ClsCommand.java
new file mode 100644
index 0000000..cef6098
--- /dev/null
+++ b/1.5/core/src/main/java/org/apache/accumulo/core/util/shell/commands/ClsCommand.java
@@ -0,0 +1,19 @@
+/*
+ * 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.core.util.shell.commands;
+
+public class ClsCommand extends ClearCommand {}

http://git-wip-us.apache.org/repos/asf/accumulo/blob/7bdbfccb/1.5/core/src/main/java/org/apache/accumulo/core/util/shell/commands/CompactCommand.java
----------------------------------------------------------------------
diff --git a/1.5/core/src/main/java/org/apache/accumulo/core/util/shell/commands/CompactCommand.java b/1.5/core/src/main/java/org/apache/accumulo/core/util/shell/commands/CompactCommand.java
new file mode 100644
index 0000000..c08a13a
--- /dev/null
+++ b/1.5/core/src/main/java/org/apache/accumulo/core/util/shell/commands/CompactCommand.java
@@ -0,0 +1,78 @@
+/*
+ * 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.core.util.shell.commands;
+
+import org.apache.accumulo.core.client.AccumuloException;
+import org.apache.accumulo.core.client.AccumuloSecurityException;
+import org.apache.accumulo.core.util.shell.Shell;
+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 CompactCommand extends TableOperation {
+  private Option noFlushOption, waitOpt;
+  private boolean flush;
+  private Text startRow;
+  private Text endRow;
+  
+  boolean override = false;
+  private boolean wait;
+  
+  @Override
+  public String description() {
+    return "sets all tablets for a table to major compact as soon as possible (based on current time)";
+  }
+  
+  protected void doTableOp(Shell shellState, String tableName) throws AccumuloException, AccumuloSecurityException {
+    // compact the tables
+    try {
+      if (wait)
+        Shell.log.info("Compacting table ...");
+      
+      shellState.getConnector().tableOperations().compact(tableName, startRow, endRow, flush, wait);
+      
+      Shell.log.info("Compaction of table " + tableName + " " + (wait ? "completed" : "started") + " for given range");
+    } catch (Exception ex) {
+      throw new AccumuloException(ex);
+    }
+  }
+  
+  @Override
+  public int execute(String fullCommand, CommandLine cl, Shell shellState) throws Exception {
+    flush = !cl.hasOption(noFlushOption.getOpt());
+    startRow = OptUtil.getStartRow(cl);
+    endRow = OptUtil.getEndRow(cl);
+    wait = cl.hasOption(waitOpt.getOpt());
+    
+    return super.execute(fullCommand, cl, shellState);
+  }
+  
+  @Override
+  public Options getOptions() {
+    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);
+    
+    return opts;
+  }
+}


Mime
View raw message