You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@accumulo.apache.org by md...@apache.org on 2014/04/08 02:37:16 UTC
[13/27] Revert "ACCUMULO-1897 Move shell into new package and module"
http://git-wip-us.apache.org/repos/asf/accumulo/blob/b2b985e2/core/src/main/java/org/apache/accumulo/core/util/shell/ShellOptionsJC.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/accumulo/core/util/shell/ShellOptionsJC.java b/core/src/main/java/org/apache/accumulo/core/util/shell/ShellOptionsJC.java
new file mode 100644
index 0000000..38692a0
--- /dev/null
+++ b/core/src/main/java/org/apache/accumulo/core/util/shell/ShellOptionsJC.java
@@ -0,0 +1,280 @@
+/*
+ * 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.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Scanner;
+import java.util.TreeMap;
+
+import org.apache.accumulo.core.client.ClientConfiguration;
+import org.apache.accumulo.core.client.ClientConfiguration.ClientProperty;
+import org.apache.accumulo.core.client.security.tokens.AuthenticationToken;
+import org.apache.commons.configuration.ConfigurationException;
+import org.apache.commons.configuration.PropertiesConfiguration;
+import org.apache.log4j.Logger;
+
+import com.beust.jcommander.DynamicParameter;
+import com.beust.jcommander.IStringConverter;
+import com.beust.jcommander.Parameter;
+import com.beust.jcommander.ParameterException;
+import com.beust.jcommander.converters.FileConverter;
+
+public class ShellOptionsJC {
+ // Use the Shell logger because this is really just an extension.
+ public static final Logger log = Logger.getLogger(Shell.class);
+
+ @Parameter(names = {"-u", "--user"}, description = "username (defaults to your OS user)")
+ private String username = System.getProperty("user.name", "root");
+
+ public static class PasswordConverter implements IStringConverter<String> {
+ public static final String STDIN = "stdin";
+
+ private enum KeyType {
+ PASS("pass:"), ENV("env:") {
+ @Override
+ String process(String value) {
+ return System.getenv(value);
+ }
+ },
+ FILE("file:") {
+ @Override
+ String process(String value) {
+ Scanner scanner = null;
+ try {
+ scanner = new Scanner(new File(value));
+ return scanner.nextLine();
+ } catch (FileNotFoundException e) {
+ throw new ParameterException(e);
+ } finally {
+ if (scanner != null) {
+ scanner.close();
+ }
+ }
+ }
+ },
+ STDIN(PasswordConverter.STDIN) {
+ @Override
+ public boolean matches(String value) {
+ return prefix.equals(value);
+ }
+
+ @Override
+ public String convert(String value) {
+ // Will check for this later
+ return prefix;
+ }
+ };
+
+ String prefix;
+
+ private KeyType(String prefix) {
+ this.prefix = prefix;
+ }
+
+ public boolean matches(String value) {
+ return value.startsWith(prefix);
+ }
+
+ public String convert(String value) {
+ return process(value.substring(prefix.length()));
+ }
+
+ String process(String value) {
+ return value;
+ }
+ };
+
+ @Override
+ public String convert(String value) {
+ for (KeyType keyType : KeyType.values()) {
+ if (keyType.matches(value)) {
+ return keyType.convert(value);
+ }
+ }
+
+ return value;
+ }
+ }
+
+ // Note: Don't use "password = true" because then it will prompt even if we have a token
+ @Parameter(names = {"-p", "--password"}, description = "password (can be specified as 'pass:<password>', 'file:<local file containing the password>', "
+ + "'env:<variable containing the pass>', or stdin)", converter = PasswordConverter.class)
+ private String password;
+
+ public static class TokenConverter implements IStringConverter<AuthenticationToken> {
+ @Override
+ public AuthenticationToken convert(String value) {
+ try {
+ return Class.forName(value).asSubclass(AuthenticationToken.class).newInstance();
+ } catch (Exception e) {
+ // Catching ClassNotFoundException, ClassCastException, InstantiationException and IllegalAccessException
+ throw new ParameterException(e);
+ }
+ }
+ }
+
+ @Parameter(names = {"-tc", "--tokenClass"}, description = "token type to create, use the -l to pass options", converter = TokenConverter.class)
+ private AuthenticationToken authenticationToken;
+
+ @DynamicParameter(names = {"-l", "--tokenProperty"}, description = "login properties in the format key=value. Reuse -l for each property")
+ private Map<String,String> tokenProperties = new TreeMap<String,String>();
+
+ @Parameter(names = "--disable-tab-completion", description = "disables tab completion (for less overhead when scripting)")
+ private boolean tabCompletionDisabled;
+
+ @Parameter(names = "--debug", description = "enables client debugging")
+ private boolean debugEnabled;
+
+ @Parameter(names = "--fake", description = "fake a connection to accumulo")
+ private boolean fake;
+
+ @Parameter(names = {"-?", "--help"}, help = true, description = "display this help")
+ private boolean helpEnabled;
+
+ @Parameter(names = {"-e", "--execute-command"}, description = "executes a command, and then exits")
+ private String execCommand;
+
+ @Parameter(names = {"-f", "--execute-file"}, description = "executes commands from a file at startup", converter = FileConverter.class)
+ private File execFile;
+
+ @Parameter(names = {"-fv", "--execute-file-verbose"}, description = "executes commands from a file at startup, with commands shown",
+ converter = FileConverter.class)
+ private File execFileVerbose;
+
+ @Parameter(names = {"-h", "--hdfsZooInstance"}, description = "use hdfs zoo instance")
+ private boolean hdfsZooInstance;
+
+ @Parameter(names = {"-z", "--zooKeeperInstance"}, description = "use a zookeeper instance with the given instance name and list of zoo hosts", arity = 2)
+ private List<String> zooKeeperInstance = new ArrayList<String>();
+
+ @Parameter(names = {"--ssl"}, description = "use ssl to connect to accumulo")
+ private boolean useSsl = false;
+
+ @Parameter(
+ names = "--config-file",
+ description = "read the given client config file. If omitted, the path searched can be specified with $ACCUMULO_CLIENT_CONF_PATH, which defaults to ~/.accumulo/config:$ACCUMULO_CONF_DIR/client.conf:/etc/accumulo/client.conf")
+ private String clientConfigFile = null;
+
+ @Parameter(names = {"-zi", "--zooKeeperInstanceName"}, description = "use a zookeeper instance with the given instance name")
+ private String zooKeeperInstanceName;
+
+ @Parameter(names = {"-zh", "--zooKeeperHosts"}, description = "use a zookeeper instance with the given list of zoo hosts")
+ private String zooKeeperHosts;
+
+ @Parameter(names = "--auth-timeout", description = "minutes the shell can be idle without re-entering a password")
+ private int authTimeout = 60; // TODO Add validator for positive number
+
+ @Parameter(names = "--disable-auth-timeout", description = "disables requiring the user to re-type a password after being idle")
+ private boolean authTimeoutDisabled;
+
+ @Parameter(hidden = true)
+ private List<String> unrecognizedOptions;
+
+ public String getUsername() {
+ return username;
+ }
+
+ public String getPassword() {
+ return password;
+ }
+
+ public AuthenticationToken getAuthenticationToken() {
+ return authenticationToken;
+ }
+
+ public Map<String,String> getTokenProperties() {
+ return tokenProperties;
+ }
+
+ public boolean isTabCompletionDisabled() {
+ return tabCompletionDisabled;
+ }
+
+ public boolean isDebugEnabled() {
+ return debugEnabled;
+ }
+
+ public boolean isFake() {
+ return fake;
+ }
+
+ public boolean isHelpEnabled() {
+ return helpEnabled;
+ }
+
+ public String getExecCommand() {
+ return execCommand;
+ }
+
+ public File getExecFile() {
+ return execFile;
+ }
+
+ public File getExecFileVerbose() {
+ return execFileVerbose;
+ }
+
+ public boolean isHdfsZooInstance() {
+ return hdfsZooInstance;
+ }
+
+ public List<String> getZooKeeperInstance() {
+ return zooKeeperInstance;
+ }
+
+ public String getZooKeeperInstanceName() {
+ return zooKeeperInstanceName;
+ }
+
+ public String getZooKeeperHosts() {
+ return zooKeeperHosts;
+ }
+
+ public int getAuthTimeout() {
+ return authTimeout;
+ }
+
+ public boolean isAuthTimeoutDisabled() {
+ return authTimeoutDisabled;
+ }
+
+ public List<String> getUnrecognizedOptions() {
+ return unrecognizedOptions;
+ }
+
+ public boolean useSsl() {
+ return useSsl;
+ }
+
+ public String getClientConfigFile() {
+ return clientConfigFile;
+ }
+
+ public ClientConfiguration getClientConfiguration() throws ConfigurationException, FileNotFoundException {
+ ClientConfiguration clientConfig = clientConfigFile == null ? ClientConfiguration.loadDefault() : new ClientConfiguration(new PropertiesConfiguration(
+ getClientConfigFile()));
+ if (useSsl()) {
+ clientConfig.setProperty(ClientProperty.INSTANCE_RPC_SSL_ENABLED, "true");
+ }
+ return clientConfig;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/accumulo/blob/b2b985e2/core/src/main/java/org/apache/accumulo/core/util/shell/ShellUtil.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/accumulo/core/util/shell/ShellUtil.java b/core/src/main/java/org/apache/accumulo/core/util/shell/ShellUtil.java
new file mode 100644
index 0000000..f0dd505
--- /dev/null
+++ b/core/src/main/java/org/apache/accumulo/core/util/shell/ShellUtil.java
@@ -0,0 +1,60 @@
+/*
+ * 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.nio.charset.StandardCharsets;
+import java.util.List;
+import java.util.Scanner;
+
+import org.apache.commons.codec.binary.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());
+ 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));
+ }
+ }
+ } finally {
+ file.close();
+ }
+ return result;
+ }
+}
http://git-wip-us.apache.org/repos/asf/accumulo/blob/b2b985e2/core/src/main/java/org/apache/accumulo/core/util/shell/Token.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/accumulo/core/util/shell/Token.java b/core/src/main/java/org/apache/accumulo/core/util/shell/Token.java
new file mode 100644
index 0000000..b6c5869
--- /dev/null
+++ b/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/b2b985e2/core/src/main/java/org/apache/accumulo/core/util/shell/commands/AboutCommand.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/accumulo/core/util/shell/commands/AboutCommand.java b/core/src/main/java/org/apache/accumulo/core/util/shell/commands/AboutCommand.java
new file mode 100644
index 0000000..a0a73e4
--- /dev/null
+++ b/core/src/main/java/org/apache/accumulo/core/util/shell/commands/AboutCommand.java
@@ -0,0 +1,56 @@
+/*
+ * 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(final String fullCommand, final CommandLine cl, final 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() {
+ final 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/b2b985e2/core/src/main/java/org/apache/accumulo/core/util/shell/commands/ActiveCompactionIterator.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/accumulo/core/util/shell/commands/ActiveCompactionIterator.java b/core/src/main/java/org/apache/accumulo/core/util/shell/commands/ActiveCompactionIterator.java
new file mode 100644
index 0000000..bd7d9b2
--- /dev/null
+++ b/core/src/main/java/org/apache/accumulo/core/util/shell/commands/ActiveCompactionIterator.java
@@ -0,0 +1,136 @@
+/*
+ * 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.Comparator;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.accumulo.core.client.IteratorSetting;
+import org.apache.accumulo.core.client.admin.ActiveCompaction;
+import org.apache.accumulo.core.client.admin.InstanceOperations;
+import org.apache.accumulo.core.util.Duration;
+
+class ActiveCompactionIterator implements Iterator<String> {
+
+ private InstanceOperations instanceOps;
+ private Iterator<String> tsIter;
+ private Iterator<String> compactionIter;
+
+ private static String maxDecimal(double count) {
+ if (count < 9.995)
+ return String.format("%.2f", count);
+ if (count < 99.95)
+ return String.format("%.1f", count);
+ return String.format("%.0f", count);
+ }
+
+ private static String shortenCount(long count) {
+ if (count < 1000)
+ return count + "";
+ if (count < 1000000)
+ return maxDecimal(count / 1000.0) + "K";
+ if (count < 1000000000)
+ return maxDecimal(count / 1000000.0) + "M";
+ return maxDecimal(count / 1000000000.0) + "B";
+ }
+
+ private void readNext() {
+ final List<String> compactions = new ArrayList<String>();
+
+ while (tsIter.hasNext()) {
+
+ final String tserver = tsIter.next();
+ try {
+ List<ActiveCompaction> acl = instanceOps.getActiveCompactions(tserver);
+
+ acl = new ArrayList<ActiveCompaction>(acl);
+
+ Collections.sort(acl, new Comparator<ActiveCompaction>() {
+ @Override
+ public int compare(ActiveCompaction o1, ActiveCompaction o2) {
+ return (int) (o2.getAge() - o1.getAge());
+ }
+ });
+
+ for (ActiveCompaction ac : acl) {
+ String output = ac.getOutputFile();
+ int index = output.indexOf("tables");
+ if (index > 0) {
+ output = output.substring(index + 6);
+ }
+
+ ac.getIterators();
+
+ List<String> iterList = new ArrayList<String>();
+ Map<String,Map<String,String>> iterOpts = new HashMap<String,Map<String,String>>();
+ for (IteratorSetting is : ac.getIterators()) {
+ iterList.add(is.getName() + "=" + is.getPriority() + "," + is.getIteratorClass());
+ iterOpts.put(is.getName(), is.getOptions());
+ }
+
+ compactions.add(String.format("%21s | %9s | %5s | %6s | %5s | %5s | %15s | %-40s | %5s | %35s | %9s | %s", tserver,
+ Duration.format(ac.getAge(), "", "-"), ac.getType(), ac.getReason(), shortenCount(ac.getEntriesRead()), shortenCount(ac.getEntriesWritten()),
+ ac.getTable(), ac.getExtent(), ac.getInputFiles().size(), output, iterList, iterOpts));
+ }
+ } catch (Exception e) {
+ compactions.add(tserver + " ERROR " + e.getMessage());
+ }
+
+ if (compactions.size() > 0) {
+ break;
+ }
+ }
+
+ compactionIter = compactions.iterator();
+ }
+
+ ActiveCompactionIterator(List<String> tservers, InstanceOperations instanceOps) {
+ this.instanceOps = instanceOps;
+ this.tsIter = tservers.iterator();
+
+ final String header = String.format(" %-21s| %-9s | %-5s | %-6s | %-5s | %-5s | %-15s | %-40s | %-5s | %-35s | %-9s | %s", "TABLET SERVER", "AGE", "TYPE",
+ "REASON", "READ", "WROTE", "TABLE", "TABLET", "INPUT", "OUTPUT", "ITERATORS", "ITERATOR OPTIONS");
+
+ compactionIter = Collections.singletonList(header).iterator();
+ }
+
+ @Override
+ public boolean hasNext() {
+ return compactionIter.hasNext();
+ }
+
+ @Override
+ public String next() {
+ final String next = compactionIter.next();
+
+ if (!compactionIter.hasNext())
+ readNext();
+
+ return next;
+ }
+
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/accumulo/blob/b2b985e2/core/src/main/java/org/apache/accumulo/core/util/shell/commands/ActiveScanIterator.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/accumulo/core/util/shell/commands/ActiveScanIterator.java b/core/src/main/java/org/apache/accumulo/core/util/shell/commands/ActiveScanIterator.java
new file mode 100644
index 0000000..f1e736f
--- /dev/null
+++ b/core/src/main/java/org/apache/accumulo/core/util/shell/commands/ActiveScanIterator.java
@@ -0,0 +1,91 @@
+/*
+ * 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() {
+ final List<String> scans = new ArrayList<String>();
+
+ while (tsIter.hasNext()) {
+
+ final String tserver = tsIter.next();
+ try {
+ final List<ActiveScan> asl = instanceOps.getActiveScans(tserver);
+
+ for (ActiveScan as : asl) {
+ scans.add(String.format("%21s |%21s |%9s |%9s |%7s |%6s |%8s |%8s |%10s |%20s |%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.getAuthorizations(), (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();
+
+ final String header = String.format(" %-21s| %-21s| %-9s| %-9s| %-7s| %-6s| %-8s| %-8s| %-10s| %-20s| %-10s| %-10s | %s", "TABLET SERVER", "CLIENT", "AGE",
+ "LAST", "STATE", "TYPE", "USER", "TABLE", "COLUMNS", "AUTHORIZATIONS", "TABLET", "ITERATORS", "ITERATOR OPTIONS");
+
+ scansIter = Collections.singletonList(header).iterator();
+ }
+
+ @Override
+ public boolean hasNext() {
+ return scansIter.hasNext();
+ }
+
+ @Override
+ public String next() {
+ final 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/b2b985e2/core/src/main/java/org/apache/accumulo/core/util/shell/commands/AddAuthsCommand.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/accumulo/core/util/shell/commands/AddAuthsCommand.java b/core/src/main/java/org/apache/accumulo/core/util/shell/commands/AddAuthsCommand.java
new file mode 100644
index 0000000..bd478de
--- /dev/null
+++ b/core/src/main/java/org/apache/accumulo/core/util/shell/commands/AddAuthsCommand.java
@@ -0,0 +1,82 @@
+/*
+ * 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.Map;
+import java.util.Set;
+
+import org.apache.accumulo.core.client.AccumuloException;
+import org.apache.accumulo.core.client.AccumuloSecurityException;
+import org.apache.accumulo.core.security.Authorizations;
+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.OptionGroup;
+import org.apache.commons.cli.Options;
+
+public class AddAuthsCommand extends Command {
+ private Option userOpt;
+ private Option scanOptAuths;
+
+ @Override
+ public int execute(final String fullCommand, final CommandLine cl, final Shell shellState) throws AccumuloException, AccumuloSecurityException {
+ final String user = cl.getOptionValue(userOpt.getOpt(), shellState.getConnector().whoami());
+ final String scanOpts = cl.getOptionValue(scanOptAuths.getOpt());
+ Authorizations auths = shellState.getConnector().securityOperations().getUserAuthorizations(user);
+ StringBuilder userAuths = new StringBuilder();
+ if (!auths.isEmpty()) {
+ userAuths.append(auths.toString());
+ userAuths.append(",");
+ }
+ userAuths.append(scanOpts);
+ shellState.getConnector().securityOperations().changeUserAuthorizations(user, ScanCommand.parseAuthorizations(userAuths.toString()));
+ Shell.log.debug("Changed record-level authorizations for user " + user);
+ return 0;
+ }
+
+ @Override
+ public String description() {
+ return "adds authorizations to the maximum scan authorizations for a user";
+ }
+
+ @Override
+ public void registerCompletion(final Token root, final Map<Command.CompletionSet,Set<String>> completionSet) {
+ registerCompletionForUsers(root, completionSet);
+ }
+
+ @Override
+ public Options getOptions() {
+ final Options o = new Options();
+ final OptionGroup setOrClear = new OptionGroup();
+ scanOptAuths = new Option("s", "scan-authorizations", true, "scan authorizations to set");
+ scanOptAuths.setArgName("comma-separated-authorizations");
+ setOrClear.addOption(scanOptAuths);
+ setOrClear.setRequired(true);
+ o.addOptionGroup(setOrClear);
+ userOpt = new Option(Shell.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/b2b985e2/core/src/main/java/org/apache/accumulo/core/util/shell/commands/AddSplitsCommand.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/accumulo/core/util/shell/commands/AddSplitsCommand.java b/core/src/main/java/org/apache/accumulo/core/util/shell/commands/AddSplitsCommand.java
new file mode 100644
index 0000000..b8ba621
--- /dev/null
+++ b/core/src/main/java/org/apache/accumulo/core/util/shell/commands/AddSplitsCommand.java
@@ -0,0 +1,88 @@
+/*
+ * 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.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.accumulo.core.util.shell.ShellUtil;
+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.hadoop.io.Text;
+
+public class AddSplitsCommand extends Command {
+ private Option optSplitsFile, base64Opt;
+
+ public int execute(final String fullCommand, final CommandLine cl, final Shell shellState) throws Exception {
+ final String tableName = OptUtil.getTableOpt(cl, shellState);
+ final boolean decode = cl.hasOption(base64Opt.getOpt());
+
+ final TreeSet<Text> splits = new TreeSet<Text>();
+
+ if (cl.hasOption(optSplitsFile.getOpt())) {
+ splits.addAll(ShellUtil.scanFile(cl.getOptionValue(optSplitsFile.getOpt()), decode));
+ } 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() {
+ final 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/b2b985e2/core/src/main/java/org/apache/accumulo/core/util/shell/commands/AuthenticateCommand.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/accumulo/core/util/shell/commands/AuthenticateCommand.java b/core/src/main/java/org/apache/accumulo/core/util/shell/commands/AuthenticateCommand.java
new file mode 100644
index 0000000..8ebdae8
--- /dev/null
+++ b/core/src/main/java/org/apache/accumulo/core/util/shell/commands/AuthenticateCommand.java
@@ -0,0 +1,66 @@
+/*
+ * 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.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.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(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 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/b2b985e2/core/src/main/java/org/apache/accumulo/core/util/shell/commands/ByeCommand.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/accumulo/core/util/shell/commands/ByeCommand.java b/core/src/main/java/org/apache/accumulo/core/util/shell/commands/ByeCommand.java
new file mode 100644
index 0000000..f0c9d24
--- /dev/null
+++ b/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/b2b985e2/core/src/main/java/org/apache/accumulo/core/util/shell/commands/ClasspathCommand.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/accumulo/core/util/shell/commands/ClasspathCommand.java b/core/src/main/java/org/apache/accumulo/core/util/shell/commands/ClasspathCommand.java
new file mode 100644
index 0000000..b2fe300
--- /dev/null
+++ b/core/src/main/java/org/apache/accumulo/core/util/shell/commands/ClasspathCommand.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 jline.console.ConsoleReader;
+
+import org.apache.accumulo.core.util.shell.Shell;
+import org.apache.accumulo.core.util.shell.Shell.Command;
+import org.apache.accumulo.start.classloader.vfs.AccumuloVFSClassLoader;
+import org.apache.accumulo.start.classloader.vfs.AccumuloVFSClassLoader.Printer;
+import org.apache.commons.cli.CommandLine;
+
+public class ClasspathCommand extends Command {
+ @Override
+ public int execute(final String fullCommand, final CommandLine cl, final Shell shellState) {
+ final ConsoleReader reader = shellState.getReader();
+ AccumuloVFSClassLoader.printClassPath(new Printer() {
+ @Override
+ public void print(String s) {
+ try {
+ reader.println(s);
+ } catch (IOException ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+ });
+ 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/b2b985e2/core/src/main/java/org/apache/accumulo/core/util/shell/commands/ClearCommand.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/accumulo/core/util/shell/commands/ClearCommand.java b/core/src/main/java/org/apache/accumulo/core/util/shell/commands/ClearCommand.java
new file mode 100644
index 0000000..4f15650
--- /dev/null
+++ b/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(final String fullCommand, final CommandLine cl, final 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().print(((char) 27) + "[2J");
+ shellState.getReader().flush();
+
+ // then send the ANSI code to go to position 1,1
+ shellState.getReader().print(((char) 27) + "[1;1H");
+ shellState.getReader().flush();
+
+ return 0;
+ }
+
+ @Override
+ public int numArgs() {
+ return 0;
+ }
+}
http://git-wip-us.apache.org/repos/asf/accumulo/blob/b2b985e2/core/src/main/java/org/apache/accumulo/core/util/shell/commands/CloneTableCommand.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/accumulo/core/util/shell/commands/CloneTableCommand.java b/core/src/main/java/org/apache/accumulo/core/util/shell/commands/CloneTableCommand.java
new file mode 100644
index 0000000..207e530
--- /dev/null
+++ b/core/src/main/java/org/apache/accumulo/core/util/shell/commands/CloneTableCommand.java
@@ -0,0 +1,102 @@
+/*
+ * 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(final String fullCommand, final CommandLine cl, final Shell shellState) throws AccumuloException, AccumuloSecurityException, TableNotFoundException,
+ TableExistsException {
+
+ final HashMap<String,String> props = new HashMap<String,String>();
+ final 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(final Token root, final Map<Command.CompletionSet,Set<String>> completionSet) {
+ registerCompletionForTables(root, completionSet);
+ }
+
+ @Override
+ public Options getOptions() {
+ final 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/b2b985e2/core/src/main/java/org/apache/accumulo/core/util/shell/commands/ClsCommand.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/accumulo/core/util/shell/commands/ClsCommand.java b/core/src/main/java/org/apache/accumulo/core/util/shell/commands/ClsCommand.java
new file mode 100644
index 0000000..cef6098
--- /dev/null
+++ b/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/b2b985e2/core/src/main/java/org/apache/accumulo/core/util/shell/commands/CompactCommand.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/accumulo/core/util/shell/commands/CompactCommand.java b/core/src/main/java/org/apache/accumulo/core/util/shell/commands/CompactCommand.java
new file mode 100644
index 0000000..55e9395
--- /dev/null
+++ b/core/src/main/java/org/apache/accumulo/core/util/shell/commands/CompactCommand.java
@@ -0,0 +1,129 @@
+/*
+ * 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.List;
+
+import org.apache.accumulo.core.client.AccumuloException;
+import org.apache.accumulo.core.client.AccumuloSecurityException;
+import org.apache.accumulo.core.client.IteratorSetting;
+import org.apache.accumulo.core.client.TableNotFoundException;
+import org.apache.accumulo.core.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, profileOpt, cancelOpt;
+ private boolean flush;
+ private Text startRow;
+ private Text endRow;
+ private List<IteratorSetting> iterators;
+
+ boolean override = false;
+ private boolean wait;
+
+ private boolean cancel = false;
+
+ @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(final Shell shellState, final String tableName) throws AccumuloException, AccumuloSecurityException {
+ // compact the tables
+
+ if (cancel) {
+ try {
+ shellState.getConnector().tableOperations().cancelCompaction(tableName);
+ Shell.log.info("Compaction canceled for table " + tableName);
+ } catch (TableNotFoundException e) {
+ throw new AccumuloException(e);
+ }
+ } else {
+ try {
+ if (wait) {
+ Shell.log.info("Compacting table ...");
+ }
+
+ shellState.getConnector().tableOperations().compact(tableName, startRow, endRow, iterators, 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(final String fullCommand, final CommandLine cl, final Shell shellState) throws Exception {
+
+ if (cl.hasOption(cancelOpt.getLongOpt())) {
+ cancel = true;
+
+ if (cl.getOptions().length > 2) {
+ throw new IllegalArgumentException("Can not specify other options with cancel");
+ }
+ } else {
+ cancel = false;
+ }
+
+ flush = !cl.hasOption(noFlushOption.getOpt());
+ startRow = OptUtil.getStartRow(cl);
+ endRow = OptUtil.getEndRow(cl);
+ wait = cl.hasOption(waitOpt.getOpt());
+
+ if (cl.hasOption(profileOpt.getOpt())) {
+ List<IteratorSetting> iterators = shellState.iteratorProfiles.get(cl.getOptionValue(profileOpt.getOpt()));
+ if (iterators == null) {
+ Shell.log.error("Profile " + cl.getOptionValue(profileOpt.getOpt()) + " does not exist");
+ return -1;
+ }
+
+ this.iterators = new ArrayList<IteratorSetting>(iterators);
+ } else {
+ this.iterators = Collections.emptyList();
+ }
+
+
+ return super.execute(fullCommand, cl, shellState);
+ }
+
+ @Override
+ public Options getOptions() {
+ final Options opts = super.getOptions();
+
+ opts.addOption(OptUtil.startRowOpt());
+ opts.addOption(OptUtil.endRowOpt());
+ noFlushOption = new Option("nf", "noFlush", false, "do not flush table data in memory before compacting.");
+ opts.addOption(noFlushOption);
+ waitOpt = new Option("w", "wait", false, "wait for compact to finish");
+ opts.addOption(waitOpt);
+
+ profileOpt = new Option("pn", "profile", true, "iterator profile name");
+ profileOpt.setArgName("profile");
+ opts.addOption(profileOpt);
+
+ cancelOpt = new Option(null, "cancel", false, "cancel user initiated compactions");
+ opts.addOption(cancelOpt);
+
+ return opts;
+ }
+}
http://git-wip-us.apache.org/repos/asf/accumulo/blob/b2b985e2/core/src/main/java/org/apache/accumulo/core/util/shell/commands/ConfigCommand.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/accumulo/core/util/shell/commands/ConfigCommand.java b/core/src/main/java/org/apache/accumulo/core/util/shell/commands/ConfigCommand.java
new file mode 100644
index 0000000..c76a51f
--- /dev/null
+++ b/core/src/main/java/org/apache/accumulo/core/util/shell/commands/ConfigCommand.java
@@ -0,0 +1,315 @@
+/*
+ * 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.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.TreeMap;
+
+import jline.console.ConsoleReader;
+
+import org.apache.accumulo.core.client.AccumuloException;
+import org.apache.accumulo.core.client.AccumuloSecurityException;
+import org.apache.accumulo.core.client.NamespaceNotFoundException;
+import org.apache.accumulo.core.client.TableNotFoundException;
+import org.apache.accumulo.core.client.impl.Namespaces;
+import org.apache.accumulo.core.client.impl.Tables;
+import org.apache.accumulo.core.conf.AccumuloConfiguration;
+import org.apache.accumulo.core.conf.Property;
+import org.apache.accumulo.core.security.ColumnVisibility;
+import org.apache.accumulo.core.util.BadArgumentException;
+import org.apache.accumulo.core.util.shell.Shell;
+import org.apache.accumulo.core.util.shell.Shell.Command;
+import org.apache.accumulo.core.util.shell.Shell.PrintFile;
+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.OptionGroup;
+import org.apache.commons.cli.Options;
+
+public class ConfigCommand extends Command {
+ private Option tableOpt, deleteOpt, setOpt, filterOpt, disablePaginationOpt, outputFileOpt, namespaceOpt;
+
+ private int COL1 = 10, COL2 = 7;
+ private ConsoleReader reader;
+
+ @Override
+ public void registerCompletion(final Token root, final Map<Command.CompletionSet,Set<String>> completionSet) {
+ final Token cmd = new Token(getName());
+ final Token sub = new Token("-" + setOpt.getOpt());
+ for (Property p : Property.values()) {
+ if (!(p.getKey().endsWith(".")) && !p.isExperimental()) {
+ sub.addSubcommand(new Token(p.toString()));
+ }
+ }
+ cmd.addSubcommand(sub);
+ root.addSubcommand(cmd);
+ }
+
+ @Override
+ public int execute(final String fullCommand, final CommandLine cl, final Shell shellState) throws AccumuloException, AccumuloSecurityException,
+ TableNotFoundException, IOException, ClassNotFoundException, NamespaceNotFoundException {
+ reader = shellState.getReader();
+
+ final String tableName = cl.getOptionValue(tableOpt.getOpt());
+ if (tableName != null && !shellState.getConnector().tableOperations().exists(tableName)) {
+ throw new TableNotFoundException(null, tableName, null);
+ }
+ final String namespace = cl.getOptionValue(namespaceOpt.getOpt());
+ if (namespace != null && !shellState.getConnector().namespaceOperations().exists(namespace)) {
+ throw new NamespaceNotFoundException(null, namespace, null);
+ }
+ if (cl.hasOption(deleteOpt.getOpt())) {
+ // delete property from table
+ String property = cl.getOptionValue(deleteOpt.getOpt());
+ if (property.contains("=")) {
+ throw new BadArgumentException("Invalid '=' operator in delete operation.", fullCommand, fullCommand.indexOf('='));
+ }
+ if (tableName != null) {
+ if (!Property.isValidTablePropertyKey(property)) {
+ Shell.log.warn("Invalid per-table property : " + property + ", still removing from zookeeper if it's there.");
+ }
+ shellState.getConnector().tableOperations().removeProperty(tableName, property);
+ Shell.log.debug("Successfully deleted table configuration option.");
+ } else if (namespace != null) {
+ if (!Property.isValidTablePropertyKey(property)) {
+ Shell.log.warn("Invalid per-table property : " + property + ", still removing from zookeeper if it's there.");
+ }
+ shellState.getConnector().namespaceOperations().removeProperty(namespace, property);
+ Shell.log.debug("Successfully deleted namespace configuration option.");
+ } else {
+ if (!Property.isValidZooPropertyKey(property)) {
+ Shell.log.warn("Invalid per-table property : " + property + ", still removing from zookeeper if it's there.");
+ }
+ shellState.getConnector().instanceOperations().removeProperty(property);
+ Shell.log.debug("Successfully deleted system configuration option");
+ }
+ } else if (cl.hasOption(setOpt.getOpt())) {
+ // set property on table
+ String property = cl.getOptionValue(setOpt.getOpt()), value = null;
+ if (!property.contains("=")) {
+ throw new BadArgumentException("Missing '=' operator in set operation.", fullCommand, fullCommand.indexOf(property));
+ }
+ final String pair[] = property.split("=", 2);
+ property = pair[0];
+ value = pair[1];
+
+ if (tableName != null) {
+ if (!Property.isValidTablePropertyKey(property)) {
+ throw new BadArgumentException("Invalid per-table property.", fullCommand, fullCommand.indexOf(property));
+ }
+ if (property.equals(Property.TABLE_DEFAULT_SCANTIME_VISIBILITY.getKey())) {
+ new ColumnVisibility(value); // validate that it is a valid expression
+ }
+ shellState.getConnector().tableOperations().setProperty(tableName, property, value);
+ Shell.log.debug("Successfully set table configuration option.");
+ } else if (namespace != null) {
+ if (!Property.isValidTablePropertyKey(property)) {
+ throw new BadArgumentException("Invalid per-table property.", fullCommand, fullCommand.indexOf(property));
+ }
+ if (property.equals(Property.TABLE_DEFAULT_SCANTIME_VISIBILITY.getKey())) {
+ new ColumnVisibility(value); // validate that it is a valid expression
+ }
+ shellState.getConnector().namespaceOperations().setProperty(namespace, property, value);
+ Shell.log.debug("Successfully set table configuration option.");
+ } else {
+ if (!Property.isValidZooPropertyKey(property)) {
+ throw new BadArgumentException("Property cannot be modified in zookeeper", fullCommand, fullCommand.indexOf(property));
+ }
+ shellState.getConnector().instanceOperations().setProperty(property, value);
+ Shell.log.debug("Successfully set system configuration option");
+ }
+ } else {
+ // display properties
+ final TreeMap<String,String> systemConfig = new TreeMap<String,String>();
+ systemConfig.putAll(shellState.getConnector().instanceOperations().getSystemConfiguration());
+
+ final String outputFile = cl.getOptionValue(outputFileOpt.getOpt());
+ final PrintFile printFile = outputFile == null ? null : new PrintFile(outputFile);
+
+ final TreeMap<String,String> siteConfig = new TreeMap<String,String>();
+ siteConfig.putAll(shellState.getConnector().instanceOperations().getSiteConfiguration());
+
+ final TreeMap<String,String> defaults = new TreeMap<String,String>();
+ for (Entry<String,String> defaultEntry : AccumuloConfiguration.getDefaultConfiguration()) {
+ defaults.put(defaultEntry.getKey(), defaultEntry.getValue());
+ }
+
+ final TreeMap<String,String> namespaceConfig = new TreeMap<String,String>();
+ if (tableName != null) {
+ String n = Namespaces.getNamespaceName(shellState.getInstance(),
+ Tables.getNamespaceId(shellState.getInstance(), Tables.getTableId(shellState.getInstance(), tableName)));
+ for (Entry<String,String> e : shellState.getConnector().namespaceOperations().getProperties(n)) {
+ namespaceConfig.put(e.getKey(), e.getValue());
+ }
+ }
+
+ Iterable<Entry<String,String>> acuconf = shellState.getConnector().instanceOperations().getSystemConfiguration().entrySet();
+ if (tableName != null) {
+ acuconf = shellState.getConnector().tableOperations().getProperties(tableName);
+ } else if (namespace != null) {
+ acuconf = shellState.getConnector().namespaceOperations().getProperties(namespace);
+ }
+ final TreeMap<String,String> sortedConf = new TreeMap<String,String>();
+ for (Entry<String,String> propEntry : acuconf) {
+ sortedConf.put(propEntry.getKey(), propEntry.getValue());
+ }
+
+ for (Entry<String,String> propEntry : acuconf) {
+ final String key = propEntry.getKey();
+ // only show properties with similar names to that
+ // specified, or all of them if none specified
+ if (cl.hasOption(filterOpt.getOpt()) && !key.contains(cl.getOptionValue(filterOpt.getOpt()))) {
+ continue;
+ }
+ if ((tableName != null || namespace != null) && !Property.isValidTablePropertyKey(key)) {
+ continue;
+ }
+ COL2 = Math.max(COL2, propEntry.getKey().length() + 3);
+ }
+
+ final ArrayList<String> output = new ArrayList<String>();
+ printConfHeader(output);
+
+ for (Entry<String,String> propEntry : sortedConf.entrySet()) {
+ final String key = propEntry.getKey();
+
+ // only show properties with similar names to that
+ // specified, or all of them if none specified
+ if (cl.hasOption(filterOpt.getOpt()) && !key.contains(cl.getOptionValue(filterOpt.getOpt()))) {
+ continue;
+ }
+ if ((tableName != null || namespace != null) && !Property.isValidTablePropertyKey(key)) {
+ continue;
+ }
+ String siteVal = siteConfig.get(key);
+ String sysVal = systemConfig.get(key);
+ String curVal = propEntry.getValue();
+ String dfault = defaults.get(key);
+ String nspVal = namespaceConfig.get(key);
+ boolean printed = false;
+
+ if (dfault != null && key.toLowerCase().contains("password")) {
+ siteVal = sysVal = dfault = curVal = curVal.replaceAll(".", "*");
+ }
+ if (sysVal != null) {
+ if (defaults.containsKey(key) && !Property.getPropertyByKey(key).isExperimental()) {
+ printConfLine(output, "default", key, dfault);
+ printed = true;
+ }
+ if (!defaults.containsKey(key) || !defaults.get(key).equals(siteVal)) {
+ printConfLine(output, "site", printed ? " @override" : key, siteVal == null ? "" : siteVal);
+ printed = true;
+ }
+ if (!siteConfig.containsKey(key) || !siteVal.equals(sysVal)) {
+ printConfLine(output, "system", printed ? " @override" : key, sysVal == null ? "" : sysVal);
+ printed = true;
+ }
+
+ }
+ if (nspVal != null) {
+ if (!systemConfig.containsKey(key) || !sysVal.equals(nspVal)) {
+ printConfLine(output, "namespace", printed ? " @override" : key, nspVal == null ? "" : nspVal);
+ printed = true;
+ }
+ }
+
+ // show per-table value only if it is different (overridden)
+ if (tableName != null && !curVal.equals(nspVal)) {
+ printConfLine(output, "table", printed ? " @override" : key, curVal);
+ } else if (namespace != null && !curVal.equals(sysVal)) {
+ printConfLine(output, "namespace", printed ? " @override" : key, curVal);
+ }
+ }
+ printConfFooter(output);
+ shellState.printLines(output.iterator(), !cl.hasOption(disablePaginationOpt.getOpt()), printFile);
+ if (printFile != null) {
+ printFile.close();
+ }
+ }
+ return 0;
+ }
+
+ private void printConfHeader(List<String> output) {
+ printConfFooter(output);
+ output.add(String.format("%-" + COL1 + "s | %-" + COL2 + "s | %s", "SCOPE", "NAME", "VALUE"));
+ printConfFooter(output);
+ }
+
+ private void printConfLine(List<String> output, String s1, String s2, String s3) {
+ if (s2.length() < COL2) {
+ s2 += " " + Shell.repeat(".", COL2 - s2.length() - 1);
+ }
+ output.add(String.format("%-" + COL1 + "s | %-" + COL2 + "s | %s", s1, s2,
+ s3.replace("\n", "\n" + Shell.repeat(" ", COL1 + 1) + "|" + Shell.repeat(" ", COL2 + 2) + "|" + " ")));
+ }
+
+ private void printConfFooter(List<String> output) {
+ int col3 = Math.max(1, Math.min(Integer.MAX_VALUE, reader.getTerminal().getWidth() - COL1 - COL2 - 6));
+ output.add(String.format("%" + COL1 + "s-+-%" + COL2 + "s-+-%-" + col3 + "s", Shell.repeat("-", COL1), Shell.repeat("-", COL2), Shell.repeat("-", col3)));
+ }
+
+ @Override
+ public String description() {
+ return "prints system properties and table specific properties";
+ }
+
+ @Override
+ public Options getOptions() {
+ final Options o = new Options();
+ final OptionGroup og = new OptionGroup();
+ final OptionGroup tgroup = new OptionGroup();
+
+ tableOpt = new Option(Shell.tableOption, "table", true, "table to display/set/delete properties for");
+ deleteOpt = new Option("d", "delete", true, "delete a per-table property");
+ setOpt = new Option("s", "set", true, "set a per-table property");
+ filterOpt = new Option("f", "filter", true, "show only properties that contain this string");
+ disablePaginationOpt = new Option("np", "no-pagination", false, "disables pagination of output");
+ outputFileOpt = new Option("o", "output", true, "local file to write the scan output to");
+ namespaceOpt = new Option(Shell.namespaceOption, "namespace", true, "namespace to display/set/delete properties for");
+
+ tableOpt.setArgName("table");
+ deleteOpt.setArgName("property");
+ setOpt.setArgName("property=value");
+ filterOpt.setArgName("string");
+ outputFileOpt.setArgName("file");
+ namespaceOpt.setArgName("namespace");
+
+ og.addOption(deleteOpt);
+ og.addOption(setOpt);
+ og.addOption(filterOpt);
+
+ tgroup.addOption(tableOpt);
+ tgroup.addOption(namespaceOpt);
+
+ o.addOptionGroup(tgroup);
+ o.addOptionGroup(og);
+ o.addOption(disablePaginationOpt);
+ o.addOption(outputFileOpt);
+
+ return o;
+ }
+
+ @Override
+ public int numArgs() {
+ return 0;
+ }
+}
http://git-wip-us.apache.org/repos/asf/accumulo/blob/b2b985e2/core/src/main/java/org/apache/accumulo/core/util/shell/commands/ConstraintCommand.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/accumulo/core/util/shell/commands/ConstraintCommand.java b/core/src/main/java/org/apache/accumulo/core/util/shell/commands/ConstraintCommand.java
new file mode 100644
index 0000000..208ac4a
--- /dev/null
+++ b/core/src/main/java/org/apache/accumulo/core/util/shell/commands/ConstraintCommand.java
@@ -0,0 +1,134 @@
+/*
+ * 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.Map.Entry;
+
+import org.apache.accumulo.core.constraints.Constraint;
+import org.apache.accumulo.core.util.shell.Shell;
+import org.apache.accumulo.core.util.shell.Shell.Command;
+import org.apache.accumulo.core.util.shell.ShellCommandException;
+import org.apache.accumulo.core.util.shell.ShellCommandException.ErrorCode;
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.Option;
+import org.apache.commons.cli.OptionGroup;
+import org.apache.commons.cli.Options;
+
+public class ConstraintCommand extends Command {
+ protected Option namespaceOpt;
+
+ @Override
+ public int execute(final String fullCommand, final CommandLine cl, final Shell shellState) throws Exception {
+ final String tableName;
+ final String namespace;
+
+ if (cl.hasOption(namespaceOpt.getOpt())) {
+ namespace = cl.getOptionValue(namespaceOpt.getOpt());
+ } else {
+ namespace = null;
+ }
+
+ if (cl.hasOption(OptUtil.tableOpt().getOpt()) || !shellState.getTableName().isEmpty()) {
+ tableName = OptUtil.getTableOpt(cl, shellState);
+ } else {
+ tableName = null;
+ }
+
+ int i;
+ switch (OptUtil.getAldOpt(cl)) {
+ case ADD:
+ for (String constraint : cl.getArgs()) {
+ if (namespace != null) {
+ if (!shellState.getConnector().namespaceOperations().testClassLoad(namespace, constraint, Constraint.class.getName())) {
+ throw new ShellCommandException(ErrorCode.INITIALIZATION_FAILURE, "Servers are unable to load " + constraint + " as type "
+ + Constraint.class.getName());
+ }
+ i = shellState.getConnector().namespaceOperations().addConstraint(namespace, constraint);
+ shellState.getReader().println("Added constraint " + constraint + " to namespace " + namespace + " with number " + i);
+ } else if (tableName != null && !tableName.isEmpty()) {
+ if (!shellState.getConnector().tableOperations().testClassLoad(tableName, constraint, Constraint.class.getName())) {
+ throw new ShellCommandException(ErrorCode.INITIALIZATION_FAILURE, "Servers are unable to load " + constraint + " as type "
+ + Constraint.class.getName());
+ }
+ i = shellState.getConnector().tableOperations().addConstraint(tableName, constraint);
+ shellState.getReader().println("Added constraint " + constraint + " to table " + tableName + " with number " + i);
+ } else {
+ throw new IllegalArgumentException("Please specify either a table or a namespace");
+ }
+ }
+ break;
+ case DELETE:
+ for (String constraint : cl.getArgs()) {
+ i = Integer.parseInt(constraint);
+ if (namespace != null) {
+ shellState.getConnector().namespaceOperations().removeConstraint(namespace, i);
+ shellState.getReader().println("Removed constraint " + i + " from namespace " + namespace);
+ } else if (tableName != null) {
+ shellState.getConnector().tableOperations().removeConstraint(tableName, i);
+ shellState.getReader().println("Removed constraint " + i + " from table " + tableName);
+ } else {
+ throw new IllegalArgumentException("Please specify either a table or a namespace");
+ }
+ }
+ break;
+ case LIST:
+ if (namespace != null) {
+ for (Entry<String,Integer> property : shellState.getConnector().namespaceOperations().listConstraints(namespace).entrySet()) {
+ shellState.getReader().println(property.toString());
+ }
+ } else if (tableName != null) {
+ for (Entry<String,Integer> property : shellState.getConnector().tableOperations().listConstraints(tableName).entrySet()) {
+ shellState.getReader().println(property.toString());
+ }
+ } else {
+ throw new IllegalArgumentException("Please specify either a table or a namespace");
+ }
+ }
+
+ return 0;
+ }
+
+ @Override
+ public String description() {
+ return "adds, deletes, or lists constraints for a table";
+ }
+
+ @Override
+ public int numArgs() {
+ return Shell.NO_FIXED_ARG_LENGTH_CHECK;
+ }
+
+ @Override
+ public String usage() {
+ return getName() + " <constraint>{ <constraint>}";
+ }
+
+ @Override
+ public Options getOptions() {
+ final Options o = new Options();
+ o.addOptionGroup(OptUtil.addListDeleteGroup("constraint"));
+
+ OptionGroup grp = new OptionGroup();
+ grp.addOption(OptUtil.tableOpt("table to add, delete, or list constraints for"));
+ namespaceOpt = new Option(Shell.namespaceOption, "namespace", true, "name of a namespace to operate on");
+ namespaceOpt.setArgName("namespace");
+ grp.addOption(namespaceOpt);
+
+ o.addOptionGroup(grp);
+ return o;
+ }
+}
http://git-wip-us.apache.org/repos/asf/accumulo/blob/b2b985e2/core/src/main/java/org/apache/accumulo/core/util/shell/commands/CreateNamespaceCommand.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/accumulo/core/util/shell/commands/CreateNamespaceCommand.java b/core/src/main/java/org/apache/accumulo/core/util/shell/commands/CreateNamespaceCommand.java
new file mode 100644
index 0000000..a9f3deb
--- /dev/null
+++ b/core/src/main/java/org/apache/accumulo/core/util/shell/commands/CreateNamespaceCommand.java
@@ -0,0 +1,99 @@
+/*
+ * 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.Entry;
+
+import org.apache.accumulo.core.client.AccumuloException;
+import org.apache.accumulo.core.client.AccumuloSecurityException;
+import org.apache.accumulo.core.client.NamespaceExistsException;
+import org.apache.accumulo.core.client.NamespaceNotFoundException;
+import org.apache.accumulo.core.client.TableExistsException;
+import org.apache.accumulo.core.client.TableNotFoundException;
+import org.apache.accumulo.core.conf.Property;
+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.OptionGroup;
+import org.apache.commons.cli.Options;
+
+public class CreateNamespaceCommand extends Command {
+ private Option createNamespaceOptCopyConfig;
+
+ @Override
+ public int execute(final String fullCommand, final CommandLine cl, final Shell shellState) throws AccumuloException, AccumuloSecurityException,
+ TableExistsException, TableNotFoundException, IOException, ClassNotFoundException, NamespaceExistsException, NamespaceNotFoundException {
+
+ if (createNamespaceOptCopyConfig == null) {
+ getOptions();
+ }
+
+ String namespace = cl.getArgs()[0];
+
+ shellState.getConnector().namespaceOperations().create(namespace);
+
+ // Copy options if flag was set
+ Iterable<Entry<String,String>> configuration = null;
+ if (cl.hasOption(createNamespaceOptCopyConfig.getOpt())) {
+ String copy = cl.getOptionValue(createNamespaceOptCopyConfig.getOpt());
+ if (shellState.getConnector().namespaceOperations().exists(namespace)) {
+ configuration = shellState.getConnector().namespaceOperations().getProperties(copy);
+ }
+ }
+ if (configuration != null) {
+ for (Entry<String,String> entry : configuration) {
+ if (Property.isValidTablePropertyKey(entry.getKey())) {
+ shellState.getConnector().namespaceOperations().setProperty(namespace, entry.getKey(), entry.getValue());
+ }
+ }
+ }
+
+ return 0;
+ }
+
+ @Override
+ public String description() {
+ return "creates a new namespace";
+ }
+
+ @Override
+ public String usage() {
+ return getName() + " <namespaceName>";
+ }
+
+ @Override
+ public Options getOptions() {
+ final Options o = new Options();
+
+ createNamespaceOptCopyConfig = new Option("cc", "copy-config", true, "namespace to copy configuration from");
+ createNamespaceOptCopyConfig.setArgName("namespace");
+
+ OptionGroup ogp = new OptionGroup();
+ ogp.addOption(createNamespaceOptCopyConfig);
+
+ o.addOptionGroup(ogp);
+
+ return o;
+ }
+
+ @Override
+ public int numArgs() {
+ return 1;
+ }
+}