2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with this
4 * work for additional information regarding copyright ownership. The ASF
5 * licenses this file to you under the Apache License, Version 2.0 (the
6 * "License"); you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14 * License for the specific language governing permissions and limitations
17 package org
.apache
.hadoop
.hbase
.util
;
19 import java
.io
.IOException
;
20 import java
.util
.ArrayList
;
21 import java
.util
.Comparator
;
22 import java
.util
.HashMap
;
23 import java
.util
.List
;
24 import java
.util
.Objects
;
26 import org
.apache
.hadoop
.conf
.Configuration
;
27 import org
.apache
.hadoop
.hbase
.HBaseConfiguration
;
28 import org
.apache
.hadoop
.util
.Tool
;
29 import org
.apache
.hadoop
.util
.ToolRunner
;
30 import org
.apache
.yetus
.audience
.InterfaceAudience
;
31 import org
.slf4j
.Logger
;
32 import org
.slf4j
.LoggerFactory
;
34 import org
.apache
.hbase
.thirdparty
.org
.apache
.commons
.cli
.BasicParser
;
35 import org
.apache
.hbase
.thirdparty
.org
.apache
.commons
.cli
.CommandLine
;
36 import org
.apache
.hbase
.thirdparty
.org
.apache
.commons
.cli
.CommandLineParser
;
37 import org
.apache
.hbase
.thirdparty
.org
.apache
.commons
.cli
.DefaultParser
;
38 import org
.apache
.hbase
.thirdparty
.org
.apache
.commons
.cli
.HelpFormatter
;
39 import org
.apache
.hbase
.thirdparty
.org
.apache
.commons
.cli
.MissingOptionException
;
40 import org
.apache
.hbase
.thirdparty
.org
.apache
.commons
.cli
.Option
;
41 import org
.apache
.hbase
.thirdparty
.org
.apache
.commons
.cli
.Options
;
42 import org
.apache
.hbase
.thirdparty
.org
.apache
.commons
.cli
.ParseException
;
45 * Common base class used for HBase command-line tools. Simplifies workflow and
46 * command-line argument parsing.
48 @InterfaceAudience.Private
49 public abstract class AbstractHBaseTool
implements Tool
{
50 public static final int EXIT_SUCCESS
= 0;
51 public static final int EXIT_FAILURE
= 1;
53 public static final String SHORT_HELP_OPTION
= "h";
54 public static final String LONG_HELP_OPTION
= "help";
56 private static final Option HELP_OPTION
= new Option("h", "help", false,
57 "Prints help for this tool.");
59 private static final Logger LOG
= LoggerFactory
.getLogger(AbstractHBaseTool
.class);
61 protected final Options options
= new Options();
63 protected Configuration conf
= null;
65 protected String
[] cmdLineArgs
= null;
67 // To print options in order they were added in help text.
68 private HashMap
<Option
, Integer
> optionsOrder
= new HashMap
<>();
69 private int optionsCount
= 0;
71 public class OptionsOrderComparator
implements Comparator
<Option
> {
73 public int compare(Option o1
, Option o2
) {
74 return optionsOrder
.get(o1
) - optionsOrder
.get(o2
);
79 * Override this to add command-line options using {@link #addOptWithArg}
80 * and similar methods.
82 protected abstract void addOptions();
85 * This method is called to process the options after they have been parsed.
87 protected abstract void processOptions(CommandLine cmd
);
89 /** The "main function" of the tool */
90 protected abstract int doWork() throws Exception
;
93 * For backward compatibility. DO NOT use it for new tools.
94 * We have options in existing tools which can't be ported to Apache CLI's {@link Option}.
95 * (because they don't pass validation, for e.g. "-copy-to". "-" means short name
96 * which doesn't allow '-' in name). This function is to allow tools to have, for time being,
97 * parameters which can't be parsed using {@link Option}.
98 * Overrides should consume all valid legacy arguments. If the param 'args' is not empty on
99 * return, it means there were invalid options, in which case we'll exit from the tool.
100 * Note that it's called before {@link #processOptions(CommandLine)}, which means new options'
101 * values will override old ones'.
103 protected void processOldArgs(List
<String
> args
) {
107 public Configuration
getConf() {
112 public void setConf(Configuration conf
) {
117 public int run(String
[] args
) throws IOException
{
120 Objects
.requireNonNull(conf
, "Tool configuration is not initialized");
123 List
<String
> argsList
= new ArrayList
<>(args
.length
);
124 for (String arg
: args
) {
127 // For backward compatibility of args which can't be parsed as Option. See javadoc for
128 // processOldArgs(..)
129 processOldArgs(argsList
);
132 if (isHelpCommand(args
)) {
136 String
[] remainingArgs
= new String
[argsList
.size()];
137 argsList
.toArray(remainingArgs
);
138 cmd
= newParser().parse(options
, remainingArgs
);
139 } catch (MissingOptionException e
) {
140 LOG
.error(e
.getMessage());
141 LOG
.error("Use -h or --help for usage instructions.");
143 } catch (ParseException e
) {
144 LOG
.error("Error when parsing command-line arguments", e
);
145 LOG
.error("Use -h or --help for usage instructions.");
154 } catch (Exception e
) {
155 LOG
.error("Error running command-line tool", e
);
162 * Create the parser to use for parsing and validating the command line. Since commons-cli lacks
163 * the capability to validate arbitrary combination of options, it may be helpful to bake custom
164 * logic into a specialized parser implementation. See LoadTestTool for examples.
165 * @return a new parser specific to the current tool
167 protected CommandLineParser
newParser() {
168 return new DefaultParser();
171 private boolean isHelpCommand(String
[] args
) throws ParseException
{
172 Options helpOption
= new Options().addOption(HELP_OPTION
);
173 // this parses the command line but doesn't throw an exception on unknown options
174 CommandLine cl
= new DefaultParser().parse(helpOption
, args
, true);
175 return cl
.getOptions().length
!= 0;
178 protected CommandLine
parseArgs(String
[] args
) throws ParseException
{
179 options
.addOption(SHORT_HELP_OPTION
, LONG_HELP_OPTION
, false, "Show usage");
181 CommandLineParser parser
= new BasicParser();
182 return parser
.parse(options
, args
);
185 protected void printUsage() {
186 printUsage("hbase " + getClass().getName() + " <options>", "Options:", "");
189 protected void printUsage(final String usageStr
, final String usageHeader
,
190 final String usageFooter
) {
191 HelpFormatter helpFormatter
= new HelpFormatter();
192 helpFormatter
.setWidth(120);
193 helpFormatter
.setOptionComparator(new OptionsOrderComparator());
194 helpFormatter
.printHelp(usageStr
, usageHeader
, options
, usageFooter
);
197 protected void addOption(Option option
) {
198 options
.addOption(option
);
199 optionsOrder
.put(option
, optionsCount
++);
202 protected void addRequiredOption(Option option
) {
203 option
.setRequired(true);
207 protected void addRequiredOptWithArg(String opt
, String description
) {
208 Option option
= new Option(opt
, true, description
);
209 option
.setRequired(true);
213 protected void addRequiredOptWithArg(String shortOpt
, String longOpt
, String description
) {
214 Option option
= new Option(shortOpt
, longOpt
, true, description
);
215 option
.setRequired(true);
219 protected void addOptNoArg(String opt
, String description
) {
220 addOption(new Option(opt
, false, description
));
223 protected void addOptNoArg(String shortOpt
, String longOpt
, String description
) {
224 addOption(new Option(shortOpt
, longOpt
, false, description
));
227 protected void addOptWithArg(String opt
, String description
) {
228 addOption(new Option(opt
, true, description
));
231 protected void addOptWithArg(String shortOpt
, String longOpt
, String description
) {
232 addOption(new Option(shortOpt
, longOpt
, true, description
));
235 public int getOptionAsInt(CommandLine cmd
, String opt
, int defaultValue
) {
236 return getOptionAsInt(cmd
, opt
, defaultValue
, 10);
239 public int getOptionAsInt(CommandLine cmd
, String opt
, int defaultValue
, int radix
) {
240 if (cmd
.hasOption(opt
)) {
241 return Integer
.parseInt(cmd
.getOptionValue(opt
), radix
);
247 public long getOptionAsLong(CommandLine cmd
, String opt
, int defaultValue
) {
248 return getOptionAsLong(cmd
, opt
, defaultValue
, 10);
251 public long getOptionAsLong(CommandLine cmd
, String opt
, int defaultValue
, int radix
) {
252 if (cmd
.hasOption(opt
)) {
253 return Long
.parseLong(cmd
.getOptionValue(opt
), radix
);
259 public double getOptionAsDouble(CommandLine cmd
, String opt
, double defaultValue
) {
260 if (cmd
.hasOption(opt
)) {
261 return Double
.parseDouble(cmd
.getOptionValue(opt
));
268 * Parse a number and enforce a range.
270 public static long parseLong(String s
, long minValue
, long maxValue
) {
271 long l
= Long
.parseLong(s
);
272 if (l
< minValue
|| l
> maxValue
) {
273 throw new IllegalArgumentException("The value " + l
274 + " is out of range [" + minValue
+ ", " + maxValue
+ "]");
279 public static int parseInt(String s
, int minValue
, int maxValue
) {
280 return (int) parseLong(s
, minValue
, maxValue
);
283 /** Call this from the concrete tool class's main function. */
284 protected void doStaticMain(String args
[]) {
287 ret
= ToolRunner
.run(HBaseConfiguration
.create(), this, args
);
288 } catch (Exception ex
) {
289 LOG
.error("Error running command-line tool", ex
);