分析Hadoop自带WordCount例子的执行过程(2)

这里说明一下Option类及其如何设置一个Option类的实例。

在buildGeneralOptions()方法接收Options opts然后又返回了opts,在这个过程中已经改变了opts的值。如下所示:

/**
   * Specify properties of each generic option
   */
@SuppressWarnings("static-access")
private Options buildGeneralOptions(Options opts) {
    Option fs = OptionBuilder.withArgName("local|namenode:port")
    .hasArg()
    .withDescription("specify a namenode")
    .create("fs");
    Option jt = OptionBuilder.withArgName("local|jobtracker:port")
    .hasArg()
    .withDescription("specify a job tracker")
    .create("jt");
    Option oconf = OptionBuilder.withArgName("configuration file")
    .hasArg()
    .withDescription("specify an application configuration file")
    .create("conf");
    Option property = OptionBuilder.withArgName("property=value")
    .hasArgs()
    .withArgPattern("=", 1)
    .withDescription("use value for given property")
    .create('D');

opts.addOption(fs);
    opts.addOption(jt);
    opts.addOption(oconf);
    opts.addOption(property);
   
    return opts;
}

 

开始传进来一个opts,它并没有任何内容(是指Option类的对象,即一个选项),因为从开始实例化就没有配置过Options opts。但是,在上面代码的后面部分,已经为opts设置内容了,其实就是设置添加Option类的对象到Options中去。

看看具体都添加了一些什么信息。拿出一项来看看:

Option fs = OptionBuilder.withArgName("local|namenode:port")
    .hasArg()
    .withDescription("specify a namenode")
    .create("fs");

opts.addOption(fs);

 

Option代表了一个命令行,我们看一下Option类的定义:

package org.apache.commons.cli;

import java.util.ArrayList;
import java.util.regex.Pattern;

