View Javadoc

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
8    *
9    * http://www.apache.org/licenses/LICENSE-2.0
10   *
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.
16   */
17  package org.apache.hadoop.hbase.util;
18  
19  import java.io.IOException;
20  import java.util.Set;
21  import java.util.TreeSet;
22  
23  import org.apache.commons.cli.BasicParser;
24  import org.apache.commons.cli.CommandLine;
25  import org.apache.commons.cli.CommandLineParser;
26  import org.apache.commons.cli.HelpFormatter;
27  import org.apache.commons.cli.Options;
28  import org.apache.commons.cli.ParseException;
29  import org.apache.commons.logging.Log;
30  import org.apache.commons.logging.LogFactory;
31  import org.apache.hadoop.hbase.classification.InterfaceAudience;
32  import org.apache.hadoop.conf.Configuration;
33  import org.apache.hadoop.hbase.HBaseConfiguration;
34  import org.apache.hadoop.util.Tool;
35  import org.apache.hadoop.util.ToolRunner;
36  
37  /**
38   * Common base class used for HBase command-line tools. Simplifies workflow and
39   * command-line argument parsing.
40   */
41  @InterfaceAudience.Private
42  public abstract class AbstractHBaseTool implements Tool {
43  
44    protected static final int EXIT_SUCCESS = 0;
45    protected static final int EXIT_FAILURE = 1;
46  
47    private static final String SHORT_HELP_OPTION = "h";
48    private static final String LONG_HELP_OPTION = "help";
49  
50    private static final Log LOG = LogFactory.getLog(AbstractHBaseTool.class);
51  
52    private final Options options = new Options();
53  
54    protected Configuration conf = null;
55  
56    private static final Set<String> requiredOptions = new TreeSet<String>();
57  
58    protected String[] cmdLineArgs = null;
59  
60    /**
61     * Override this to add command-line options using {@link #addOptWithArg}
62     * and similar methods.
63     */
64    protected abstract void addOptions();
65  
66    /**
67     * This method is called to process the options after they have been parsed.
68     */
69    protected abstract void processOptions(CommandLine cmd);
70  
71    /** The "main function" of the tool */
72    protected abstract int doWork() throws Exception;
73  
74    @Override
75    public Configuration getConf() {
76      return conf;
77    }
78  
79    @Override
80    public void setConf(Configuration conf) {
81      this.conf = conf;
82    }
83  
84    @Override
85    public final int run(String[] args) throws IOException {
86      if (conf == null) {
87        LOG.error("Tool configuration is not initialized");
88        throw new NullPointerException("conf");
89      }
90  
91      CommandLine cmd;
92      try {
93        // parse the command line arguments
94        cmd = parseArgs(args);
95        cmdLineArgs = args;
96      } catch (ParseException e) {
97        LOG.error("Error when parsing command-line arguments", e);
98        printUsage();
99        return EXIT_FAILURE;
100     }
101 
102     if (cmd.hasOption(SHORT_HELP_OPTION) || cmd.hasOption(LONG_HELP_OPTION) ||
103         !sanityCheckOptions(cmd)) {
104       printUsage();
105       return EXIT_FAILURE;
106     }
107 
108     processOptions(cmd);
109 
110     int ret = EXIT_FAILURE;
111     try {
112       ret = doWork();
113     } catch (Exception e) {
114       LOG.error("Error running command-line tool", e);
115       return EXIT_FAILURE;
116     }
117     return ret;
118   }
119 
120   private boolean sanityCheckOptions(CommandLine cmd) {
121     boolean success = true;
122     for (String reqOpt : requiredOptions) {
123       if (!cmd.hasOption(reqOpt)) {
124         LOG.error("Required option -" + reqOpt + " is missing");
125         success = false;
126       }
127     }
128     return success;
129   }
130 
131   protected CommandLine parseArgs(String[] args) throws ParseException {
132     options.addOption(SHORT_HELP_OPTION, LONG_HELP_OPTION, false, "Show usage");
133     addOptions();
134     CommandLineParser parser = new BasicParser();
135     return parser.parse(options, args);
136   }
137 
138   protected void printUsage() {
139     printUsage("bin/hbase " + getClass().getName() + " <options>", "Options:", "");
140   }
141 
142   protected void printUsage(final String usageStr, final String usageHeader,
143       final String usageFooter) {
144     HelpFormatter helpFormatter = new HelpFormatter();
145     helpFormatter.setWidth(120);
146     helpFormatter.printHelp(usageStr, usageHeader, options, usageFooter);
147   }
148 
149   protected void addRequiredOptWithArg(String opt, String description) {
150     requiredOptions.add(opt);
151     addOptWithArg(opt, description);
152   }
153 
154   protected void addRequiredOptWithArg(String shortOpt, String longOpt, String description) {
155     requiredOptions.add(longOpt);
156     addOptWithArg(shortOpt, longOpt, description);
157   }
158 
159   protected void addOptNoArg(String opt, String description) {
160     options.addOption(opt, false, description);
161   }
162 
163   protected void addOptNoArg(String shortOpt, String longOpt, String description) {
164     options.addOption(shortOpt, longOpt, false, description);
165   }
166 
167   protected void addOptWithArg(String opt, String description) {
168     options.addOption(opt, true, description);
169   }
170 
171   protected void addOptWithArg(String shortOpt, String longOpt, String description) {
172     options.addOption(shortOpt, longOpt, true, description);
173   }
174 
175   /**
176    * Parse a number and enforce a range.
177    */
178   public static long parseLong(String s, long minValue, long maxValue) {
179     long l = Long.parseLong(s);
180     if (l < minValue || l > maxValue) {
181       throw new IllegalArgumentException("The value " + l
182           + " is out of range [" + minValue + ", " + maxValue + "]");
183     }
184     return l;
185   }
186 
187   public static int parseInt(String s, int minValue, int maxValue) {
188     return (int) parseLong(s, minValue, maxValue);
189   }
190 
191   /** Call this from the concrete tool class's main function. */
192   protected void doStaticMain(String args[]) {
193     int ret;
194     try {
195       ret = ToolRunner.run(HBaseConfiguration.create(), this, args);
196     } catch (Exception ex) {
197       LOG.error("Error running command-line tool", ex);
198       ret = EXIT_FAILURE;
199     }
200     System.exit(ret);
201   }
202 
203 }