HBASE-19497 Fix findbugs and error-prone warnings in hbase-common (branch-2)
[hbase.git] / hbase-common / src / main / java / org / apache / hadoop / hbase / util / AbstractHBaseTool.java
blob21b174e71b301bbc151099fb3deceb6f9f729a73
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;
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;
43 /**
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> {
71 @Override
72 public int compare(Option o1, Option o2) {
73 return optionsOrder.get(o1) - optionsOrder.get(o2);
77 /**
78 * Override this to add command-line options using {@link #addOptWithArg}
79 * and similar methods.
81 protected abstract void addOptions();
83 /**
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;
91 /**
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) {
105 @Override
106 public Configuration getConf() {
107 return conf;
110 @Override
111 public void setConf(Configuration conf) {
112 this.conf = conf;
115 @Override
116 public int run(String[] args) throws IOException {
117 cmdLineArgs = args;
118 if (conf == null) {
119 LOG.error("Tool configuration is not initialized");
120 throw new NullPointerException("conf");
123 CommandLine cmd;
124 List<String> argsList = new ArrayList<>(args.length);
125 for (String arg : args) {
126 argsList.add(arg);
128 // For backward compatibility of args which can't be parsed as Option. See javadoc for
129 // processOldArgs(..)
130 processOldArgs(argsList);
131 try {
132 addOptions();
133 if (isHelpCommand(args)) {
134 printUsage();
135 return EXIT_SUCCESS;
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.");
143 return EXIT_FAILURE;
144 } catch (ParseException e) {
145 LOG.error("Error when parsing command-line arguments", e);
146 LOG.error("Use -h or --help for usage instructions.");
147 return EXIT_FAILURE;
150 processOptions(cmd);
152 int ret;
153 try {
154 ret = doWork();
155 } catch (Exception e) {
156 LOG.error("Error running command-line tool", e);
157 return EXIT_FAILURE;
159 return ret;
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");
171 addOptions();
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);
195 addOption(option);
198 protected void addRequiredOptWithArg(String opt, String description) {
199 Option option = new Option(opt, true, description);
200 option.setRequired(true);
201 addOption(option);
204 protected void addRequiredOptWithArg(String shortOpt, String longOpt, String description) {
205 Option option = new Option(shortOpt, longOpt, true, description);
206 option.setRequired(true);
207 addOption(option);
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));
229 } else {
230 return defaultValue;
234 public long getOptionAsLong(CommandLine cmd, String opt, int defaultValue) {
235 if (cmd.hasOption(opt)) {
236 return Long.parseLong(cmd.getOptionValue(opt));
237 } else {
238 return defaultValue;
242 public double getOptionAsDouble(CommandLine cmd, String opt, double defaultValue) {
243 if (cmd.hasOption(opt)) {
244 return Double.parseDouble(cmd.getOptionValue(opt));
245 } else {
246 return defaultValue;
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 + "]");
259 return l;
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[]) {
268 int ret;
269 try {
270 ret = ToolRunner.run(HBaseConfiguration.create(), this, args);
271 } catch (Exception ex) {
272 LOG.error("Error running command-line tool", ex);
273 ret = EXIT_FAILURE;
275 System.exit(ret);