Merge branch '1.6' into 1.7
Project: http://git-wip-us.apache.org/repos/asf/accumulo/repo Commit: http://git-wip-us.apache.org/repos/asf/accumulo/commit/4678cf92 Tree: http://git-wip-us.apache.org/repos/asf/accumulo/tree/4678cf92 Diff: http://git-wip-us.apache.org/repos/asf/accumulo/diff/4678cf92 Branch: refs/heads/1.7 Commit: 4678cf928a623467cd7cf678bb43b7f92967943d Parents: 09ddfd4 eb0f9b4 Author: Christopher Tubbs <ctubb...@apache.org> Authored: Fri Feb 19 21:45:39 2016 -0500 Committer: Christopher Tubbs <ctubb...@apache.org> Committed: Fri Feb 19 21:45:39 2016 -0500 ---------------------------------------------------------------------- .../core/client/admin/TableOperations.java | 4 +-- .../shell/commands/DeleteRowsCommand.java | 4 +-- .../accumulo/shell/commands/MergeCommand.java | 4 +-- .../apache/accumulo/shell/commands/OptUtil.java | 2 +- .../accumulo/shell/commands/ScanCommand.java | 5 +++- .../shell/commands/CompactCommandTest.java | 29 ++++++++++++++++++++ .../shell/commands/DeleteManyCommandTest.java | 29 ++++++++++++++++++++ .../shell/commands/DeleteRowsCommandTest.java | 29 ++++++++++++++++++++ .../shell/commands/FlushCommandTest.java | 29 ++++++++++++++++++++ .../shell/commands/MergeCommandTest.java | 29 ++++++++++++++++++++ .../shell/commands/ScanCommandTest.java | 29 ++++++++++++++++++++ 11 files changed, 183 insertions(+), 10 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/accumulo/blob/4678cf92/core/src/main/java/org/apache/accumulo/core/client/admin/TableOperations.java ---------------------------------------------------------------------- diff --cc core/src/main/java/org/apache/accumulo/core/client/admin/TableOperations.java index 2e15d26,bcad3a3..45b94a5 --- a/core/src/main/java/org/apache/accumulo/core/client/admin/TableOperations.java +++ b/core/src/main/java/org/apache/accumulo/core/client/admin/TableOperations.java @@@ -297,10 -276,9 +297,10 @@@ public interface TableOperations * @param start * first tablet to be compacted contains the row after this row, null means the first tablet in table * @param end - * last tablet to be merged contains this row, null means the last tablet in table + * last tablet to be compacted contains this row, null means the last tablet in table * @param iterators - * A set of iterators that will be applied to each tablet compacted + * A set of iterators that will be applied to each tablet compacted. If two or more concurrent calls to compact pass iterators, then only one will + * succeed and the others will fail. * @param flush * when true, table memory is flushed before compaction starts * @param wait http://git-wip-us.apache.org/repos/asf/accumulo/blob/4678cf92/shell/src/main/java/org/apache/accumulo/shell/commands/DeleteRowsCommand.java ---------------------------------------------------------------------- diff --cc shell/src/main/java/org/apache/accumulo/shell/commands/DeleteRowsCommand.java index af7eb9a,0000000..527efe6 mode 100644,000000..100644 --- a/shell/src/main/java/org/apache/accumulo/shell/commands/DeleteRowsCommand.java +++ b/shell/src/main/java/org/apache/accumulo/shell/commands/DeleteRowsCommand.java @@@ -1,65 -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 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; +import org.apache.hadoop.io.Text; + +public class DeleteRowsCommand extends Command { + private Option forceOpt; + private Option startRowOptExclusive; + + @Override + public int execute(final String fullCommand, final CommandLine cl, final Shell shellState) throws Exception { + final String tableName = OptUtil.getTableOpt(cl, shellState); + final Text startRow = OptUtil.getStartRow(cl); + final Text endRow = OptUtil.getEndRow(cl); + if (!cl.hasOption(forceOpt.getOpt()) && (startRow == null || endRow == null)) { + shellState.getReader().println("Not deleting unbounded range. Specify both ends, or use --force"); + return 1; + } + shellState.getConnector().tableOperations().deleteRows(tableName, startRow, endRow); + return 0; + } + + @Override + public String description() { + return "deletes a range of rows in a table. Note that rows matching the start row ARE NOT deleted, but rows matching the end row ARE deleted."; + } + + @Override + public int numArgs() { + return 0; + } + + @Override + public Options getOptions() { + final Options o = new Options(); + forceOpt = new Option("f", "force", false, "delete data even if start or end are not specified"); - startRowOptExclusive = new Option(OptUtil.START_ROW_OPT, "begin-row", true, "begin row (exclusive)"); - startRowOptExclusive.setArgName("begin-row"); - o.addOption(startRowOptExclusive); ++ o.addOption(OptUtil.startRowOpt()); + o.addOption(OptUtil.endRowOpt()); + o.addOption(OptUtil.tableOpt("table to delete a row range from")); + o.addOption(forceOpt); + return o; + } +} http://git-wip-us.apache.org/repos/asf/accumulo/blob/4678cf92/shell/src/main/java/org/apache/accumulo/shell/commands/MergeCommand.java ---------------------------------------------------------------------- diff --cc shell/src/main/java/org/apache/accumulo/shell/commands/MergeCommand.java index 90fcace,0000000..0da53c0 mode 100644,000000..100644 --- a/shell/src/main/java/org/apache/accumulo/shell/commands/MergeCommand.java +++ b/shell/src/main/java/org/apache/accumulo/shell/commands/MergeCommand.java @@@ -1,112 -1,0 +1,110 @@@ +/* + * 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 org.apache.accumulo.core.conf.AccumuloConfiguration; +import org.apache.accumulo.core.util.Merge; +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; +import org.apache.hadoop.io.Text; + +public class MergeCommand extends Command { + private Option verboseOpt, forceOpt, sizeOpt, allOpt; + + @Override + public int execute(final String fullCommand, final CommandLine cl, final Shell shellState) throws Exception { + boolean verbose = shellState.isVerbose(); + boolean force = false; + boolean all = false; + long size = -1; + final String tableName = OptUtil.getTableOpt(cl, shellState); + final Text startRow = OptUtil.getStartRow(cl); + final Text endRow = OptUtil.getEndRow(cl); + if (cl.hasOption(verboseOpt.getOpt())) { + verbose = true; + } + if (cl.hasOption(forceOpt.getOpt())) { + force = true; + } + if (cl.hasOption(allOpt.getOpt())) { + all = true; + } + if (cl.hasOption(sizeOpt.getOpt())) { + size = AccumuloConfiguration.getMemoryInBytes(cl.getOptionValue(sizeOpt.getOpt())); + } + if (startRow == null && endRow == null && size < 0 && !all) { + shellState.getReader().flush(); + String line = shellState.getReader().readLine("Merge the entire table { " + tableName + " } into one tablet (yes|no)? "); + if (line == null) + return 0; + if (!line.equalsIgnoreCase("y") && !line.equalsIgnoreCase("yes")) + return 0; + } + if (size < 0) { + shellState.getConnector().tableOperations().merge(tableName, startRow, endRow); + } else { + final boolean finalVerbose = verbose; + final Merge merge = new Merge() { + @Override + protected void message(String fmt, Object... args) { + if (finalVerbose) { + try { + shellState.getReader().println(String.format(fmt, args)); + } catch (IOException ex) { + throw new RuntimeException(ex); + } + } + } + }; + merge.mergomatic(shellState.getConnector(), tableName, startRow, endRow, size, force); + } + return 0; + } + + @Override + public String description() { + return "merges tablets in a table"; + } + + @Override + public int numArgs() { + return 0; + } + + @Override + public Options getOptions() { + final Options o = new Options(); + verboseOpt = new Option("v", "verbose", false, "verbose output during merge"); + sizeOpt = new Option("s", "size", true, "merge tablets to the given size over the entire table"); + forceOpt = new Option("f", "force", false, "merge small tablets to large tablets, even if it goes over the given size"); + allOpt = new Option("", "all", false, "allow an entire table to be merged into one tablet without prompting the user for confirmation"); - Option startRowOpt = OptUtil.startRowOpt(); - startRowOpt.setDescription("begin row (NOT inclusive)"); - o.addOption(startRowOpt); ++ o.addOption(OptUtil.startRowOpt()); + o.addOption(OptUtil.endRowOpt()); + o.addOption(OptUtil.tableOpt("table to be merged")); + o.addOption(verboseOpt); + o.addOption(sizeOpt); + o.addOption(forceOpt); + o.addOption(allOpt); + return o; + } + +} http://git-wip-us.apache.org/repos/asf/accumulo/blob/4678cf92/shell/src/main/java/org/apache/accumulo/shell/commands/OptUtil.java ---------------------------------------------------------------------- diff --cc shell/src/main/java/org/apache/accumulo/shell/commands/OptUtil.java index 16d7220,0000000..eb8833f mode 100644,000000..100644 --- a/shell/src/main/java/org/apache/accumulo/shell/commands/OptUtil.java +++ b/shell/src/main/java/org/apache/accumulo/shell/commands/OptUtil.java @@@ -1,147 -1,0 +1,147 @@@ +/* + * 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.UnsupportedEncodingException; + +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.shell.Shell; +import org.apache.accumulo.shell.ShellOptions; +import org.apache.commons.cli.CommandLine; +import org.apache.commons.cli.Option; +import org.apache.commons.cli.OptionGroup; +import org.apache.hadoop.io.Text; + +public abstract class OptUtil { + public static final String START_ROW_OPT = "b"; + public static final String END_ROW_OPT = "e"; + + public static String getTableOpt(final CommandLine cl, final Shell shellState) throws TableNotFoundException { + String tableName; + + if (cl.hasOption(ShellOptions.tableOption)) { + tableName = cl.getOptionValue(ShellOptions.tableOption); + if (!shellState.getConnector().tableOperations().exists(tableName)) { + throw new TableNotFoundException(tableName, tableName, "specified table that doesn't exist"); + } + } else { + shellState.checkTableState(); + tableName = shellState.getTableName(); + } + + return tableName; + } + + public static String getNamespaceOpt(final CommandLine cl, final Shell shellState) throws NamespaceNotFoundException, AccumuloException, + AccumuloSecurityException { + String namespace = null; + if (cl.hasOption(ShellOptions.namespaceOption)) { + namespace = cl.getOptionValue(ShellOptions.namespaceOption); + if (!shellState.getConnector().namespaceOperations().exists(namespace)) { + throw new NamespaceNotFoundException(namespace, namespace, "specified namespace that doesn't exist"); + } + } else { + throw new NamespaceNotFoundException(null, null, "no namespace specified"); + } + return namespace; + } + + public static Option tableOpt() { + return tableOpt("tableName"); + } + + public static Option tableOpt(final String description) { + final Option tableOpt = new Option(ShellOptions.tableOption, "table", true, description); + tableOpt.setArgName("table"); + tableOpt.setRequired(false); + return tableOpt; + } + + public static Option namespaceOpt() { + return namespaceOpt("namespace"); + } + + public static Option namespaceOpt(final String description) { + final Option namespaceOpt = new Option(ShellOptions.namespaceOption, "namespace", true, description); + namespaceOpt.setArgName("namespace"); + namespaceOpt.setRequired(false); + return namespaceOpt; + } + + public static enum AdlOpt { + ADD("a"), DELETE("d"), LIST("l"); + + public final String opt; + + private AdlOpt(String opt) { + this.opt = opt; + } + } + + public static AdlOpt getAldOpt(final CommandLine cl) { + if (cl.hasOption(AdlOpt.ADD.opt)) { + return AdlOpt.ADD; + } else if (cl.hasOption(AdlOpt.DELETE.opt)) { + return AdlOpt.DELETE; + } else { + return AdlOpt.LIST; + } + } + + public static OptionGroup addListDeleteGroup(final String name) { + final Option addOpt = new Option(AdlOpt.ADD.opt, "add", false, "add " + name); + final Option deleteOpt = new Option(AdlOpt.DELETE.opt, "delete", false, "delete " + name); + final Option listOpt = new Option(AdlOpt.LIST.opt, "list", false, "list " + name + "(s)"); + final OptionGroup og = new OptionGroup(); + og.addOption(addOpt); + og.addOption(deleteOpt); + og.addOption(listOpt); + og.setRequired(true); + return og; + } + + public static Option startRowOpt() { - final Option o = new Option(START_ROW_OPT, "begin-row", true, "begin row (inclusive)"); ++ final Option o = new Option(START_ROW_OPT, "begin-row", true, "begin row (exclusive)"); + o.setArgName("begin-row"); + return o; + } + + public static Option endRowOpt() { + final Option o = new Option(END_ROW_OPT, "end-row", true, "end row (inclusive)"); + o.setArgName("end-row"); + return o; + } + + public static Text getStartRow(final CommandLine cl) throws UnsupportedEncodingException { + if (cl.hasOption(START_ROW_OPT)) { + return new Text(cl.getOptionValue(START_ROW_OPT).getBytes(Shell.CHARSET)); + } else { + return null; + } + } + + public static Text getEndRow(final CommandLine cl) throws UnsupportedEncodingException { + if (cl.hasOption(END_ROW_OPT)) { + return new Text(cl.getOptionValue(END_ROW_OPT).getBytes(Shell.CHARSET)); + } else { + return null; + } + } +} http://git-wip-us.apache.org/repos/asf/accumulo/blob/4678cf92/shell/src/main/java/org/apache/accumulo/shell/commands/ScanCommand.java ---------------------------------------------------------------------- diff --cc shell/src/main/java/org/apache/accumulo/shell/commands/ScanCommand.java index 3531fe9,0000000..6f1ddd3 mode 100644,000000..100644 --- a/shell/src/main/java/org/apache/accumulo/shell/commands/ScanCommand.java +++ b/shell/src/main/java/org/apache/accumulo/shell/commands/ScanCommand.java @@@ -1,340 -1,0 +1,343 @@@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.accumulo.shell.commands; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.util.List; +import java.util.Map.Entry; +import java.util.concurrent.TimeUnit; + +import org.apache.accumulo.core.client.AccumuloException; +import org.apache.accumulo.core.client.AccumuloSecurityException; +import org.apache.accumulo.core.client.IteratorSetting; +import org.apache.accumulo.core.client.Scanner; +import org.apache.accumulo.core.client.ScannerBase; +import org.apache.accumulo.core.client.TableNotFoundException; +import org.apache.accumulo.core.conf.AccumuloConfiguration; +import org.apache.accumulo.core.data.Key; +import org.apache.accumulo.core.data.Range; +import org.apache.accumulo.core.data.Value; +import org.apache.accumulo.core.iterators.SortedKeyValueIterator; +import org.apache.accumulo.core.security.Authorizations; +import org.apache.accumulo.core.util.format.BinaryFormatter; +import org.apache.accumulo.core.util.format.Formatter; +import org.apache.accumulo.core.util.interpret.DefaultScanInterpreter; +import org.apache.accumulo.core.util.interpret.ScanInterpreter; +import org.apache.accumulo.shell.Shell; +import org.apache.accumulo.shell.Shell.Command; +import org.apache.accumulo.shell.Shell.PrintFile; +import org.apache.accumulo.shell.ShellCommandException; +import org.apache.accumulo.shell.ShellCommandException.ErrorCode; +import org.apache.accumulo.start.classloader.vfs.AccumuloVFSClassLoader; +import org.apache.commons.cli.CommandLine; +import org.apache.commons.cli.Option; +import org.apache.commons.cli.Options; +import org.apache.hadoop.io.Text; + +public class ScanCommand extends Command { + + private Option scanOptAuths, scanOptRow, scanOptColumns, disablePaginationOpt, showFewOpt, formatterOpt, interpreterOpt, formatterInterpeterOpt, + outputFileOpt; + + protected Option timestampOpt; + private Option optStartRowExclusive; ++ private Option optStartRowInclusive; + private Option optEndRowExclusive; + private Option timeoutOption; + private Option profileOpt; + + @Override + public int execute(final String fullCommand, final CommandLine cl, final Shell shellState) throws Exception { + final PrintFile printFile = getOutputFile(cl); + final String tableName = OptUtil.getTableOpt(cl, shellState); + + final Class<? extends Formatter> formatter = getFormatter(cl, tableName, shellState); + final ScanInterpreter interpeter = getInterpreter(cl, tableName, shellState); + + // handle first argument, if present, the authorizations list to + // scan with + final Authorizations auths = getAuths(cl, shellState); + final Scanner scanner = shellState.getConnector().createScanner(tableName, auths); + + // handle session-specific scan iterators + addScanIterators(shellState, cl, scanner, tableName); + + // handle remaining optional arguments + scanner.setRange(getRange(cl, interpeter)); + + // handle columns + fetchColumns(cl, scanner, interpeter); + + // set timeout + scanner.setTimeout(getTimeout(cl), TimeUnit.MILLISECONDS); + + // output the records + if (cl.hasOption(showFewOpt.getOpt())) { + final String showLength = cl.getOptionValue(showFewOpt.getOpt()); + try { + final int length = Integer.parseInt(showLength); + if (length < 1) { + throw new IllegalArgumentException(); + } + BinaryFormatter.getlength(length); + printBinaryRecords(cl, shellState, scanner, printFile); + } catch (NumberFormatException nfe) { + shellState.getReader().println("Arg must be an integer."); + } catch (IllegalArgumentException iae) { + shellState.getReader().println("Arg must be greater than one."); + } + + } else { + printRecords(cl, shellState, scanner, formatter, printFile); + } + if (printFile != null) { + printFile.close(); + } + + return 0; + } + + protected long getTimeout(final CommandLine cl) { + if (cl.hasOption(timeoutOption.getLongOpt())) { + return AccumuloConfiguration.getTimeInMillis(cl.getOptionValue(timeoutOption.getLongOpt())); + } + + return Long.MAX_VALUE; + } + + static void ensureTserversCanLoadIterator(final Shell shellState, String tableName, String classname) throws AccumuloException, AccumuloSecurityException, + TableNotFoundException, ShellCommandException { + if (!shellState.getConnector().tableOperations().testClassLoad(tableName, classname, SortedKeyValueIterator.class.getName())) { + throw new ShellCommandException(ErrorCode.INITIALIZATION_FAILURE, "Servers are unable to load " + classname + " as type " + + SortedKeyValueIterator.class.getName()); + } + } + + protected void addScanIterators(final Shell shellState, CommandLine cl, final Scanner scanner, final String tableName) throws Exception { + + List<IteratorSetting> tableScanIterators; + if (cl.hasOption(profileOpt.getOpt())) { + String profile = cl.getOptionValue(profileOpt.getOpt()); + tableScanIterators = shellState.iteratorProfiles.get(profile); + + if (tableScanIterators == null) { + throw new IllegalArgumentException("Profile " + profile + " does not exist"); + } + + for (IteratorSetting iteratorSetting : tableScanIterators) { + ensureTserversCanLoadIterator(shellState, tableName, iteratorSetting.getIteratorClass()); + } + } else { + tableScanIterators = shellState.scanIteratorOptions.get(tableName); + if (tableScanIterators == null) { + Shell.log.debug("Found no scan iterators to set"); + return; + } + } + + Shell.log.debug("Found " + tableScanIterators.size() + " scan iterators to set"); + + for (IteratorSetting setting : tableScanIterators) { + Shell.log.debug("Setting scan iterator " + setting.getName() + " at priority " + setting.getPriority() + " using class name " + + setting.getIteratorClass()); + for (Entry<String,String> option : setting.getOptions().entrySet()) { + Shell.log.debug("Setting option for " + setting.getName() + ": " + option.getKey() + "=" + option.getValue()); + } + scanner.addScanIterator(setting); + } + } + + protected void printRecords(final CommandLine cl, final Shell shellState, final Iterable<Entry<Key,Value>> scanner, + final Class<? extends Formatter> formatter, PrintFile outFile) throws IOException { + if (outFile == null) { + shellState.printRecords(scanner, cl.hasOption(timestampOpt.getOpt()), !cl.hasOption(disablePaginationOpt.getOpt()), formatter); + } else { + shellState.printRecords(scanner, cl.hasOption(timestampOpt.getOpt()), !cl.hasOption(disablePaginationOpt.getOpt()), formatter, outFile); + } + } + + protected void printBinaryRecords(final CommandLine cl, final Shell shellState, final Iterable<Entry<Key,Value>> scanner, PrintFile outFile) + throws IOException { + if (outFile == null) { + shellState.printBinaryRecords(scanner, cl.hasOption(timestampOpt.getOpt()), !cl.hasOption(disablePaginationOpt.getOpt())); + } else { + shellState.printBinaryRecords(scanner, cl.hasOption(timestampOpt.getOpt()), !cl.hasOption(disablePaginationOpt.getOpt()), outFile); + } + } + + protected ScanInterpreter getInterpreter(final CommandLine cl, final String tableName, final Shell shellState) throws Exception { + + Class<? extends ScanInterpreter> clazz = null; + try { + if (cl.hasOption(interpreterOpt.getOpt())) { + clazz = AccumuloVFSClassLoader.loadClass(cl.getOptionValue(interpreterOpt.getOpt()), ScanInterpreter.class); + } else if (cl.hasOption(formatterInterpeterOpt.getOpt())) { + clazz = AccumuloVFSClassLoader.loadClass(cl.getOptionValue(formatterInterpeterOpt.getOpt()), ScanInterpreter.class); + } + } catch (ClassNotFoundException e) { + shellState.getReader().println("Interpreter class could not be loaded.\n" + e.getMessage()); + } + + if (clazz == null) + clazz = InterpreterCommand.getCurrentInterpreter(tableName, shellState); + + if (clazz == null) + clazz = DefaultScanInterpreter.class; + + return clazz.newInstance(); + } + + protected Class<? extends Formatter> getFormatter(final CommandLine cl, final String tableName, final Shell shellState) throws IOException { + + try { + if (cl.hasOption(formatterOpt.getOpt())) { + return shellState.getClassLoader(cl, shellState).loadClass(cl.getOptionValue(formatterOpt.getOpt())).asSubclass(Formatter.class); + } else if (cl.hasOption(formatterInterpeterOpt.getOpt())) { + return shellState.getClassLoader(cl, shellState).loadClass(cl.getOptionValue(formatterInterpeterOpt.getOpt())).asSubclass(Formatter.class); + } + } catch (Exception e) { + shellState.getReader().println("Formatter class could not be loaded.\n" + e.getMessage()); + } + + return shellState.getFormatter(tableName); + } + + protected void fetchColumns(final CommandLine cl, final ScannerBase scanner, final ScanInterpreter formatter) throws UnsupportedEncodingException { + if (cl.hasOption(scanOptColumns.getOpt())) { + for (String a : cl.getOptionValue(scanOptColumns.getOpt()).split(",")) { + final String sa[] = a.split(":", 2); + if (sa.length == 1) { + scanner.fetchColumnFamily(formatter.interpretColumnFamily(new Text(a.getBytes(Shell.CHARSET)))); + } else { + scanner.fetchColumn(formatter.interpretColumnFamily(new Text(sa[0].getBytes(Shell.CHARSET))), + formatter.interpretColumnQualifier(new Text(sa[1].getBytes(Shell.CHARSET)))); + } + } + } + } + + protected Range getRange(final CommandLine cl, final ScanInterpreter formatter) throws UnsupportedEncodingException { + if ((cl.hasOption(OptUtil.START_ROW_OPT) || cl.hasOption(OptUtil.END_ROW_OPT)) && cl.hasOption(scanOptRow.getOpt())) { + // did not see a way to make commons cli do this check... it has mutually exclusive options but does not support the or + throw new IllegalArgumentException("Options -" + scanOptRow.getOpt() + " AND (-" + OptUtil.START_ROW_OPT + " OR -" + OptUtil.END_ROW_OPT + + ") are mutally exclusive "); + } + + if (cl.hasOption(scanOptRow.getOpt())) { + return new Range(formatter.interpretRow(new Text(cl.getOptionValue(scanOptRow.getOpt()).getBytes(Shell.CHARSET)))); + } else { + Text startRow = OptUtil.getStartRow(cl); + if (startRow != null) + startRow = formatter.interpretBeginRow(startRow); + Text endRow = OptUtil.getEndRow(cl); + if (endRow != null) + endRow = formatter.interpretEndRow(endRow); + final boolean startInclusive = !cl.hasOption(optStartRowExclusive.getOpt()); + final boolean endInclusive = !cl.hasOption(optEndRowExclusive.getOpt()); + return new Range(startRow, startInclusive, endRow, endInclusive); + } + } + + protected Authorizations getAuths(final CommandLine cl, final Shell shellState) throws AccumuloSecurityException, AccumuloException { + final String user = shellState.getConnector().whoami(); + Authorizations auths = shellState.getConnector().securityOperations().getUserAuthorizations(user); + if (cl.hasOption(scanOptAuths.getOpt())) { + auths = ScanCommand.parseAuthorizations(cl.getOptionValue(scanOptAuths.getOpt())); + } + return auths; + } + + static Authorizations parseAuthorizations(final String field) { + if (field == null || field.isEmpty()) { + return Authorizations.EMPTY; + } + return new Authorizations(field.split(",")); + } + + @Override + public String description() { + return "scans the table, and displays the resulting records"; + } + + @Override + public Options getOptions() { + final Options o = new Options(); + + scanOptAuths = new Option("s", "scan-authorizations", true, "scan authorizations (all user auths are used if this argument is not specified)"); + optStartRowExclusive = new Option("be", "begin-exclusive", false, "make start row exclusive (by default it's inclusive)"); + optStartRowExclusive.setArgName("begin-exclusive"); + optEndRowExclusive = new Option("ee", "end-exclusive", false, "make end row exclusive (by default it's inclusive)"); + optEndRowExclusive.setArgName("end-exclusive"); + scanOptRow = new Option("r", "row", true, "row to scan"); + scanOptColumns = new Option("c", "columns", true, "comma-separated columns"); + timestampOpt = new Option("st", "show-timestamps", false, "display timestamps"); + disablePaginationOpt = new Option("np", "no-pagination", false, "disable pagination of output"); + showFewOpt = new Option("f", "show-few", true, "show only a specified number of characters"); + formatterOpt = new Option("fm", "formatter", true, "fully qualified name of the formatter class to use"); + interpreterOpt = new Option("i", "interpreter", true, "fully qualified name of the interpreter class to use"); + formatterInterpeterOpt = new Option("fi", "fmt-interpreter", true, "fully qualified name of a class that is a formatter and interpreter"); + timeoutOption = new Option(null, "timeout", true, + "time before scan should fail if no data is returned. If no unit is given assumes seconds. Units d,h,m,s,and ms are supported. e.g. 30s or 100ms"); + outputFileOpt = new Option("o", "output", true, "local file to write the scan output to"); + + scanOptAuths.setArgName("comma-separated-authorizations"); + scanOptRow.setArgName("row"); + scanOptColumns.setArgName("<columnfamily>[:<columnqualifier>]{,<columnfamily>[:<columnqualifier>]}"); + showFewOpt.setRequired(false); + showFewOpt.setArgName("int"); + formatterOpt.setArgName("className"); + timeoutOption.setArgName("timeout"); + outputFileOpt.setArgName("file"); + + profileOpt = new Option("pn", "profile", true, "iterator profile name"); + profileOpt.setArgName("profile"); + + o.addOption(scanOptAuths); + o.addOption(scanOptRow); - o.addOption(OptUtil.startRowOpt()); ++ optStartRowInclusive = new Option(OptUtil.START_ROW_OPT, "begin-row", true, "begin row (inclusive)"); ++ optStartRowInclusive.setArgName("begin-row"); ++ o.addOption(optStartRowInclusive); + o.addOption(OptUtil.endRowOpt()); + o.addOption(optStartRowExclusive); + o.addOption(optEndRowExclusive); + o.addOption(scanOptColumns); + o.addOption(timestampOpt); + o.addOption(disablePaginationOpt); + o.addOption(OptUtil.tableOpt("table to be scanned")); + o.addOption(showFewOpt); + o.addOption(formatterOpt); + o.addOption(interpreterOpt); + o.addOption(formatterInterpeterOpt); + o.addOption(timeoutOption); + o.addOption(outputFileOpt); + o.addOption(profileOpt); + + return o; + } + + @Override + public int numArgs() { + return 0; + } + + protected PrintFile getOutputFile(final CommandLine cl) throws FileNotFoundException { + final String outputFile = cl.getOptionValue(outputFileOpt.getOpt()); + return (outputFile == null ? null : new PrintFile(outputFile)); + } +} http://git-wip-us.apache.org/repos/asf/accumulo/blob/4678cf92/shell/src/test/java/org/apache/accumulo/shell/commands/CompactCommandTest.java ---------------------------------------------------------------------- diff --cc shell/src/test/java/org/apache/accumulo/shell/commands/CompactCommandTest.java index 0000000,0000000..928f7f2 new file mode 100644 --- /dev/null +++ b/shell/src/test/java/org/apache/accumulo/shell/commands/CompactCommandTest.java @@@ -1,0 -1,0 +1,29 @@@ ++/* ++ * 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 org.junit.Assert.assertTrue; ++import org.junit.Test; ++ ++public class CompactCommandTest { ++ ++ @Test ++ public void testBeginRowHelp() { ++ assertTrue("-b should say it is exclusive", new CompactCommand().getOptions().getOption("b").getDescription().contains("(exclusive)")); ++ } ++ ++} http://git-wip-us.apache.org/repos/asf/accumulo/blob/4678cf92/shell/src/test/java/org/apache/accumulo/shell/commands/DeleteManyCommandTest.java ---------------------------------------------------------------------- diff --cc shell/src/test/java/org/apache/accumulo/shell/commands/DeleteManyCommandTest.java index 0000000,0000000..bfe370b new file mode 100644 --- /dev/null +++ b/shell/src/test/java/org/apache/accumulo/shell/commands/DeleteManyCommandTest.java @@@ -1,0 -1,0 +1,29 @@@ ++/* ++ * 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 org.junit.Assert.assertTrue; ++import org.junit.Test; ++ ++public class DeleteManyCommandTest { ++ ++ @Test ++ public void testBeginRowHelp() { ++ assertTrue("-b should say it is inclusive", new DeleteManyCommand().getOptions().getOption("b").getDescription().contains("row (inclusive)")); ++ } ++ ++} http://git-wip-us.apache.org/repos/asf/accumulo/blob/4678cf92/shell/src/test/java/org/apache/accumulo/shell/commands/DeleteRowsCommandTest.java ---------------------------------------------------------------------- diff --cc shell/src/test/java/org/apache/accumulo/shell/commands/DeleteRowsCommandTest.java index 0000000,0000000..0cf8c11 new file mode 100644 --- /dev/null +++ b/shell/src/test/java/org/apache/accumulo/shell/commands/DeleteRowsCommandTest.java @@@ -1,0 -1,0 +1,29 @@@ ++/* ++ * 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 org.junit.Assert.assertTrue; ++import org.junit.Test; ++ ++public class DeleteRowsCommandTest { ++ ++ @Test ++ public void testBeginRowHelp() { ++ assertTrue("-b should say it is exclusive", new DeleteRowsCommand().getOptions().getOption("b").getDescription().contains("(exclusive)")); ++ } ++ ++} http://git-wip-us.apache.org/repos/asf/accumulo/blob/4678cf92/shell/src/test/java/org/apache/accumulo/shell/commands/FlushCommandTest.java ---------------------------------------------------------------------- diff --cc shell/src/test/java/org/apache/accumulo/shell/commands/FlushCommandTest.java index 0000000,0000000..7250427 new file mode 100644 --- /dev/null +++ b/shell/src/test/java/org/apache/accumulo/shell/commands/FlushCommandTest.java @@@ -1,0 -1,0 +1,29 @@@ ++/* ++ * 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 org.junit.Assert.assertTrue; ++import org.junit.Test; ++ ++public class FlushCommandTest { ++ ++ @Test ++ public void testBeginRowHelp() { ++ assertTrue("-b should say it is exclusive", new FlushCommand().getOptions().getOption("b").getDescription().contains("(exclusive)")); ++ } ++ ++} http://git-wip-us.apache.org/repos/asf/accumulo/blob/4678cf92/shell/src/test/java/org/apache/accumulo/shell/commands/MergeCommandTest.java ---------------------------------------------------------------------- diff --cc shell/src/test/java/org/apache/accumulo/shell/commands/MergeCommandTest.java index 0000000,0000000..5cd2f2e new file mode 100644 --- /dev/null +++ b/shell/src/test/java/org/apache/accumulo/shell/commands/MergeCommandTest.java @@@ -1,0 -1,0 +1,29 @@@ ++/* ++ * 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 org.junit.Assert.assertTrue; ++import org.junit.Test; ++ ++public class MergeCommandTest { ++ ++ @Test ++ public void testBeginRowHelp() { ++ assertTrue("-b should say it is exclusive", new MergeCommand().getOptions().getOption("b").getDescription().contains("(exclusive)")); ++ } ++ ++} http://git-wip-us.apache.org/repos/asf/accumulo/blob/4678cf92/shell/src/test/java/org/apache/accumulo/shell/commands/ScanCommandTest.java ---------------------------------------------------------------------- diff --cc shell/src/test/java/org/apache/accumulo/shell/commands/ScanCommandTest.java index 0000000,0000000..173d8a1 new file mode 100644 --- /dev/null +++ b/shell/src/test/java/org/apache/accumulo/shell/commands/ScanCommandTest.java @@@ -1,0 -1,0 +1,29 @@@ ++/* ++ * 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 org.junit.Assert.assertTrue; ++import org.junit.Test; ++ ++public class ScanCommandTest { ++ ++ @Test ++ public void testBeginRowHelp() { ++ assertTrue("-b should say it is inclusive", new ScanCommand().getOptions().getOption("b").getDescription().contains("row (inclusive)")); ++ } ++ ++}