public class Option {

// 参数值没有被指定时,用-1表示
    public static final int UNINITIALIZED = -1;

// 参数值为无穷时使用-2表示
    public static final int UNLIMITED_VALUES = -2;

//   标识一个Option的字符串名称
    private String opt;

// Option使用长名称表示
    private String longOpt;

// 表明一个Option是否有一个相关的参数
    private boolean hasArg;

// 表明一个Option的参数的名称
    private String argName = "arg";

// 一个Option的描述信息
    private String description;

// 一个Option是否是必须指定的
    private boolean required;

// 是否一个Option的参数值是可选的
    private boolean optionalArg;

// 一个Option可以具有参数值的个数
     private int numberOfArgs = UNINITIALIZED;

// 一个Option的类型
    private Object type;

// 参数值列表
    private ArrayList values = new ArrayList();

// 指定用作分隔符的字符
    private char valuesep;

// 参数样式及其它出现的次数
    private Pattern argPattern;
    private int limit;

/**
     * 构造一个Option.
     *
     * @param opt 标识一个Option的名称
     * @param description   一个Option的描述信息
     */
    public Option(String opt, String description)
           throws IllegalArgumentException
    {
        this(opt, null, false, description); // 调用其他构造方法
    }

// 另一种构造方法
    public Option(String opt, boolean hasArg, String description)
           throws IllegalArgumentException
    {
        this(opt, null, hasArg, description);
    }

// 还是构造一个Option
    public Option(String opt, String longOpt, boolean hasArg,
                  String description)
           throws IllegalArgumentException
    {
        // 验证一个Option是合法的
        OptionValidator.validateOption(opt);

this.opt = opt;
        this.longOpt = longOpt;

// if hasArg is set then the number of arguments is 1
        if (hasArg)
        {
            this.numberOfArgs = 1;
        }

this.hasArg = hasArg;
        this.description = description;
    }

// 返回Option的ID
    public int getId()
    {
        return getKey().charAt(0);
    }

/**
     * Returns the 'unique' Option identifier.
     *
     * @return the 'unique' Option identifier
     */
    String getKey()
    {
        // if 'opt' is null, then it is a 'long' option
        if (opt == null)
        {
            return this.longOpt;
        }

return this.opt;
    }

/**
     * 返回一个Option的name
     */
    public String getOpt()
    {
        return this.opt;
    }

/**
     * 返回一个Option的类型
     */
    public Object getType()
    {
        return this.type;
    }

/**
     * 设置一个Option的类型
     */
    public void setType(Object type)
    {
        this.type = type;
    }

/**
     * 返回一个Option的长名称
     */
    public String getLongOpt()
    {
        return this.longOpt;
    }

/**
     * 设置一个Option的长名称
     */
    public void setLongOpt(String longOpt)
    {
        this.longOpt = longOpt;
    }

/**
     * 设置一个Option是否具有一个可选的参数
     */
    public void setOptionalArg(boolean optionalArg)
    {
        this.optionalArg = optionalArg;
    }

/**
     * 返回一个Option的是否具有可选的参数
     */
    public boolean hasOptionalArg()
    {
        return this.optionalArg;
    }

/**
     * 是否Option具有一个长名称
     */
    public boolean hasLongOpt()
    {
        return (this.longOpt != null);
    }

/**
     * 是否一个Option有一个必需的参数
     */
    public boolean hasArg()
    {
        return (this.numberOfArgs > 0) || (numberOfArgs == UNLIMITED_VALUES);
    }
      // 返回一个Option的描述信息
    public String getDescription()
    {
        return this.description;
    }

// 设置一个Option的描述信息
    public void setDescription(String description)
    {
        this.description = description;
    }

// 是否一个Option需要指定一个参数
    public boolean isRequired()
    {
        return this.required;
    }

// 设置一个Option的参数是否必需
    public void setRequired(boolean required)
    {
        this.required = required;
    }

// 设置这个参数值的显示名称
    public void setArgName(String argName)
    {
        this.argName = argName;
    }

// 返回这个参数值的显示名称
    public String getArgName()
    {
        return this.argName;
    }

//   是否这个参数值的显示名称已经被设置了
      public boolean hasArgName()
    {
        return (this.argName != null && this.argName.length() > 0);
    }

//   是否一个Option可以具有多个参数值
    public boolean hasArgs()
    {
        return (this.numberOfArgs > 1)
                || (this.numberOfArgs == UNLIMITED_VALUES);
    }

// 设置一个Option具有的参数值的个数
    public void setArgs(int num)
    {
        this.numberOfArgs = num;
    }

// 设置值的分隔符字符
    public void setValueSeparator(char sep)
    {
        this.valuesep = sep;
    }

// 返回值的分隔符字符
    public char getValueSeparator()
    {
        return this.valuesep;
    }

//   是否一个Option指定了值的分隔符字符
    public boolean hasValueSeparator()
    {
        return (this.valuesep > 0);
    }

//   一个Option是否指定多了参数的样式
    public boolean hasArgPattern()
    {
        return (limit!=0&&argPattern!=null);
    }

public void setArgPattern( String argPattern, int limit )
    {
        if(argPattern==null || argPattern.length()==0 || limit==0 )
          return;
        this.argPattern = Pattern.compile(argPattern);
        this.limit = limit;
    }

//   返回一个Option具有参数的个数
    public int getArgs()
    {
        return this.numberOfArgs;
    }

// 设置一个Option的值
    void addValue(String value)
    {
        switch (numberOfArgs)
        {
        case UNINITIALIZED:
            throw new RuntimeException("NO_ARGS_ALLOWED");

default:
            processValue(value);
        }
    }

//   检查参数样式
    private void checkArgPattern( String arg ) {
      if(!hasArgPattern()) {
        add(arg);
      } else {
        String [] tokens = argPattern.split(arg, -1);
        if(tokens.length != limit+1)
          throw new RuntimeException("ARG_PATTERN_NOT_MATCH");
        for(int i=0; i<= limit; i++) {
          add(tokens[i]);
        }
      }
    }

// 处理一个Option的值
    private void processValue(String value)
    {
        // this Option has a separator character
        if (hasValueSeparator())
        {
            // get the separator character
            char sep = getValueSeparator();

// store the index for the value separator
            int index = value.indexOf(sep);

// while there are more value separators
            while (index != -1)
            {
                // next value to be added
                if (values.size()/(limit+1) == (numberOfArgs - 1))
                {
                    break;
                }


                // store
                checkArgPattern(value.substring(0, index));


                // parse
                value = value.substring(index + 1);


                // get new index
                index = value.indexOf(sep);
            }
        }


        // check if the argment matches specified pattern; if yes,
        // store the actual value or the last value that has been parsed
        checkArgPattern(value);
    }

//   向一个Option添加值,如果参数的个数大于0并且有足够的列表的时候才可以添加
      private void add(String value)
    {
        if ((numberOfArgs > 0) && (values.size() > (numberOfArgs - 1)))
        {
            throw new RuntimeException("Cannot add value, list full.");
        }


        this.values.add(value);
    }

//   返回Option的值
    public String getValue()
    {
        return hasNoValues() ? null : (String) this.values.get(0);
    }

// 返回指定的Option的值
    public String getValue(int index)
        throws IndexOutOfBoundsException
    {
        return hasNoValues() ? null : (String) this.values.get(index);
    }

// 返回一个Option的值,或者第一个值,如果它没有值就返回一个默认值     
    public String getValue(String defaultValue)
    {
        String value = getValue();

return (value != null) ? value : defaultValue;
    }

//   以一个字符串数组的形式返回一个Option的所有值
    public String[] getValues()
    {
        return hasNoValues()
               ? null : (String[]) this.values.toArray(new String[] { });
    }

//   以列表的形式返回一个Option的所有值
    public java.util.List getValuesList()
    {
        return this.values;
    }

//   用于调试使用的
    public String toString()
    {
        StringBuffer buf = new StringBuffer().append("[ option: ");

buf.append(this.opt);

if (this.longOpt != null)
        {
            buf.append(" ").append(this.longOpt);
        }

buf.append(" ");

if (hasArg)
        {
            buf.append("+ARG");
        }

buf.append(" :: ").append(this.description);

if (this.type != null)
        {
            buf.append(" :: ").append(this.type);
        }

buf.append(" ]");

return buf.toString();
    }

//   一个Option是否可以是任意值
    private boolean hasNoValues()
    {
        return this.values.size() == 0;
    }
}

 

可以看出,一个Option所具有的信息很多:长名称(longOpt)、短名称(name)、类型(type)、样式(pattern)、参数个数(numberOfArgs)、参数值的字符分隔符、ID,描述等等。

只有设置好了这些Option的信息,调用private Options buildGeneralOptions(Options opts) 方法时候返回的Options可以被后面进行解析使用。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/pxpfw.html