继续向下看:
.hasArg()
.withDescription( " specifyanamenode " )
.create( " fs " );
opts.addOption(fs);
有一个很重要的类OptionBuilder,它才完成了“充实”一个Option的过程,然后经过多次调用,会将多个Option都添加到opts列表中。
看一看OptionBuilder类的withArgName()方法:
*ThenextOptioncreatedwillhavethespecifiedargumentvalue
*name.
*
* @param namethenamefortheargumentvalue
* @return theOptionBuilderinstance
*/
public static OptionBuilderwithArgName(Stringname)
{
OptionBuilder.argName = name;
return instance;
}
上面,为一个OptionBuilder的实例指定一个参数(argName)为name,实际上是返回了一个具有name的OptionBuilder实例。
然后,又调用了hasArg()方法,它也是OptionBuilder类的静态方法:
*ThenextOptioncreatedwillrequireanargumentvalue.
*
* @return theOptionBuilderinstance
*/
public static OptionBuilderhasArg()
{
OptionBuilder.numberOfArgs = 1 ;
return instance;
}
为刚才指定参数名的那个OptionBuilder实例设置了参数的个数,因为第一次设置,当然个数为1了。
调用withDescription()方法来设定描述信息:
*ThenextOptioncreatedwillhavethespecifieddescription
*
* @param newDescriptionadescriptionoftheOption'spurpose
* @return theOptionBuilderinstance
*/
public static OptionBuilderwithDescription(StringnewDescription)
{
OptionBuilder.description = newDescription;
return instance;
}
比较关键的是最后一步调用,通过调用OptionBuilder类的create()方法才真正完成了一个Option的创建:
*CreateanOptionusingthecurrentsettingsandwith
*thespecifiedOption<code>char</code>.
*
* @param optthe<code>java.lang.String</code>representation
*oftheOption
* @return theOptioninstance
* @throws IllegalArgumentExceptionif<code>opt</code>isnot
*avalidcharacter.SeeOption.
*/
public static Optioncreate(Stringopt)
throws IllegalArgumentException
{
// createtheoption
Optionoption = new Option(opt,description);
// settheoptionproperties
option.setLongOpt(longopt);
option.setRequired(required);
option.setOptionalArg(optionalArg);
option.setArgs(numberOfArgs);
option.setType(type);
option.setValueSeparator(valuesep);
option.setArgName(argName);
option.setArgPattern(argPattern,limit);
// resettheOptionBuilderproperties
OptionBuilder.reset();
// returntheOptioninstance
return option;
}
从上面一个Option的设置,我们可以看出来,OptionBuilder类其实是一个辅助工具,用来收集与一个Option相关的信息,从而将这些信息一次全部赋予到一个新建的Option对象上,这个对象现在具有详细的信息了。
接着,通过CommandLineParser parser的parse方法,可以知道public abstract class Parser implements CommandLineParser,从抽象类Parser中找到parse的实现:
boolean stopAtNonOption)
throws ParseException
{
return parse(options,arguments, null ,stopAtNonOption);
}
参数stopAtNonOption表明,如果解析过程中遇到的是一个空选项是否仍然继续解析。从前面parseGeneralOptions方法 中commandLine = parser.parse(opts, args, true);可知:我们传递过来一个true。
再次调用Parser类的重载成员方法parse(),如下所示,解析过程非常详细:
*Parsetheargumentsaccordingtothespecifiedoptionsand
*properties.
*
* @param optionsthespecifiedOptions
* @param argumentsthecommandlinearguments
* @param propertiescommandlineoptionname-valuepairs
* @param stopAtNonOptionstopparsingtheargumentswhenthefirst
*nonoptionisencountered.
*
* @return thelistofatomicoptionandvaluetokens
*
* @throws ParseExceptionifthereareanyproblemsencountered
*whileparsingthecommandlinetokens.
*/
public CommandLineparse(Optionsoptions,String[]arguments,
Propertiesproperties, boolean stopAtNonOption)
throws ParseException
{
// initialisemembers
this .options = options;
requiredOptions = options.getRequiredOptions();
cmd = new CommandLine();
boolean eatTheRest = false ;
if (arguments == null )
{
arguments = new String[ 0 ];
}
ListtokenList = Arrays.asList(flatten( this .options,
arguments,
stopAtNonOption));
ListIteratoriterator = tokenList.listIterator();
// processeachflattenedtoken
while (iterator.hasNext())
{
Stringt = (String)iterator.next();
// thevalueisthedouble-dash
if ( " -- " .equals(t))
{
eatTheRest = true ;
}
// thevalueisasingledash
else if ( " - " .equals(t))
{
if (stopAtNonOption)
{
eatTheRest = true ;
}
else
{
cmd.addArg(t);
}
}
// thevalueisanoption
else if (t.startsWith( " - " ))
{
if (stopAtNonOption && ! options.hasOption(t))
{
eatTheRest = true ;
cmd.addArg(t);
}
else
{
processOption(t,iterator);
}
}
// thevalueisanargument
else
{
cmd.addArg(t);
if (stopAtNonOption)
{
eatTheRest = true ;
}
}
// eattheremainingtokens
if (eatTheRest)
{
while (iterator.hasNext())
{
Stringstr = (String)iterator.next();
// ensureonlyonedouble-dashisadded
if ( ! " -- " .equals(str))
{
cmd.addArg(str);
}
}
}
}
processProperties(properties);
checkRequiredOptions();
return cmd;
}
解析之后,返回CommandLine类的实例,从而GenericOptionsParser类的成员变量commandLine获取到了一个引用。commandLine是GenericOptionsParser类的一个私有成员变量。
看一下CommandLine类的实现:
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
/**
*Representslistofargumentsparsedagainst
*a{ @link Options}descriptor.
*
*Itallowsqueryingofaboolean{ @link #hasOption(Stringopt)},
*inadditiontoretrievingthe{ @link #getOptionValue(Stringopt)}
*foroptionsrequiringarguments.
*/
public class CommandLine{
// 不能识别的options/arguments
private Listargs = new LinkedList();
/** theprocessedoptions */
private Mapoptions = new HashMap();
/** theoptionnamemap */
private Mapnames = new HashMap();
/** Mapofuniqueoptionsforeasetogetcompletelistofoptions */
private MaphashcodeMap = new HashMap();
/** theprocessedoptions */
private Option[]optionsArray;
// 创建一个命令行CommandLine的实例。
CommandLine()
{
// nothingtodo
}
// 从options这个HashMap中查看,判断是否opt已经被设置了
public boolean hasOption(Stringopt)
{
return options.containsKey(opt);
}
// 调用hasOption()方法,从options这个HashMap中查看,判断是否opt已经被设置了
public boolean hasOption( char opt)
{
return hasOption(String.valueOf(opt));
}
// 根据Stringopt返回Option的Object类型
public ObjectgetOptionObject(Stringopt)
{
Stringres = getOptionValue(opt);
if ( ! options.containsKey(opt))
{
return null ;
}
Objecttype = ((Option)options.get(opt)).getType();
return (res == null ) ? null :TypeHandler.createValue(res,type);
}
// 根据charopt返回Option的Object类型
public ObjectgetOptionObject( char opt)
{
return getOptionObject(String.valueOf(opt));
}
// 根据指定的Stringopt获取Option的值
public StringgetOptionValue(Stringopt)
{
String[]values = getOptionValues(opt);
return (values == null ) ? null :values[ 0 ];
}
// 根据指定的charopt获取Option的值
public StringgetOptionValue( char opt)
{
return getOptionValue(String.valueOf(opt));
}
/**
*Retrievesthearrayofvalues,ifany,ofanoption.
*
* @param optstringnameoftheoption
* @return Valuesoftheargumentifoptionisset,andhasanargument,
*otherwisenull.
*/
public String[]getOptionValues(Stringopt)
{
opt = Util.stripLeadingHyphens(opt);
Stringkey = opt;
if (names.containsKey(opt))
{
key = (String)names.get(opt);
}
if (options.containsKey(key))
{
return ((Option)options.get(key)).getValues();
}
return null ;
}
// 根据指定的Stringopt,返回Option的值的一个数组
public String[]getOptionValues( char opt)
{
return getOptionValues(String.valueOf(opt));
}
// 根据指定的Stringopt和StringdefaultValue获取Option的值
public StringgetOptionValue(Stringopt,StringdefaultValue)
{
Stringanswer = getOptionValue(opt);
return (answer != null ) ? answer:defaultValue;
}
// 根据指定的charopt和StringdefaultValue获取Option的值
public StringgetOptionValue( char opt,StringdefaultValue)
{
return getOptionValue(String.valueOf(opt),defaultValue);
}
// 返回不能够解析的Option和参数的一个数组
public String[]getArgs()
{
String[]answer = new String[args.size()];
args.toArray(answer);
return answer;
}
// 返回不能够解析的Option和参数的一个列表
public ListgetArgList()
{
return args;
}
/**
*jkeyes
*-commentedoutuntilitisimplementedproperly
*<p>Dumpstate,suitablefordebugging.</p>
*
* @return Stringifiedformofthisobject
*/
public StringtoString(){
StringBufferbuf = new StringBuffer();
buf.append( " [CommandLine:[options: " );
buf.append(options.toString());
buf.append( " ][args: " );
buf.append(args.toString());
buf.append( " ]] " );
return buf.toString();
}
/**
*Addleft-overunrecognizedoption/argument.
*
* @param argtheunrecognisedoption/argument.
*/
void addArg(Stringarg)
{
args.add(arg);
}
// 向CommandLine中添加一个Option,其中Option的值(可能多个)被存储
void addOption(Optionopt)
{
hashcodeMap.put( new Integer(opt.hashCode()),opt);
Stringkey = opt.getKey();
if (key == null )
{
key = opt.getLongOpt();
}
else
{
names.put(opt.getLongOpt(),key);
}
options.put(key,opt);
}
// 返回CommandLine的Option成员表的一个迭代器
public Iteratoriterator()
{
return hashcodeMap.values().iterator();
}
// 返回处理过的Option的对象数组
public Option[]getOptions()
{
Collectionprocessed = options.values();
// reinitialisearray
optionsArray = new Option[processed.size()];
// returnthearray
return (Option[])processed.toArray(optionsArray);
}
}
一个CommandLine中包含一个重要的HashMap,里面存储的是键值对,即(key, opt),通过它可以非常方便地设置和访问。
接着在parseGeneralOptions方法中调用processGeneralOptions()方法,进行处理:
processGeneralOptions的处理过程如下:
*Modifyconfigurationaccordinguser-specifiedgenericoptions
* @param confConfigurationtobemodified
* @param lineUser-specifiedgenericoptions
*/
private void processGeneralOptions(Configurationconf,
CommandLineline){
if (line.hasOption( " fs " )){
conf.set( " fs.default.name " ,line.getOptionValue( " fs " ));
}
if (line.hasOption( " jt " )){
conf.set( " mapred.job.tracker " ,line.getOptionValue( " jt " ));
}
if (line.hasOption( " conf " )){
conf.addResource( new Path(line.getOptionValue( " conf " )));
}
if (line.hasOption( ' D ' )){
String[]property = line.getOptionValues( ' D ' );
for ( int i = 0 ;i < property.length - 1 ;i = i + 2 ){
if (property[i] != null )
conf.set(property[i],property[i + 1 ]);
}
}
}
传进去一个CommandLine实例,通过CommanLine的信息,来设置Configuration conf对象。设置Configuration conf对象的目的是:为Hadoop的Tool工作而设置的,比如WordCount这个工具,在运行开始时需要获取到Hadoop的配置信息的,这个 就需要从这里设置的Configuration conf对象来获取。
上面这个processGeneralOptions()方法,是根据CommanLine的对象,获取到所有参数值的一个数组,并返回。
到此位置,前面都是为了初始化一个GenericOptionsParser parser解析器所做的工作:
进而,可以使用 GenericOptionsParser类的实例parser 来获取Hadoop的通用参数了:
String[]toolArgs = parser.getRemainingArgs();
已经具备了运行Hadoop工具的条件了,可以启动了:
可以根据返回的状态码检查工具运行情况。
上面Tool tool就是我们实例化的WordCount对象,这时候才进入到WordCount实现中。