http://git-wip-us.apache.org/repos/asf/accumulo/blob/cfbdef13/server/tserver/src/test/java/org/apache/accumulo/tserver/replication/ReplicationProcessorTest.java
----------------------------------------------------------------------
diff --cc 
server/tserver/src/test/java/org/apache/accumulo/tserver/replication/ReplicationProcessorTest.java
index e37d78a,0000000..d389c0b
mode 100644,000000..100644
--- 
a/server/tserver/src/test/java/org/apache/accumulo/tserver/replication/ReplicationProcessorTest.java
+++ 
b/server/tserver/src/test/java/org/apache/accumulo/tserver/replication/ReplicationProcessorTest.java
@@@ -1,100 -1,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.tserver.replication;
 +
- import java.nio.charset.StandardCharsets;
++import static java.nio.charset.StandardCharsets.UTF_8;
++
 +import java.util.HashMap;
 +import java.util.Map;
 +
 +import org.apache.accumulo.core.client.Instance;
 +import org.apache.accumulo.core.client.replication.ReplicaSystem;
 +import org.apache.accumulo.core.client.security.tokens.PasswordToken;
 +import org.apache.accumulo.core.conf.ConfigurationCopy;
 +import org.apache.accumulo.core.conf.Property;
 +import org.apache.accumulo.core.replication.ReplicaSystemHelper;
 +import org.apache.accumulo.core.replication.ReplicationTarget;
 +import org.apache.accumulo.core.replication.proto.Replication.Status;
 +import org.apache.accumulo.core.security.Credentials;
 +import org.apache.accumulo.server.fs.VolumeManager;
 +import 
org.apache.accumulo.server.replication.DistributedWorkQueueWorkAssignerHelper;
 +import org.apache.hadoop.fs.Path;
 +import org.easymock.EasyMock;
 +import org.junit.Assert;
 +import org.junit.Test;
 +
 +/**
 + * 
 + */
 +public class ReplicationProcessorTest {
 +
 +  @Test
 +  public void peerTypeExtractionFromConfiguration() {
 +    Instance inst = EasyMock.createMock(Instance.class);
 +    VolumeManager fs = EasyMock.createMock(VolumeManager.class);
 +    Credentials creds = new Credentials("foo", new PasswordToken("bar"));
 +
 +    Map<String,String> data = new HashMap<>();
 +
 +    String peerName = "peer";
 +    String configuration = "java.lang.String,foo";
 +    data.put(Property.REPLICATION_PEERS + peerName, configuration);
 +    ConfigurationCopy conf = new ConfigurationCopy(data);
 +
 +    ReplicationProcessor proc = new ReplicationProcessor(inst, conf, fs, 
creds);
 +
 +    Assert.assertEquals(configuration, proc.getPeerType(peerName));
 +  }
 +
 +  @Test(expected = IllegalArgumentException.class)
 +  public void noPeerConfigurationThrowsAnException() {
 +    Instance inst = EasyMock.createMock(Instance.class);
 +    VolumeManager fs = EasyMock.createMock(VolumeManager.class);
 +    Credentials creds = new Credentials("foo", new PasswordToken("bar"));
 +
 +    Map<String,String> data = new HashMap<>();
 +    ConfigurationCopy conf = new ConfigurationCopy(data);
 +
 +    ReplicationProcessor proc = new ReplicationProcessor(inst, conf, fs, 
creds);
 +
 +    proc.getPeerType("foo");
 +  }
 +
 +  @Test
 +  public void filesWhichMakeNoProgressArentReplicatedAgain() throws Exception 
{
 +    ReplicaSystem replica = EasyMock.createMock(ReplicaSystem.class);
 +    ReplicaSystemHelper helper = 
EasyMock.createMock(ReplicaSystemHelper.class);
 +    ReplicationProcessor proc = 
EasyMock.createMockBuilder(ReplicationProcessor.class).addMockedMethods("getReplicaSystem",
 "doesFileExist", "getStatus", "getHelper").createMock();
 +
 +    ReplicationTarget target = new ReplicationTarget("peer", "1", "1");
 +    Status status = 
Status.newBuilder().setBegin(0).setEnd(0).setInfiniteEnd(true).setClosed(true).build();
 +    Path path = new Path("/accumulo");
 +
 +    String queueKey = 
DistributedWorkQueueWorkAssignerHelper.getQueueKey(path.toString(), target);
 +
 +    EasyMock.expect(proc.getReplicaSystem(target)).andReturn(replica);
 +    EasyMock.expect(proc.getStatus(path.toString(), 
target)).andReturn(status);
 +    EasyMock.expect(proc.doesFileExist(path, target)).andReturn(true);
 +    EasyMock.expect(proc.getHelper()).andReturn(helper);
 +    EasyMock.expect(replica.replicate(path, status, target, 
helper)).andReturn(status);
 +
 +    EasyMock.replay(replica, proc);
 +
-     proc.process(queueKey, path.toString().getBytes(StandardCharsets.UTF_8));
++    proc.process(queueKey, path.toString().getBytes(UTF_8));
 +
 +    EasyMock.verify(replica, proc);
 +  }
 +}

