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