HBASE-25611 ExportSnapshot chmod flag uses value as decimal (#3003)
[hbase.git] / hbase-common / src / main / java / org / apache / hadoop / hbase / util / AbstractHBaseTool.java
blob8aaba41adf1e772c19e3a8aff7a8b17845ae7633
1 /**
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
15 * under the License.
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;
44 /**
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> {
72 @Override
73 public int compare(Option o1, Option o2) {
74 return optionsOrder.get(o1) - optionsOrder.get(o2);
78 /**
79 * Override this to add command-line options using {@link #addOptWithArg}
80 * and similar methods.
82 protected abstract void addOptions();
84 /**
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;
92 /**
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) {
106 @Override
107 public Configuration getConf() {
108 return conf;
111 @Override
112 public void setConf(Configuration conf) {
113 this.conf = conf;
116 @Override
117 public int run(String[] args) throws IOException {
118 cmdLineArgs = args;
120 Objects.requireNonNull(conf, "Tool configuration is not initialized");
122 CommandLine cmd;
123 List<String> argsList = new ArrayList<>(args.length);
124 for (String arg : args) {
125 argsList.add(arg);
127 // For backward compatibility of args which can't be parsed as Option. See javadoc for
128 // processOldArgs(..)
129 processOldArgs(argsList);
130 try {
131 addOptions();
132 if (isHelpCommand(args)) {
133 printUsage();
134 return EXIT_SUCCESS;
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.");
142 return EXIT_FAILURE;
143 } catch (ParseException e) {
144 LOG.error("Error when parsing command-line arguments", e);
145 LOG.error("Use -h or --help for usage instructions.");
146 return EXIT_FAILURE;
149 processOptions(cmd);
151 int ret;
152 try {
153 ret = doWork();
154 } catch (Exception e) {
155 LOG.error("Error running command-line tool", e);
156 return EXIT_FAILURE;
158 return ret;
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");
180 addOptions();
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);
204 addOption(option);
207 protected void addRequiredOptWithArg(String opt, String description) {
208 Option option = new Option(opt, true, description);
209 option.setRequired(true);
210 addOption(option);
213 protected void addRequiredOptWithArg(String shortOpt, String longOpt, String description) {
214 Option option = new Option(shortOpt, longOpt, true, description);
215 option.setRequired(true);
216 addOption(option);
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);
242 } else {
243 return defaultValue;
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);
254 } else {
255 return defaultValue;
259 public double getOptionAsDouble(CommandLine cmd, String opt, double defaultValue) {
260 if (cmd.hasOption(opt)) {
261 return Double.parseDouble(cmd.getOptionValue(opt));
262 } else {
263 return defaultValue;
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 + "]");
276 return l;
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[]) {
285 int ret;
286 try {
287 ret = ToolRunner.run(HBaseConfiguration.create(), this, args);
288 } catch (Exception ex) {
289 LOG.error("Error running command-line tool", ex);
290 ret = EXIT_FAILURE;
292 System.exit(ret);