http://git-wip-us.apache.org/repos/asf/accumulo/blob/cfbdef13/shell/src/main/java/org/apache/accumulo/shell/Shell.java
----------------------------------------------------------------------
diff --cc shell/src/main/java/org/apache/accumulo/shell/Shell.java
index 2ebdb6c,0000000..a0ff17a
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,1229 -1,0 +1,1231 @@@
 +/*
 + * 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.UTF_8;
++import static java.nio.charset.StandardCharsets.ISO_8859_1;
++
 +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.nio.charset.StandardCharsets;
 +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.ClientConfigurationHelper;
 +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.DefaultConfiguration;
 +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.fate.zookeeper.ZooReader;
 +import org.apache.accumulo.start.classloader.vfs.AccumuloVFSClassLoader;
 +import org.apache.accumulo.start.classloader.vfs.ContextManager;
 +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.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;
 +
 +/**
 + * 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 Charset CHARSET = StandardCharsets.ISO_8859_1;
++  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 String principal;
 +  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[]>();
 +  protected boolean configError = false;
 +
 +  // 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;
 +  }
 +
 +  // Not for client use
 +  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) {
 +      configError = true;
 +    }
 +
 +    if (options.isHelpEnabled()) {
 +      configError = true;
 +    }
 +
 +    if (!configError && options.getUnrecognizedOptions() != null) {
 +      configError = true;
 +      logError("Unrecognized Options: " + 
options.getUnrecognizedOptions().toString());
 +    }
 +
 +    if (configError) {
 +      jc.usage();
 +      return true;
 +    }
 +
 +    setDebugging(options.isDebugEnabled());
 +    authTimeout = TimeUnit.MINUTES.toNanos(options.getAuthTimeout());
 +    disableAuthTimeout = options.isAuthTimeoutDisabled();
 +
 +    // get the options that were parsed
 +    String user = options.getUsername();
 +    String password = options.getPassword();
 +
 +    tabCompletion = !options.isTabCompletionDisabled();
 +
 +    // Use a fake (Mock), ZK, or HdfsZK Accumulo instance
 +    setInstance(options);
 +
 +    // AuthenticationToken options
 +    token = options.getAuthenticationToken();
 +    Map<String,String> loginOptions = options.getTokenProperties();
 +
 +    // process default parameters if unspecified
 +    try {
 +      boolean hasToken = (token != null);
 +      boolean hasTokenOptions = !loginOptions.isEmpty();
 +
 +      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);
 +        }
 +      });
 +
 +      // Need either both a token and options, or neither, but not just one.
 +      if (hasToken != hasTokenOptions) {
 +        throw new ParameterException("Must supply either both or neither of 
'--tokenClass' and '--tokenProperty'");
 +      } else 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();
 +
 +        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()) {
 +        ZooReader zr = new ZooReader(instance.getZooKeepers(), 
instance.getZooKeepersSessionTimeOut());
 +        DistributedTrace.enable(instance, zr, "shell", 
InetAddress.getLocalHost().getHostName());
 +      }
 +
 +      this.setTableName("");
 +      this.principal = user;
 +      connector = instance.getConnector(this.principal, token);
 +
 +    } catch (Exception e) {
 +      printException(e);
 +      configError = true;
 +    }
 +
 +    // 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 configError;
 +  }
 +
 +  /**
 +   * 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);
 +      }
 +    }
 +  }
 +
 +  /*
 +   * 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 keepers, 
ClientConfiguration clientConfig) {
 +    UUID instanceId = null;
 +    if (instanceName == null) {
 +      instanceName = clientConfig.get(ClientProperty.INSTANCE_NAME);
 +    }
 +    if (instanceName == null || keepers == null) {
 +      AccumuloConfiguration conf = 
SiteConfiguration.getInstance(ClientConfigurationHelper.convertClientConfig(DefaultConfiguration.getInstance(),
 clientConfig));
 +      if (instanceName == null) {
 +        Path instanceDir = new 
Path(VolumeConfiguration.getVolumeUris(conf)[0], "instance_id");
 +        instanceId = 
UUID.fromString(ZooUtil.getInstanceIDFromHdfs(instanceDir, conf));
 +      }
 +      if (keepers == null) {
 +        keepers = conf.get(Property.INSTANCE_ZK_HOST);
 +      }
 +    }
 +    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;
 +  }
 +
 +  public static void main(String args[]) throws IOException {
 +    Shell shell = new Shell();
 +    try {
 +      shell.config(args);
 +
 +      System.exit(shell.start());
 +    } finally {
 +      shell.shutdown();
 +    }
 +  }
 +
 +  public int start() throws IOException {
 +    if (configError)
 +      return 1;
 +
 +    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, 
StandardCharsets.UTF_8.name());
++      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
 +    }
 +
 +    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);
 +    }
 +
 +    static Set<String> getNamespaces(Map<CompletionSet,Set<String>> objects) {
 +      return objects.get(CompletionSet.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), StandardCharsets.UTF_8)));
++      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);
 +  }
 +
 +  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.principal = principal;
 +    this.token = token;
 +  }
 +
 +  public String getPrincipal() {
 +    return principal;
 +  }
 +
 +  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/cfbdef13/shell/src/main/java/org/apache/accumulo/shell/ShellUtil.java
----------------------------------------------------------------------
diff --cc shell/src/main/java/org/apache/accumulo/shell/ShellUtil.java
index d8b9f65,0000000..966fb00
mode 100644,000000..100644
--- a/shell/src/main/java/org/apache/accumulo/shell/ShellUtil.java
+++ b/shell/src/main/java/org/apache/accumulo/shell/ShellUtil.java
@@@ -1,60 -1,0 +1,61 @@@
 +/*
 + * 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.UTF_8;
++
 +import java.io.File;
 +import java.io.FileNotFoundException;
- import java.nio.charset.StandardCharsets;
 +import java.util.List;
 +import java.util.Scanner;
 +
 +import org.apache.accumulo.core.util.Base64;
 +import org.apache.hadoop.io.Text;
 +
 +import com.google.common.collect.Lists;
 +
 +public class ShellUtil {
 +
 +  /**
 +   * Scans the given file line-by-line (ignoring empty lines) and returns a 
list containing those lines. If decode is set to true, every line is decoded 
using
 +   * {@link Base64#decodeBase64(byte[])} from the UTF-8 bytes of that line 
before inserting in the list.
 +   * 
 +   * @param filename
 +   *          Path to the file that needs to be scanned
 +   * @param decode
 +   *          Whether to decode lines in the file
 +   * @return List of {@link Text} objects containing data in the given file
 +   * @throws FileNotFoundException
 +   *           if the given file doesn't exist
 +   */
 +  public static List<Text> scanFile(String filename, boolean decode) throws 
