GenericOptionsParser.java
上传用户:quxuerui
上传日期:2018-01-08
资源大小:41811k
文件大小:14k
源码类别:

网格计算

开发平台:

Java

  1. /**
  2.  * Licensed to the Apache Software Foundation (ASF) under one
  3.  * or more contributor license agreements.  See the NOTICE file
  4.  * distributed with this work for additional information
  5.  * regarding copyright ownership.  The ASF licenses this file
  6.  * to you under the Apache License, Version 2.0 (the
  7.  * "License"); you may not use this file except in compliance
  8.  * with the License.  You may obtain a copy of the License at
  9.  *
  10.  *     http://www.apache.org/licenses/LICENSE-2.0
  11.  *
  12.  * Unless required by applicable law or agreed to in writing, software
  13.  * distributed under the License is distributed on an "AS IS" BASIS,
  14.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15.  * See the License for the specific language governing permissions and
  16.  * limitations under the License.
  17.  */
  18. package org.apache.hadoop.util;
  19. import java.io.FileNotFoundException;
  20. import java.io.IOException;
  21. import java.io.PrintStream;
  22. import java.net.URI;
  23. import java.net.URL;
  24. import java.net.URLClassLoader;
  25. import org.apache.commons.cli.CommandLine;
  26. import org.apache.commons.cli.CommandLineParser;
  27. import org.apache.commons.cli.GnuParser;
  28. import org.apache.commons.cli.HelpFormatter;
  29. import org.apache.commons.cli.Option;
  30. import org.apache.commons.cli.OptionBuilder;
  31. import org.apache.commons.cli.Options;
  32. import org.apache.commons.cli.ParseException;
  33. import org.apache.commons.logging.Log;
  34. import org.apache.commons.logging.LogFactory;
  35. import org.apache.hadoop.conf.Configuration;
  36. import org.apache.hadoop.fs.FileSystem;
  37. import org.apache.hadoop.fs.Path;
  38. /**
  39.  * <code>GenericOptionsParser</code> is a utility to parse command line
  40.  * arguments generic to the Hadoop framework. 
  41.  * 
  42.  * <code>GenericOptionsParser</code> recognizes several standarad command 
  43.  * line arguments, enabling applications to easily specify a namenode, a 
  44.  * jobtracker, additional configuration resources etc.
  45.  * 
  46.  * <h4 id="GenericOptions">Generic Options</h4>
  47.  * 
  48.  * <p>The supported generic options are:</p>
  49.  * <p><blockquote><pre>
  50.  *     -conf &lt;configuration file&gt;     specify a configuration file
  51.  *     -D &lt;property=value&gt;            use value for given property
  52.  *     -fs &lt;local|namenode:port&gt;      specify a namenode
  53.  *     -jt &lt;local|jobtracker:port&gt;    specify a job tracker
  54.  *     -files &lt;comma separated list of files&gt;    specify comma separated
  55.  *                            files to be copied to the map reduce cluster
  56.  *     -libjars &lt;comma separated list of jars&gt;   specify comma separated
  57.  *                            jar files to include in the classpath.
  58.  *     -archives &lt;comma separated list of archives&gt;    specify comma
  59.  *             separated archives to be unarchived on the compute machines.
  60.  * </pre></blockquote></p>
  61.  * 
  62.  * <p>The general command line syntax is:</p>
  63.  * <p><tt><pre>
  64.  * bin/hadoop command [genericOptions] [commandOptions]
  65.  * </pre></tt></p>
  66.  * 
  67.  * <p>Generic command line arguments <strong>might</strong> modify 
  68.  * <code>Configuration </code> objects, given to constructors.</p>
  69.  * 
  70.  * <p>The functionality is implemented using Commons CLI.</p>
  71.  *
  72.  * <p>Examples:</p>
  73.  * <p><blockquote><pre>
  74.  * $ bin/hadoop dfs -fs darwin:8020 -ls /data
  75.  * list /data directory in dfs with namenode darwin:8020
  76.  * 
  77.  * $ bin/hadoop dfs -D fs.default.name=darwin:8020 -ls /data
  78.  * list /data directory in dfs with namenode darwin:8020
  79.  *     
  80.  * $ bin/hadoop dfs -conf hadoop-site.xml -ls /data
  81.  * list /data directory in dfs with conf specified in hadoop-site.xml
  82.  *     
  83.  * $ bin/hadoop job -D mapred.job.tracker=darwin:50020 -submit job.xml
  84.  * submit a job to job tracker darwin:50020
  85.  *     
  86.  * $ bin/hadoop job -jt darwin:50020 -submit job.xml
  87.  * submit a job to job tracker darwin:50020
  88.  *     
  89.  * $ bin/hadoop job -jt local -submit job.xml
  90.  * submit a job to local runner
  91.  * 
  92.  * $ bin/hadoop jar -libjars testlib.jar 
  93.  * -archives test.tgz -files file.txt inputjar args
  94.  * job submission with libjars, files and archives
  95.  * </pre></blockquote></p>
  96.  *
  97.  * @see Tool
  98.  * @see ToolRunner
  99.  */
  100. public class GenericOptionsParser {
  101.   private static final Log LOG = LogFactory.getLog(GenericOptionsParser.class);
  102.   private Configuration conf;
  103.   private CommandLine commandLine;
  104.   /**
  105.    * Create an options parser with the given options to parse the args.
  106.    * @param opts the options
  107.    * @param args the command line arguments
  108.    */
  109.   public GenericOptionsParser(Options opts, String[] args) {
  110.     this(new Configuration(), new Options(), args);
  111.   }
  112.   /**
  113.    * Create an options parser to parse the args.
  114.    * @param args the command line arguments
  115.    */
  116.   public GenericOptionsParser(String[] args) {
  117.     this(new Configuration(), new Options(), args);
  118.   }
  119.   
  120.   /** 
  121.    * Create a <code>GenericOptionsParser<code> to parse only the generic Hadoop  
  122.    * arguments. 
  123.    * 
  124.    * The array of string arguments other than the generic arguments can be 
  125.    * obtained by {@link #getRemainingArgs()}.
  126.    * 
  127.    * @param conf the <code>Configuration</code> to modify.
  128.    * @param args command-line arguments.
  129.    */
  130.   public GenericOptionsParser(Configuration conf, String[] args) {
  131.     this(conf, new Options(), args); 
  132.   }
  133.   /** 
  134.    * Create a <code>GenericOptionsParser</code> to parse given options as well 
  135.    * as generic Hadoop options. 
  136.    * 
  137.    * The resulting <code>CommandLine</code> object can be obtained by 
  138.    * {@link #getCommandLine()}.
  139.    * 
  140.    * @param conf the configuration to modify  
  141.    * @param options options built by the caller 
  142.    * @param args User-specified arguments
  143.    */
  144.   public GenericOptionsParser(Configuration conf, Options options, String[] args) {
  145.     parseGeneralOptions(options, conf, args);
  146.     this.conf = conf;
  147.   }
  148.   /**
  149.    * Returns an array of Strings containing only application-specific arguments.
  150.    * 
  151.    * @return array of <code>String</code>s containing the un-parsed arguments
  152.    * or <strong>empty array</strong> if commandLine was not defined.
  153.    */
  154.   public String[] getRemainingArgs() {
  155.     return (commandLine == null) ? new String[]{} : commandLine.getArgs();
  156.   }
  157.   /**
  158.    * Get the modified configuration
  159.    * @return the configuration that has the modified parameters.
  160.    */
  161.   public Configuration getConfiguration() {
  162.     return conf;
  163.   }
  164.   /**
  165.    * Returns the commons-cli <code>CommandLine</code> object 
  166.    * to process the parsed arguments. 
  167.    * 
  168.    * Note: If the object is created with 
  169.    * {@link #GenericOptionsParser(Configuration, String[])}, then returned 
  170.    * object will only contain parsed generic options.
  171.    * 
  172.    * @return <code>CommandLine</code> representing list of arguments 
  173.    *         parsed against Options descriptor.
  174.    */
  175.   public CommandLine getCommandLine() {
  176.     return commandLine;
  177.   }
  178.   /**
  179.    * Specify properties of each generic option
  180.    */
  181.   @SuppressWarnings("static-access")
  182.   private static Options buildGeneralOptions(Options opts) {
  183.     Option fs = OptionBuilder.withArgName("local|namenode:port")
  184.     .hasArg()
  185.     .withDescription("specify a namenode")
  186.     .create("fs");
  187.     Option jt = OptionBuilder.withArgName("local|jobtracker:port")
  188.     .hasArg()
  189.     .withDescription("specify a job tracker")
  190.     .create("jt");
  191.     Option oconf = OptionBuilder.withArgName("configuration file")
  192.     .hasArg()
  193.     .withDescription("specify an application configuration file")
  194.     .create("conf");
  195.     Option property = OptionBuilder.withArgName("property=value")
  196.     .hasArgs()
  197.     .withArgPattern("=", 1)
  198.     .withDescription("use value for given property")
  199.     .create('D');
  200.     Option libjars = OptionBuilder.withArgName("paths")
  201.     .hasArg()
  202.     .withDescription("comma separated jar files to include in the classpath.")
  203.     .create("libjars");
  204.     Option files = OptionBuilder.withArgName("paths")
  205.     .hasArg()
  206.     .withDescription("comma separated files to be copied to the " +
  207.            "map reduce cluster")
  208.     .create("files");
  209.     Option archives = OptionBuilder.withArgName("paths")
  210.     .hasArg()
  211.     .withDescription("comma separated archives to be unarchived" +
  212.                      " on the compute machines.")
  213.     .create("archives");
  214.     opts.addOption(fs);
  215.     opts.addOption(jt);
  216.     opts.addOption(oconf);
  217.     opts.addOption(property);
  218.     opts.addOption(libjars);
  219.     opts.addOption(files);
  220.     opts.addOption(archives);
  221.     return opts;
  222.   }
  223.   /**
  224.    * Modify configuration according user-specified generic options
  225.    * @param conf Configuration to be modified
  226.    * @param line User-specified generic options
  227.    */
  228.   private void processGeneralOptions(Configuration conf,
  229.       CommandLine line) {
  230.     if (line.hasOption("fs")) {
  231.       FileSystem.setDefaultUri(conf, line.getOptionValue("fs"));
  232.     }
  233.     if (line.hasOption("jt")) {
  234.       conf.set("mapred.job.tracker", line.getOptionValue("jt"));
  235.     }
  236.     if (line.hasOption("conf")) {
  237.       String[] values = line.getOptionValues("conf");
  238.       for(String value : values) {
  239.         conf.addResource(new Path(value));
  240.       }
  241.     }
  242.     try {
  243.       if (line.hasOption("libjars")) {
  244.         conf.set("tmpjars", 
  245.                  validateFiles(line.getOptionValue("libjars"), conf));
  246.         //setting libjars in client classpath
  247.         URL[] libjars = getLibJars(conf);
  248.         if(libjars!=null && libjars.length>0) {
  249.           conf.setClassLoader(new URLClassLoader(libjars, conf.getClassLoader()));
  250.           Thread.currentThread().setContextClassLoader(
  251.               new URLClassLoader(libjars, 
  252.                   Thread.currentThread().getContextClassLoader()));
  253.         }
  254.       }
  255.       if (line.hasOption("files")) {
  256.         conf.set("tmpfiles", 
  257.                  validateFiles(line.getOptionValue("files"), conf));
  258.       }
  259.       if (line.hasOption("archives")) {
  260.         conf.set("tmparchives", 
  261.                   validateFiles(line.getOptionValue("archives"), conf));
  262.       }
  263.     } catch (IOException ioe) {
  264.       System.err.println(StringUtils.stringifyException(ioe));
  265.     }
  266.     if (line.hasOption('D')) {
  267.       String[] property = line.getOptionValues('D');
  268.       for(int i=0; i<property.length-1; i=i+2) {
  269.         if (property[i]!=null)
  270.           conf.set(property[i], property[i+1]);
  271.       }
  272.     }
  273.     conf.setBoolean("mapred.used.genericoptionsparser", true);
  274.   }
  275.   
  276.   /**
  277.    * If libjars are set in the conf, parse the libjars.
  278.    * @param conf
  279.    * @return libjar urls
  280.    * @throws IOException
  281.    */
  282.   public static URL[] getLibJars(Configuration conf) throws IOException {
  283.     String jars = conf.get("tmpjars");
  284.     if(jars==null) {
  285.       return null;
  286.     }
  287.     String[] files = jars.split(",");
  288.     URL[] cp = new URL[files.length];
  289.     for (int i=0;i<cp.length;i++) {
  290.       Path tmp = new Path(files[i]);
  291.       cp[i] = FileSystem.getLocal(conf).pathToFile(tmp).toURI().toURL();
  292.     }
  293.     return cp;
  294.   }
  295.   /**
  296.    * takes input as a comma separated list of files
  297.    * and verifies if they exist. It defaults for file:///
  298.    * if the files specified do not have a scheme.
  299.    * it returns the paths uri converted defaulting to file:///.
  300.    * So an input of  /home/user/file1,/home/user/file2 would return
  301.    * file:///home/user/file1,file:///home/user/file2
  302.    * @param files
  303.    * @return
  304.    */
  305.   private String validateFiles(String files, Configuration conf) throws IOException  {
  306.     if (files == null) 
  307.       return null;
  308.     String[] fileArr = files.split(",");
  309.     String[] finalArr = new String[fileArr.length];
  310.     for (int i =0; i < fileArr.length; i++) {
  311.       String tmp = fileArr[i];
  312.       String finalPath;
  313.       Path path = new Path(tmp);
  314.       URI pathURI =  path.toUri();
  315.       FileSystem localFs = FileSystem.getLocal(conf);
  316.       if (pathURI.getScheme() == null) {
  317.         //default to the local file system
  318.         //check if the file exists or not first
  319.         if (!localFs.exists(path)) {
  320.           throw new FileNotFoundException("File " + tmp + " does not exist.");
  321.         }
  322.         finalPath = path.makeQualified(localFs).toString();
  323.       }
  324.       else {
  325.         // check if the file exists in this file system
  326.         // we need to recreate this filesystem object to copy
  327.         // these files to the file system jobtracker is running
  328.         // on.
  329.         FileSystem fs = path.getFileSystem(conf);
  330.         if (!fs.exists(path)) {
  331.           throw new FileNotFoundException("File " + tmp + " does not exist.");
  332.         }
  333.         finalPath = path.makeQualified(fs).toString();
  334.         try {
  335.           fs.close();
  336.         } catch(IOException e){};
  337.       }
  338.       finalArr[i] = finalPath;
  339.     }
  340.     return StringUtils.arrayToString(finalArr);
  341.   }
  342.   
  343.   /**
  344.    * Parse the user-specified options, get the generic options, and modify
  345.    * configuration accordingly
  346.    * @param conf Configuration to be modified
  347.    * @param args User-specified arguments
  348.    * @return Command-specific arguments
  349.    */
  350.   private String[] parseGeneralOptions(Options opts, Configuration conf, 
  351.       String[] args) {
  352.     opts = buildGeneralOptions(opts);
  353.     CommandLineParser parser = new GnuParser();
  354.     try {
  355.       commandLine = parser.parse(opts, args, true);
  356.       processGeneralOptions(conf, commandLine);
  357.       return commandLine.getArgs();
  358.     } catch(ParseException e) {
  359.       LOG.warn("options parsing failed: "+e.getMessage());
  360.       HelpFormatter formatter = new HelpFormatter();
  361.       formatter.printHelp("general options are: ", opts);
  362.     }
  363.     return args;
  364.   }
  365.   /**
  366.    * Print the usage message for generic command-line options supported.
  367.    * 
  368.    * @param out stream to print the usage message to.
  369.    */
  370.   public static void printGenericCommandUsage(PrintStream out) {
  371.     
  372.     out.println("Generic options supported are");
  373.     out.println("-conf <configuration file>     specify an application configuration file");
  374.     out.println("-D <property=value>            use value for given property");
  375.     out.println("-fs <local|namenode:port>      specify a namenode");
  376.     out.println("-jt <local|jobtracker:port>    specify a job tracker");
  377.     out.println("-files <comma separated list of files>    " + 
  378.       "specify comma separated files to be copied to the map reduce cluster");
  379.     out.println("-libjars <comma separated list of jars>    " +
  380.       "specify comma separated jar files to include in the classpath.");
  381.     out.println("-archives <comma separated list of archives>    " +
  382.                 "specify comma separated archives to be unarchived" +
  383.                 " on the compute machines.n");
  384.     out.println("The general command line syntax is");
  385.     out.println("bin/hadoop command [genericOptions] [commandOptions]n");
  386.   }
  387.   
  388. }