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
;
25 import org
.apache
.commons
.cli
.BasicParser
;
26 import org
.apache
.commons
.cli
.CommandLine
;
27 import org
.apache
.commons
.cli
.CommandLineParser
;
28 import org
.apache
.commons
.cli
.DefaultParser
;
29 import org
.apache
.commons
.cli
.HelpFormatter
;
30 import org
.apache
.commons
.cli
.MissingOptionException
;
31 import org
.apache
.commons
.cli
.Option
;
32 import org
.apache
.commons
.cli
.Options
;
33 import org
.apache
.commons
.cli
.ParseException
;
34 import org
.apache
.commons
.logging
.Log
;
35 import org
.apache
.commons
.logging
.LogFactory
;
36 import org
.apache
.hadoop
.conf
.Configurable
;
37 import org
.apache
.hadoop
.conf
.Configuration
;
38 import org
.apache
.hadoop
.hbase
.HBaseConfiguration
;
39 import org
.apache
.hadoop
.util
.Tool
;
40 import org
.apache
.hadoop
.util
.ToolRunner
;
41 import org
.apache
.yetus
.audience
.InterfaceAudience
;
44 * Common base class used for HBase command-line tools. Simplifies workflow and
45 * command-line argument parsing.
47 @InterfaceAudience.Private
48 public abstract class AbstractHBaseTool
implements Tool
, Configurable
{
49 protected static final int EXIT_SUCCESS
= 0;
50 protected static final int EXIT_FAILURE
= 1;
52 public static final String SHORT_HELP_OPTION
= "h";
53 public static final String LONG_HELP_OPTION
= "help";
55 private static final Option HELP_OPTION
= new Option("h", "help", false,
56 "Prints help for this tool.");
58 private static final Log LOG
= LogFactory
.getLog(AbstractHBaseTool
.class);
60 protected final Options options
= new Options();
62 protected Configuration conf
= null;
64 protected String
[] cmdLineArgs
= null;
66 // To print options in order they were added in help text.
67 private HashMap
<Option
, Integer
> optionsOrder
= new HashMap
<>();
68 private int optionsCount
= 0;
70 private class OptionsOrderComparator
implements Comparator
<Option
> {
72 public int compare(Option o1
, Option o2
) {
73 return optionsOrder
.get(o1
) - optionsOrder
.get(o2
);
78 * Override this to add command-line options using {@link #addOptWithArg}
79 * and similar methods.
81 protected abstract void addOptions();
84 * This method is called to process the options after they have been parsed.
86 protected abstract void processOptions(CommandLine cmd
);
88 /** The "main function" of the tool */
89 protected abstract int doWork() throws Exception
;
92 * For backward compatibility. DO NOT use it for new tools.
93 * We have options in existing tools which can't be ported to Apache CLI's {@link Option}.
94 * (because they don't pass validation, for e.g. "-copy-to". "-" means short name
95 * which doesn't allow '-' in name). This function is to allow tools to have, for time being,
96 * parameters which can't be parsed using {@link Option}.
97 * Overrides should consume all valid legacy arguments. If the param 'args' is not empty on
98 * return, it means there were invalid options, in which case we'll exit from the tool.
99 * Note that it's called before {@link #processOptions(CommandLine)}, which means new options'
100 * values will override old ones'.
102 protected void processOldArgs(List
<String
> args
) {
106 public Configuration
getConf() {
111 public void setConf(Configuration conf
) {
116 public int run(String
[] args
) throws IOException
{
119 LOG
.error("Tool configuration is not initialized");
120 throw new NullPointerException("conf");
124 List
<String
> argsList
= new ArrayList
<>(args
.length
);
125 for (String arg
: args
) {
128 // For backward compatibility of args which can't be parsed as Option. See javadoc for
129 // processOldArgs(..)
130 processOldArgs(argsList
);
133 if (isHelpCommand(args
)) {
137 String
[] remainingArgs
= new String
[argsList
.size()];
138 argsList
.toArray(remainingArgs
);
139 cmd
= new DefaultParser().parse(options
, remainingArgs
);
140 } catch (MissingOptionException e
) {
141 LOG
.error(e
.getMessage());
142 LOG
.error("Use -h or --help for usage instructions.");
144 } catch (ParseException e
) {
145 LOG
.error("Error when parsing command-line arguments", e
);
146 LOG
.error("Use -h or --help for usage instructions.");
155 } catch (Exception e
) {
156 LOG
.error("Error running command-line tool", e
);
162 private boolean isHelpCommand(String
[] args
) throws ParseException
{
163 Options helpOption
= new Options().addOption(HELP_OPTION
);
164 // this parses the command line but doesn't throw an exception on unknown options
165 CommandLine cl
= new DefaultParser().parse(helpOption
, args
, true);
166 return cl
.getOptions().length
!= 0;
169 protected CommandLine
parseArgs(String
[] args
) throws ParseException
{
170 options
.addOption(SHORT_HELP_OPTION
, LONG_HELP_OPTION
, false, "Show usage");
172 CommandLineParser parser
= new BasicParser();
173 return parser
.parse(options
, args
);
176 protected void printUsage() {
177 printUsage("hbase " + getClass().getName() + " <options>", "Options:", "");
180 protected void printUsage(final String usageStr
, final String usageHeader
,
181 final String usageFooter
) {
182 HelpFormatter helpFormatter
= new HelpFormatter();
183 helpFormatter
.setWidth(120);
184 helpFormatter
.setOptionComparator(new OptionsOrderComparator());
185 helpFormatter
.printHelp(usageStr
, usageHeader
, options
, usageFooter
);
188 protected void addOption(Option option
) {
189 options
.addOption(option
);
190 optionsOrder
.put(option
, optionsCount
++);
193 protected void addRequiredOption(Option option
) {
194 option
.setRequired(true);
198 protected void addRequiredOptWithArg(String opt
, String description
) {
199 Option option
= new Option(opt
, true, description
);
200 option
.setRequired(true);
204 protected void addRequiredOptWithArg(String shortOpt
, String longOpt
, String description
) {
205 Option option
= new Option(shortOpt
, longOpt
, true, description
);
206 option
.setRequired(true);
210 protected void addOptNoArg(String opt
, String description
) {
211 addOption(new Option(opt
, false, description
));
214 protected void addOptNoArg(String shortOpt
, String longOpt
, String description
) {
215 addOption(new Option(shortOpt
, longOpt
, false, description
));
218 protected void addOptWithArg(String opt
, String description
) {
219 addOption(new Option(opt
, true, description
));
222 protected void addOptWithArg(String shortOpt
, String longOpt
, String description
) {
223 addOption(new Option(shortOpt
, longOpt
, true, description
));
226 public int getOptionAsInt(CommandLine cmd
, String opt
, int defaultValue
) {
227 if (cmd
.hasOption(opt
)) {
228 return Integer
.parseInt(cmd
.getOptionValue(opt
));
234 public long getOptionAsLong(CommandLine cmd
, String opt
, int defaultValue
) {
235 if (cmd
.hasOption(opt
)) {
236 return Long
.parseLong(cmd
.getOptionValue(opt
));
242 public double getOptionAsDouble(CommandLine cmd
, String opt
, double defaultValue
) {
243 if (cmd
.hasOption(opt
)) {
244 return Double
.parseDouble(cmd
.getOptionValue(opt
));
251 * Parse a number and enforce a range.
253 public static long parseLong(String s
, long minValue
, long maxValue
) {
254 long l
= Long
.parseLong(s
);
255 if (l
< minValue
|| l
> maxValue
) {
256 throw new IllegalArgumentException("The value " + l
257 + " is out of range [" + minValue
+ ", " + maxValue
+ "]");
262 public static int parseInt(String s
, int minValue
, int maxValue
) {
263 return (int) parseLong(s
, minValue
, maxValue
);
266 /** Call this from the concrete tool class's main function. */
267 protected void doStaticMain(String args
[]) {
270 ret
= ToolRunner
.run(HBaseConfiguration
.create(), this, args
);
271 } catch (Exception ex
) {
272 LOG
.error("Error running command-line tool", ex
);