FileNotFoundException {
 +    String line;
-     Scanner file = new Scanner(new File(filename), 
StandardCharsets.UTF_8.name());
++    Scanner file = new Scanner(new File(filename), UTF_8.name());
 +    List<Text> result = Lists.newArrayList();
 +    try {
 +      while (file.hasNextLine()) {
 +        line = file.nextLine();
 +        if (!line.isEmpty()) {
-           result.add(decode ? new 
Text(Base64.decodeBase64(line.getBytes(StandardCharsets.UTF_8))) : new 
Text(line));
++          result.add(decode ? new 
Text(Base64.decodeBase64(line.getBytes(UTF_8))) : new Text(line));
 +        }
 +      }
 +    } finally {
 +      file.close();
 +    }
 +    return result;
 +  }
 +}

http://git-wip-us.apache.org/repos/asf/accumulo/blob/cfbdef13/shell/src/main/java/org/apache/accumulo/shell/commands/AuthenticateCommand.java
----------------------------------------------------------------------
diff --cc 
shell/src/main/java/org/apache/accumulo/shell/commands/AuthenticateCommand.java
index 807de24,0000000..ef35f52
mode 100644,000000..100644
--- 
a/shell/src/main/java/org/apache/accumulo/shell/commands/AuthenticateCommand.java
+++ 
b/shell/src/main/java/org/apache/accumulo/shell/commands/AuthenticateCommand.java
@@@ -1,66 -1,0 +1,67 @@@
 +/*
 + * 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 static java.nio.charset.StandardCharsets.UTF_8;
++
 +import java.io.IOException;
- import java.nio.charset.StandardCharsets;
 +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.security.tokens.PasswordToken;
 +import org.apache.accumulo.shell.Shell;
 +import org.apache.accumulo.shell.Token;
 +import org.apache.accumulo.shell.Shell.Command;
 +import org.apache.commons.cli.CommandLine;
 +
 +public class AuthenticateCommand extends Command {
 +  @Override
 +  public int execute(final String fullCommand, final CommandLine cl, final 
Shell shellState) throws AccumuloException, AccumuloSecurityException, 
IOException {
 +    final String user = cl.getArgs()[0];
 +    final String p = shellState.readMaskedLine("Enter current password for '" 
+ user + "': ", '*');
 +    if (p == null) {
 +      shellState.getReader().println();
 +      return 0;
 +    } // user canceled
-     final byte[] password = p.getBytes(StandardCharsets.UTF_8);
++    final byte[] password = p.getBytes(UTF_8);
 +    final boolean valid = 
shellState.getConnector().securityOperations().authenticateUser(user, new 
PasswordToken(password));
 +    shellState.getReader().println((valid ? "V" : "Not v") + "alid");
 +    return 0;
 +  }
 +  
 +  @Override
 +  public String description() {
 +    return "verifies a user's credentials";
 +  }
 +  
 +  @Override
 +  public String usage() {
 +    return getName() + " <username>";
 +  }
 +  
 +  @Override
 +  public void registerCompletion(final Token root, final 
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/cfbdef13/shell/src/main/java/org/apache/accumulo/shell/commands/ExecfileCommand.java
----------------------------------------------------------------------
diff --cc 
shell/src/main/java/org/apache/accumulo/shell/commands/ExecfileCommand.java
index b384d5c,0000000..fb8af7f
mode 100644,000000..100644
--- 
a/shell/src/main/java/org/apache/accumulo/shell/commands/ExecfileCommand.java
+++ 
b/shell/src/main/java/org/apache/accumulo/shell/commands/ExecfileCommand.java
@@@ -1,67 -1,0 +1,68 @@@
 +/*
 + * 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 static java.nio.charset.StandardCharsets.UTF_8;
++
 +import java.io.File;
- import java.nio.charset.StandardCharsets;
 +import java.util.Scanner;
 +
 +import org.apache.accumulo.shell.Shell;
 +import org.apache.accumulo.shell.Shell.Command;
 +import org.apache.commons.cli.CommandLine;
 +import org.apache.commons.cli.Option;
 +import org.apache.commons.cli.Options;
 +
 +public class ExecfileCommand extends Command {
 +  private Option verboseOption;
 +  
 +  @Override
 +  public String description() {
 +    return "specifies a file containing accumulo commands to execute";
 +  }
 +  
 +  @Override
 +  public int execute(final String fullCommand, final CommandLine cl, final 
Shell shellState) throws Exception {
-     Scanner scanner = new Scanner(new File(cl.getArgs()[0]), 
StandardCharsets.UTF_8.name());
++    Scanner scanner = new Scanner(new File(cl.getArgs()[0]), UTF_8.name());
 +    try {
 +      while (scanner.hasNextLine()) {
 +        shellState.execCommand(scanner.nextLine(), true, 
cl.hasOption(verboseOption.getOpt()));
 +      }
 +    } finally {
 +      scanner.close();
 +    }
 +    return 0;
 +  }
 +  
 +  @Override
 +  public String usage() {
 +    return getName() + " <fileName>";
 +  }
 +  
 +  @Override
 +  public int numArgs() {
 +    return 1;
 +  }
 +  
 +  @Override
 +  public Options getOptions() {
 +    final Options opts = new Options();
 +    verboseOption = new Option("v", "verbose", false, "display command prompt 
as commands are executed");
 +    opts.addOption(verboseOption);
 +    return opts;
 +  }
 +}

http://git-wip-us.apache.org/repos/asf/accumulo/blob/cfbdef13/shell/src/main/java/org/apache/accumulo/shell/commands/HiddenCommand.java
----------------------------------------------------------------------
diff --cc 
shell/src/main/java/org/apache/accumulo/shell/commands/HiddenCommand.java
index 8cbf214,0000000..f21e33a
mode 100644,000000..100644
--- a/shell/src/main/java/org/apache/accumulo/shell/commands/HiddenCommand.java
+++ b/shell/src/main/java/org/apache/accumulo/shell/commands/HiddenCommand.java
@@@ -1,62 -1,0 +1,63 @@@
 +/*
 + * 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.nio.charset.StandardCharsets;
++import static java.nio.charset.StandardCharsets.UTF_8;
++
 +import java.security.SecureRandom;
 +import java.util.Random;
 +
 +import org.apache.accumulo.core.util.Base64;
 +import org.apache.accumulo.shell.Shell;
 +import org.apache.accumulo.shell.ShellCommandException;
 +import org.apache.accumulo.shell.Shell.Command;
 +import org.apache.accumulo.shell.ShellCommandException.ErrorCode;
 +import org.apache.commons.cli.CommandLine;
 +
 +public class HiddenCommand extends Command {
 +  private static Random rand = new SecureRandom();
 +  
 +  @Override
 +  public String description() {
 +    return "The first rule of Accumulo is: \"You don't talk about 
Accumulo.\"";
 +  }
 +  
 +  @Override
 +  public int execute(final String fullCommand, final CommandLine cl, final 
Shell shellState) throws Exception {
 +    if (rand.nextInt(10) == 0) {
 +      shellState.getReader().beep();
 +      shellState.getReader().println();
 +      shellState.getReader().println(
 +          new 
String(Base64.decodeBase64(("ICAgICAgIC4tLS4KICAgICAgLyAvXCBcCiAgICAgKCAvLS1cICkKICAgICAuPl8gIF88LgogICAgLyB8ICd8ICcgXAog"
 +              + 
"ICAvICB8Xy58Xy4gIFwKICAvIC98ICAgICAgfFwgXAogfCB8IHwgfFwvfCB8IHwgfAogfF98IHwgfCAgfCB8IHxffAogICAgIC8gIF9fICBcCiAgICAvICAv"
-               + 
"ICBcICBcCiAgIC8gIC8gICAgXCAgXF8KIHwvICAvICAgICAgXCB8IHwKIHxfXy8gICAgICAgIFx8X3wK").getBytes(StandardCharsets.UTF_8)),
 StandardCharsets.UTF_8));
++              + 
"ICBcICBcCiAgIC8gIC8gICAgXCAgXF8KIHwvICAvICAgICAgXCB8IHwKIHxfXy8gICAgICAgIFx8X3wK").getBytes(UTF_8)),
 UTF_8));
 +    } else {
 +      throw new ShellCommandException(ErrorCode.UNRECOGNIZED_COMMAND, 
getName());
 +    }
 +    return 0;
 +  }
 +  
 +  @Override
 +  public int numArgs() {
 +    return Shell.NO_FIXED_ARG_LENGTH_CHECK;
 +  }
 +  
 +  @Override
 +  public String getName() {
 +    return "accvmvlo";
 +  }
 +}

http://git-wip-us.apache.org/repos/asf/accumulo/blob/cfbdef13/shell/src/main/java/org/apache/accumulo/shell/commands/PasswdCommand.java
----------------------------------------------------------------------
diff --cc 
shell/src/main/java/org/apache/accumulo/shell/commands/PasswdCommand.java
index 86c78fc,0000000..dd38889
mode 100644,000000..100644
--- a/shell/src/main/java/org/apache/accumulo/shell/commands/PasswdCommand.java
+++ b/shell/src/main/java/org/apache/accumulo/shell/commands/PasswdCommand.java
@@@ -1,97 -1,0 +1,97 @@@
 +/*
 + * 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.IOException;
- import java.nio.charset.StandardCharsets;
++import static java.nio.charset.StandardCharsets.UTF_8;
 +
++import java.io.IOException;
 +import org.apache.accumulo.core.client.AccumuloException;
 +import org.apache.accumulo.core.client.AccumuloSecurityException;
 +import org.apache.accumulo.core.client.impl.thrift.SecurityErrorCode;
 +import org.apache.accumulo.core.client.security.tokens.PasswordToken;
 +import org.apache.accumulo.shell.Shell;
 +import org.apache.accumulo.shell.Shell.Command;
 +import org.apache.accumulo.shell.ShellOptions;
 +import org.apache.commons.cli.CommandLine;
 +import org.apache.commons.cli.Option;
 +import org.apache.commons.cli.Options;
 +
 +public class PasswdCommand extends Command {
 +  private Option userOpt;
 +  
 +  @Override
 +  public int execute(final String fullCommand, final CommandLine cl, final 
Shell shellState) throws AccumuloException, AccumuloSecurityException, 
IOException {
 +    final String currentUser = shellState.getConnector().whoami();
 +    final String user = cl.getOptionValue(userOpt.getOpt(), currentUser);
 +    
 +    String password = null;
 +    String passwordConfirm = null;
 +    String oldPassword = null;
 +    
 +    oldPassword = shellState.readMaskedLine("Enter current password for '" + 
currentUser + "': ", '*');
 +    if (oldPassword == null) {
 +      shellState.getReader().println();
 +      return 0;
 +    } // user canceled
 +    
 +    if 
(!shellState.getConnector().securityOperations().authenticateUser(currentUser, 
new PasswordToken(oldPassword)))
 +      throw new AccumuloSecurityException(user, 
SecurityErrorCode.BAD_CREDENTIALS);
 +    
 +    password = shellState.readMaskedLine("Enter new password for '" + user + 
"': ", '*');
 +    if (password == null) {
 +      shellState.getReader().println();
 +      return 0;
 +    } // user canceled
 +    passwordConfirm = shellState.readMaskedLine("Please confirm new password 
for '" + user + "': ", '*');
 +    if (passwordConfirm == null) {
 +      shellState.getReader().println();
 +      return 0;
 +    } // user canceled
 +    
 +    if (!password.equals(passwordConfirm)) {
 +      throw new IllegalArgumentException("Passwords do not match");
 +    }
-     byte[] pass = password.getBytes(StandardCharsets.UTF_8);
++    byte[] pass = password.getBytes(UTF_8);
 +    
shellState.getConnector().securityOperations().changeLocalUserPassword(user, 
new PasswordToken(pass));
 +    // update the current credentials if the password changed was for
 +    // the current user
 +    if (shellState.getConnector().whoami().equals(user)) {
 +      shellState.updateUser(user, new PasswordToken(pass));
 +    }
 +    Shell.log.debug("Changed password for user " + user);
 +    return 0;
 +  }
 +  
 +  @Override
 +  public String description() {
 +    return "changes a user's password";
 +  }
 +  
 +  @Override
 +  public Options getOptions() {
 +    final Options o = new Options();
 +    userOpt = new Option(ShellOptions.userOption, "user", true, "user to 
operate on");
 +    userOpt.setArgName("user");
 +    o.addOption(userOpt);
 +    return o;
 +  }
 +  
 +  @Override
 +  public int numArgs() {
 +    return 0;
 +  }
 +}

http://git-wip-us.apache.org/repos/asf/accumulo/blob/cfbdef13/shell/src/main/java/org/apache/accumulo/shell/commands/QuotedStringTokenizer.java
----------------------------------------------------------------------
diff --cc 
shell/src/main/java/org/apache/accumulo/shell/commands/QuotedStringTokenizer.java
index ecc51eb,0000000..2fdb7fe
mode 100644,000000..100644
--- 
a/shell/src/main/java/org/apache/accumulo/shell/commands/QuotedStringTokenizer.java
+++ 
b/shell/src/main/java/org/apache/accumulo/shell/commands/QuotedStringTokenizer.java
@@@ -1,141 -1,0 +1,142 @@@
 +/*
 + * 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 static java.nio.charset.StandardCharsets.UTF_8;
++
 +import java.io.UnsupportedEncodingException;
- import java.nio.charset.StandardCharsets;
 +import java.util.ArrayList;
 +import java.util.Iterator;
 +
 +import org.apache.accumulo.core.util.BadArgumentException;
 +import org.apache.accumulo.shell.Shell;
 +
 +/**
 + * A basic tokenizer for generating tokens from a string. It understands 
quoted strings and escaped quote characters.
 + * 
 + * You can use the escape sequence '\' to escape single quotes, double 
quotes, and spaces only, in addition to the escape character itself.
 + * 
 + * The behavior is the same for single and double quoted strings. (i.e. '\'' 
is the same as "\'")
 + */
 +
 +public class QuotedStringTokenizer implements Iterable<String> {
 +  private ArrayList<String> tokens;
 +  private String input;
 +  
 +  public QuotedStringTokenizer(final String t) throws BadArgumentException {
 +    tokens = new ArrayList<String>();
 +    this.input = t;
 +    try {
 +      createTokens();
 +    } catch (UnsupportedEncodingException e) {
 +      throw new IllegalArgumentException(e.getMessage());
 +    }
 +  }
 +  
 +  public String[] getTokens() {
 +    return tokens.toArray(new String[tokens.size()]);
 +  }
 +  
 +  private void createTokens() throws BadArgumentException, 
UnsupportedEncodingException {
 +    boolean inQuote = false;
 +    boolean inEscapeSequence = false;
 +    String hexChars = null;
 +    char inQuoteChar = '"';
 +    
 +    final byte[] token = new byte[input.length()];
 +    int tokenLength = 0;
-     final byte[] inputBytes = input.getBytes(StandardCharsets.UTF_8);
++    final byte[] inputBytes = input.getBytes(UTF_8);
 +    for (int i = 0; i < input.length(); ++i) {
 +      final char ch = input.charAt(i);
 +      
 +      // if I ended up in an escape sequence, check for valid escapable 
character, and add it as a literal
 +      if (inEscapeSequence) {
 +        inEscapeSequence = false;
 +        if (ch == 'x') {
 +          hexChars = "";
 +        } else if (ch == ' ' || ch == '\'' || ch == '"' || ch == '\\') {
 +          token[tokenLength++] = inputBytes[i];
 +        } else {
 +          throw new BadArgumentException("can only escape single quotes, 
double quotes, the space character, the backslash, and hex input", input, i);
 +        }
 +      }
 +      // in a hex escape sequence
 +      else if (hexChars != null) {
 +        final int digit = Character.digit(ch, 16);
 +        if (digit < 0) {
 +          throw new BadArgumentException("expected hex character", input, i);
 +        }
 +        hexChars += ch;
 +        if (hexChars.length() == 2) {
 +          byte b;
 +          try {
 +            b = (byte) (0xff & Short.parseShort(hexChars, 16));
 +            if (!Character.isValidCodePoint(0xff & b))
 +              throw new NumberFormatException();
 +          } catch (NumberFormatException e) {
 +            throw new BadArgumentException("unsupported non-ascii character", 
input, i);
 +          }
 +          token[tokenLength++] = b;
 +          hexChars = null;
 +        }
 +      }
 +      // in a quote, either end the quote, start escape, or continue a token
 +      else if (inQuote) {
 +        if (ch == inQuoteChar) {
 +          inQuote = false;
 +          tokens.add(new String(token, 0, tokenLength, Shell.CHARSET));
 +          tokenLength = 0;
 +        } else if (ch == '\\') {
 +          inEscapeSequence = true;
 +        } else {
 +          token[tokenLength++] = inputBytes[i];
 +        }
 +      }
 +      // not in a quote, either enter a quote, end a token, start escape, or 
continue a token
 +      else {
 +        if (ch == '\'' || ch == '"') {
 +          if (tokenLength > 0) {
 +            tokens.add(new String(token, 0, tokenLength, Shell.CHARSET));
 +            tokenLength = 0;
 +          }
 +          inQuote = true;
 +          inQuoteChar = ch;
 +        } else if (ch == ' ' && tokenLength > 0) {
 +          tokens.add(new String(token, 0, tokenLength, Shell.CHARSET));
 +          tokenLength = 0;
 +        } else if (ch == '\\') {
 +          inEscapeSequence = true;
 +        } else if (ch != ' ') {
 +          token[tokenLength++] = inputBytes[i];
 +        }
 +      }
 +    }
 +    if (inQuote) {
 +      throw new BadArgumentException("missing terminating quote", input, 
input.length());
 +    } else if (inEscapeSequence || hexChars != null) {
 +      throw new BadArgumentException("escape sequence not complete", input, 
input.length());
 +    }
 +    if (tokenLength > 0) {
 +      tokens.add(new String(token, 0, tokenLength, Shell.CHARSET));
 +    }
 +  }
 +  
 +  @Override
 +  public Iterator<String> iterator() {
 +    return tokens.iterator();
 +  }
 +}

http://git-wip-us.apache.org/repos/asf/accumulo/blob/cfbdef13/shell/src/main/java/org/apache/accumulo/shell/commands/UserCommand.java
----------------------------------------------------------------------
diff --cc 
shell/src/main/java/org/apache/accumulo/shell/commands/UserCommand.java
index 491f144,0000000..6e7247e
mode 100644,000000..100644
--- a/shell/src/main/java/org/apache/accumulo/shell/commands/UserCommand.java
+++ b/shell/src/main/java/org/apache/accumulo/shell/commands/UserCommand.java
@@@ -1,71 -1,0 +1,72 @@@
 +/*
 + * 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 static java.nio.charset.StandardCharsets.UTF_8;
++
 +import java.io.IOException;
- import java.nio.charset.StandardCharsets;
 +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.security.tokens.PasswordToken;
 +import org.apache.accumulo.shell.Shell;
 +import org.apache.accumulo.shell.Token;
 +import org.apache.accumulo.shell.Shell.Command;
 +import org.apache.commons.cli.CommandLine;
 +
 +public class UserCommand extends Command {
 +  @Override
 +  public int execute(final String fullCommand, final CommandLine cl, final 
Shell shellState) throws AccumuloException, AccumuloSecurityException, 
IOException {
 +    // save old credentials and connection in case of failure
 +    String user = cl.getArgs()[0];
 +    byte[] pass;
 +    
 +    // We can't let the wrapping try around the execute method deal
 +    // with the exceptions because we have to do something if one
 +    // of these methods fails
 +    final String p = shellState.readMaskedLine("Enter password for user " + 
user + ": ", '*');
 +    if (p == null) {
 +      shellState.getReader().println();
 +      return 0;
 +    } // user canceled
-     pass = p.getBytes(StandardCharsets.UTF_8);
++    pass = p.getBytes(UTF_8);
 +    shellState.updateUser(user, new PasswordToken(pass));
 +    return 0;
 +  }
 +  
 +  @Override
 +  public String description() {
 +    return "switches to the specified user";
 +  }
 +  
 +  @Override
 +  public void registerCompletion(final Token root, final 
Map<Command.CompletionSet,Set<String>> special) {
 +    registerCompletionForUsers(root, special);
 +  }
 +  
 +  @Override
 +  public String usage() {
 +    return getName() + " <username>";
 +  }
 +  
 +  @Override
 +  public int numArgs() {
 +    return 1;
 +  }
 +}

http://git-wip-us.apache.org/repos/asf/accumulo/blob/cfbdef13/shell/src/main/java/org/apache/accumulo/shell/mock/MockShell.java
----------------------------------------------------------------------
diff --cc shell/src/main/java/org/apache/accumulo/shell/mock/MockShell.java
index cf028eb,0000000..f862b68
mode 100644,000000..100644
--- a/shell/src/main/java/org/apache/accumulo/shell/mock/MockShell.java
+++ b/shell/src/main/java/org/apache/accumulo/shell/mock/MockShell.java
@@@ -1,143 -1,0 +1,143 @@@
 +/*
 + * 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.mock;
 +
++import static java.nio.charset.StandardCharsets.UTF_8;
++
 +import java.io.ByteArrayInputStream;
 +import java.io.IOException;
 +import java.io.InputStream;
 +import java.io.OutputStream;
- import java.nio.charset.StandardCharsets;
- 
 +import jline.console.ConsoleReader;
 +
 +import org.apache.accumulo.core.client.mock.MockInstance;
 +import org.apache.accumulo.shell.Shell;
 +import org.apache.accumulo.shell.ShellOptionsJC;
 +
 +/**
 + * An Accumulo Shell implementation that allows a developer to attach an 
InputStream and Writer to the Shell for testing purposes.
 + */
 +public class MockShell extends Shell {
 +  private static final String NEWLINE = "\n";
 +  
 +  protected InputStream in;
 +  protected OutputStream out;
 +
 +  public MockShell(InputStream in, OutputStream out) throws IOException {
 +    super();
 +    this.in = in;
 +    this.out = out;
 +  }
 +
 +  public boolean config(String... args) {
 +    configError = super.config(args);
 +    
 +    // Update the ConsoleReader with the input and output "redirected"
 +    try {
 +      this.reader = new ConsoleReader(in, out);
 +    } catch (Exception e) {
 +      printException(e);
 +      configError = true;
 +    }
 +    
 +    // Don't need this for testing purposes
 +    this.reader.setHistoryEnabled(false);
 +    this.reader.setPaginationEnabled(false);
 +    
 +    // Make the parsing from the client easier;
 +    this.verbose = false;
 +    return configError;
 +  }
 +  
 +  @Override
 +  protected void setInstance(ShellOptionsJC options) {
 +    // We always want a MockInstance for this test
 +    instance = new MockInstance();
 +  }
 +
 +  public int start() throws IOException {
 +    if (configError)
 +      return 1;
 +    
 +    String input;
 +    if (isVerbose())
 +      printInfo();
 +    
 +    if (execFile != null) {
-       java.util.Scanner scanner = new java.util.Scanner(execFile, 
StandardCharsets.UTF_8.name());
++      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) {
 +      if (hasExited())
 +        return exitCode;
 +      
 +      reader.setPrompt(getDefaultPrompt());
 +      input = reader.readLine();
 +      if (input == null) {
 +        reader.println();
 +        return exitCode;
 +      } // user canceled
 +      
 +      execCommand(input, false, false);
 +    }
 +  }
 +  
 +  /**
 +   * @param in
 +   *          the in to set
 +   */
 +  public void setConsoleInputStream(InputStream in) {
 +    this.in = in;
 +  }
 +  
 +  /**
 +   * @param out
 +   *          the output stream to set
 +   */
 +  public void setConsoleWriter(OutputStream out) {
 +    this.out = out;
 +  }
 +
 +  /**
 +   * Convenience method to create the byte-array to hand to the console
 +   * 
 +   * @param commands
 +   *          An array of commands to run
 +   * @return A byte[] input stream which can be handed to the console.
 +   */
 +  public static ByteArrayInputStream makeCommands(String... commands) {
 +    StringBuilder sb = new StringBuilder(commands.length * 8);
 +    
 +    for (String command : commands) {
 +      sb.append(command).append(NEWLINE);
 +    }
 +    
-     return new 
ByteArrayInputStream(sb.toString().getBytes(StandardCharsets.UTF_8));
++    return new ByteArrayInputStream(sb.toString().getBytes(UTF_8));
 +  }
 +}

Reply via email to