org.apache.hadoop.conf-Configuration

9/6/2015来源:Java教程人气:2453

org.apache.hadoop.conf-Configuration

终于遇到第一块硬骨头


Hadoop没有使用java.util.PRoperties管理配置文件,而是自己定义了一套配置文件管理系统和自己的API。

  


   1 package org.apache.hadoop.conf;   2    3 import java.io.BufferedInputStream;   4 import java.io.DataInput;   5 import java.io.DataOutput;   6 import java.io.File;   7 import java.io.FileInputStream;   8 import java.io.IOException;   9 import java.io.InputStream;  10 import java.io.InputStreamReader;  11 import java.io.OutputStream;  12 import java.io.Reader;  13 import java.io.Writer;  14 import java.net.URL;  15 import java.util.ArrayList;  16 import java.util.Collection;  17 import java.util.Enumeration;  18 import java.util.HashMap;  19 import java.util.HashSet;  20 import java.util.Iterator;  21 import java.util.List;  22 import java.util.ListIterator;  23 import java.util.Map;  24 import java.util.Properties;  25 import java.util.Set;  26 import java.util.StringTokenizer;  27 import java.util.WeakHashMap;  28 import java.util.concurrent.CopyOnWriteArrayList;  29 import java.util.regex.Matcher;  30 import java.util.regex.Pattern;  31 //引入了IO的流类  32 //引入了网络编程类,用来封装或获取网络资源  33 //引入了工具包中的集合类。其中StringTokenier在hadoop中用的非常多,特别是在mapreduce编程中,经常需要这个工具类来处理数据。  34 //它起着分词器的作用。  35 //关于CopyOnWriteArrayList,之前没接触过,具体推荐 http://blog.csdn.net/imzoer/article/details/9751591,就是实现了线程安全  36 //关于regex.Matcher和regex.Pattern,看regex可知就是正则类,具体用法不太一样 http://ningtukun.blog.163.com/blog/static/186541445201292984311656/  37 import javax.xml.parsers.DocumentBuilder;  38 import javax.xml.parsers.DocumentBuilderFactory;  39 import javax.xml.parsers.ParserConfigurationException;  40 import javax.xml.transform.Transformer;  41 import javax.xml.transform.TransformerFactory;  42 import javax.xml.transform.dom.DOMSource;  43 import javax.xml.transform.stream.StreamResult;  44   45 import org.apache.commons.logging.Log;  46 import org.apache.commons.logging.LogFactory;  47 import org.apache.hadoop.fs.FileSystem;  48 import org.apache.hadoop.fs.Path;  49 import org.apache.hadoop.io.Writable;  50 import org.apache.hadoop.io.WritableUtils;  51 import org.apache.hadoop.util.StringUtils;  52 import org.codehaus.jackson.JsonFactory;  53 import org.codehaus.jackson.JsonGenerator;  54 import org.w3c.dom.DOMException;  55 import org.w3c.dom.Document;  56 import org.w3c.dom.Element;  57 import org.w3c.dom.Node;  58 import org.w3c.dom.NodeList;  59 import org.w3c.dom.Text;  60 import org.xml.sax.SAXException;  61   62 /**   63  * Provides access to configuration parameters.  64  *  65  * <h4 id="Resources">Resources</h4>  66  *  67  * <p>Configurations are specified by resources. A resource contains a set of  68  * name/value pairs as XML data. Each resource is named by either a   69  * <code>String</code> or by a {@link Path}. If named by a <code>String</code>,   70  * then the classpath is examined for a file with that name.  If named by a   71  * <code>Path</code>, then the local filesystem is examined directly, without   72  * referring to the classpath.  73  *  74  * <p>Unless explicitly turned off, Hadoop by default specifies two   75  * resources, loaded in-order from the classpath: <ol>  76  * <li><tt><a href="{@docRoot}/../core-default.html">core-default.xml</a>  77  * </tt>: Read-only defaults for hadoop.</li>  78  * <li><tt>core-site.xml</tt>: Site-specific configuration for a given hadoop  79  * installation.</li>  80  * </ol>  81  * applications may add additional resources, which are loaded  82  * subsequent to these resources in the order they are added.  83  *   84  * <h4 id="FinalParams">Final Parameters</h4>  85  *  86  * <p>Configuration parameters may be declared <i>final</i>.   87  * Once a resource declares a value final, no subsequently-loaded   88  * resource can alter that value.    89  * For example, one might define a final parameter with:  90  * <tt><pre>  91  *  &lt;property&gt;  92  *    &lt;name&gt;dfs.client.buffer.dir&lt;/name&gt;  93  *    &lt;value&gt;/tmp/hadoop/dfs/client&lt;/value&gt;  94  *    <b>&lt;final&gt;true&lt;/final&gt;</b>  95  *  &lt;/property&gt;</pre></tt>  96  *  97  * Administrators typically define parameters as final in   98  * <tt>core-site.xml</tt> for values that user applications may not alter.  99  * 100  * <h4 id="VariableExpansion">Variable Expansion</h4> 101  * 102  * <p>Value strings are first processed for <i>variable expansion</i>. The 103  * available properties are:<ol> 104  * <li>Other properties defined in this Configuration; and, if a name is 105  * undefined here,</li> 106  * <li>Properties in {@link System#getProperties()}.</li> 107  * </ol> 108  * 109  * <p>For example, if a configuration resource contains the following property 110  * definitions:  111  * <tt><pre> 112  *  &lt;property&gt; 113  *    &lt;name&gt;basedir&lt;/name&gt; 114  *    &lt;value&gt;/user/${<i>user.name</i>}&lt;/value&gt; 115  *  &lt;/property&gt; 116  *   117  *  &lt;property&gt; 118  *    &lt;name&gt;tempdir&lt;/name&gt; 119  *    &lt;value&gt;${<i>basedir</i>}/tmp&lt;/value&gt; 120  *  &lt;/property&gt;</pre></tt> 121  * 122  * When <tt>conf.get("tempdir")</tt> is called, then <tt>${<i>basedir</i>}</tt> 123  * will be resolved to another property in this Configuration, while 124  * <tt>${<i>user.name</i>}</tt> would then ordinarily be resolved to the value 125  * of the System property with that name. 126  */ 127  //一大段注释。第一句说这个类是用来提供访问配置中属性的渠道 128  //第二段话说配置文件的构造,XML文件中键值对。 129  //第三段话说除非主动关闭,否则hadoop会默认加载一些默认的配置文件。并且可以“重载” 130  //第四段说了配置文件中属性标记为final会怎么样 131  //第五段说配置文件中的属性可以用变量来表示,可以不是具体的实值。还举了个例子。 132 public class Configuration implements Iterable<Map.Entry<String,String>>, 133                                       Writable { 134 //实现了Iterable和Writable接口。 135 //实现Iterable接口,可以调用Iterator()方法进行迭代 136 //关于Map.Entry类,之前不了解。就是map的一种方便的遍历工具类 137 //实现了Writable接口。hadoop没有采用Java的序列化(具体原因不解释),而是引入了自己的序列化系统,所有的 138 //序列化对象都要实现writable接口。以后会遇到。                                   139   private static final Log LOG = 140     LogFactory.getLog(Configuration.class); 141   //创建了一个日志类。并做了初始化 142   private boolean quietmode = true; 143   //布尔变量quietmode,“安静模式”,用来确定加载配置的时候日志的某些动作, 144   //当为true的时候则在加载解析配置文件的过程中不输出日志信息,反之...... 145   /** 146    * List of configuration resources. 147    */ 148   private ArrayList<Object> resources = new ArrayList<Object>(); 149   //保存了所有通过addResource()方法添加的Configuration对象的资源 150   /** 151    * List of configuration parameters marked <b>final</b>.  152    */ 153   private Set<String> finalParameters = new HashSet<String>(); 154   //用来保存所有在配置文件中已经被声明为final的键–值对的键 155   private boolean loadDefaults = true; 156   //是否加载默认的配置资源 157   /** 158    * Configuration objects 159    */ 160   private static final WeakHashMap<Configuration,Object> REGISTRY =  161     new WeakHashMap<Configuration,Object>(); 162   //REGISTRY是一个WeakHashMap的变量,key为Configuration,value为Object, 163   //可以看出这个对象存储了不同对象的多个配置信息,弱HashMap可以自动清除不在正常使用的键对应的条目, 164   //发现如果这个值是null会重新加载默认的配置文件中的信息 165   /** 166    * List of default Resources. Resources are loaded in the order of the list  167    * entries 168    */ 169   private static final CopyOnWriteArrayList<String> defaultResources = 170     new CopyOnWriteArrayList<String>(); 171   //存放的是默认的配置信息,通过方法addDefaultResource()可以添加系统的默认资源 172   //存储配置文件的名字而不是配置文件的全路径 173   /** 174    * Flag to indicate if the storage of resource which updates a key needs  175    * to be stored for each key 176    */ 177   private boolean storeResource; 178   //是否需要更新配置文件的标识 179   /** 180    * Stores the mapping of key to the resource which modifies or loads  181    * the key most recently 182    */ 183   private HashMap<String, String> updatingResource; 184   //保存所有需要更新的配置文件 185   static{ 186     //print deprecation warning if hadoop-site.xml is found in classpath 187     ClassLoader cL = Thread.currentThread().getContextClassLoader(); 188     if (cL == null) { 189       cL = Configuration.class.getClassLoader(); 190     } 191     if(cL.getResource("hadoop-site.xml")!=null) { 192       LOG.warn("DEPRECATED: hadoop-site.xml found in the classpath. " + 193           "Usage of hadoop-site.xml is deprecated. Instead use core-site.xml, " 194           + "mapred-site.xml and hdfs-site.xml to override properties of " + 195           "core-default.xml, mapred-default.xml and hdfs-default.xml " + 196           "respectively"); 197     } 198     addDefaultResource("core-default.xml"); 199     addDefaultResource("core-site.xml"); 200   } 201   //静态代码块。加载了两个核心配置文件,一个是默认的,一个是用户自己配置的。 202   //如果加载了hadoop-site.xml,则发个警告信息,说它不推荐用,以及推荐用哪个 203   private Properties properties; 204   //Hadoop配置文件解析后的键–值对,都存放在properties中 205   private Properties overlay; 206   //变量overlay用于记录通过set()方式改变的配置项。也就是说,出现在overlay中的键–值对是应用设置的, 207   //而不是通过对配置资源解析得到的 208   private ClassLoader classLoader; 209   { 210     classLoader = Thread.currentThread().getContextClassLoader(); 211     if (classLoader == null) { 212       classLoader = Configuration.class.getClassLoader(); 213     } 214   } 215   //定义了一个类加载器,并做了初始化。非静态代码块 216   /** A new configuration. */ 217   public Configuration() { 218     this(true); 219   } 220   //相当于空构造方法,或者说调用空构造方法的时候默认调用默认配置文件 221   /** A new configuration where the behavior of reading from the default  222    * resources can be turned off. 223    *  224    * If the parameter {@code loadDefaults} is false, the new instance 225    * will not load resources from the default files.  226    * @param loadDefaults specifies whether to load from the default files 227    */ 228   public Configuration(boolean loadDefaults) { 229     this.loadDefaults = loadDefaults; 230     if (LOG.isDebugEnabled()) { 231       LOG.debug(StringUtils.stringifyException(new IOException("config()"))); 232     } 233     synchronized(Configuration.class) { 234       REGISTRY.put(this, null); 235     } 236     this.storeResource = false; 237   } 238   //构造方法。参数是是否加载默认配置文件 239   /** 240    * A new configuration with the same settings and additional facility for 241    * storage of resource to each key which loads or updates  242    * the key most recently 243    * @param other the configuration from which to clone settings 244    * @param storeResource flag to indicate if the storage of resource to  245    * each key is to be stored 246    */ 247   private Configuration(Configuration other, boolean storeResource) { 248     this(other); 249     this.loadDefaults = other.loadDefaults; 250     this.storeResource = storeResource; 251     if (storeResource) { 252       updatingResource = new HashMap<String, String>(); 253     } 254   } 255   //构造方法。加载了一个新的配置文件和现有的配置文件具有相同的一些配置并有一些新的配置 256   /**  257    * A new configuration with the same settings cloned from another. 258    *  259    * @param other the configuration from which to clone settings. 260    */ 261   @SuppressWarnings("unchecked") 262   public Configuration(Configuration other) { 263     if (LOG.isDebugEnabled()) { 264       LOG.debug(StringUtils.stringifyException 265                 (new IOException("config(config)"))); 266     } 267     268    this.resources = (ArrayList)other.resources.clone(); 269    synchronized(other) { 270      if (other.properties != null) { 271        this.properties = (Properties)other.properties.clone(); 272      } 273  274      if (other.overlay!=null) { 275        this.overlay = (Properties)other.overlay.clone(); 276      } 277    } 278     279     this.finalParameters = new HashSet<String>(other.finalParameters); 280     synchronized(Configuration.class) { 281       REGISTRY.put(this, null); 282     } 283   } 284   //构造方法。加载了一个全新的配置文件,并克隆了其属性 285   /** 286    * Add a default resource. Resources are loaded in the order of the resources  287    * added. 288    * @param name file name. File should be present in the classpath. 289    */ 290   public static synchronized void addDefaultResource(String name) { 291     if(!defaultResources.contains(name)) { 292       defaultResources.add(name); 293       for(Configuration conf : REGISTRY.keySet()) { 294         if(conf.loadDefaults) { 295           conf.reloadConfiguration(); 296         } 297       } 298     } 299   } 300   //加载默认配置文件方法 301   /** 302    * Add a configuration resource.  303    *  304    * The properties of this resource will override properties of previously  305    * added resources, unless they were marked <a href="#Final">final</a>.  306    *  307    * @param name resource to be added, the classpath is examined for a file  308    *             with that name. 309    */ 310   public void addResource(String name) { 311     addResourceObject(name); 312   } 313  314   /** 315    * Add a configuration resource.  316    *  317    * The properties of this resource will override properties of previously  318    * added resources, unless they were marked <a href="#Final">final</a>.  319    *  320    * @param url url of the resource to be added, the local filesystem is  321    *            examined directly to find the resource, without referring to  322    *            the classpath. 323    */ 324   public void addResource(URL url) { 325     addResourceObject(url); 326   } 327  328   /** 329    * Add a configuration resource.  330    *  331    * The properties of this resource will override properties of previously  332    * added resources, unless they were marked <a href="#Final">final</a>.  333    *  334    * @param file file-path of resource to be added, the local filesystem is 335    *             examined directly to find the resource, without referring to  336    *             the classpath. 337    */ 338   public void addResource(Path file) { 339     addResourceObject(file); 340   } 341  342   /** 343    * Add a configuration resource.  344    *  345    * The properties of this resource will override properties of previously  346    * added resources, unless they were marked <a href="#Final">final</a>.  347    *  348    * @param in InputStream to deserialize the object from.  349    */ 350   public void addResource(InputStream in) { 351     addResourceObject(in); 352   } 353   //Hadoop在创建配置类的时候,考虑了三种资源:   354   //   355   //URL资源(网络资源,指的是一个链接);   356   //   357   //CLASSPATH资源(String形式);   358   //   359   //Hadoop文件系统中的Path资源(该资源是基于Hadoop的FileSystem的,使用斜线“/”作为分隔符,如果是绝对路径,应该以“/”开始)    360   /** 361    * Reload configuration from previously added resources. 362    * 363    * This method will clear all the configuration read from the added  364    * resources, and final parameters. This will make the resources to  365    * be read again before accessing the values. Values that are added 366    * via set methods will overlay values read from the resources. 367    */ 368   public synchronized void reloadConfiguration() { 369     properties = null;                            // trigger reload 370     finalParameters.clear();                      // clear site-limits 371   } 372   //重新加载先前加载过的配置资源。加载前会先清空。加了线程并发关键字哦 373   private synchronized void addResourceObject(Object resource) { 374     resources.add(resource);                      // add to resources 375     reloadConfiguration(); 376   } 377   //注意resource是Object类型。会触发配置的重新加载 378   private static Pattern varPat = Pattern.compile("\\$\\{[^\\}\\$\u0020]+\\}"); 379   private static int MAX_SUBST = 20; 380  381   private String substituteVars(String expr) { 382     if (expr == null) { 383       return null; 384     } 385     Matcher match = varPat.matcher(""); 386     String eval = expr; 387     for(int s=0; s<MAX_SUBST; s++) { 388       match.reset(eval); 389       if (!match.find()) { 390         return eval; 391       } 392       String var = match.group(); 393       var = var.substring(2, var.length()-1); // remove ${ .. } 394       String val = null; 395       try { 396         val = System.getProperty(var); 397       } catch(SecurityException se) { 398         LOG.warn("Unexpected SecurityException in Configuration", se); 399       } 400       if (val == null) { 401         val = getRaw(var); 402       } 403       if (val == null) { 404         return eval; // return literal ${var}: var is unbound 405       } 406       // substitute 407       eval = eval.substring(0, match.start())+val+eval.substring(match.end()); 408     } 409     throw new IllegalStateException("Variable substitution depth too large: "  410                                     + MAX_SUBST + " " + expr); 411   } 412   //属性扩展属性和方法。 413   //varPat对含有环境变量的值的进行转换的正则表达式对象; 414   //MAX_SUBST是循环次数,为了避免死循环; 415   //当循环次数过多的时候抛异常。 416   /** 417    * Get the value of the <code>name</code> property, <code>null</code> if 418    * no such property exists. 419    *  420    * Values are processed for <a href="#VariableExpansion">variable expansion</a>  421    * before being returned.  422    *  423    * @param name the property name. 424    * @return the value of the <code>name</code> property,  425    *         or null if no such property exists. 426    */ 427   public String get(String name) { 428     return substituteVars(getProps().getProperty(name)); 429   } 430  431   /** 432    * Get the value of the <code>name</code> property, without doing 433    * <a href="#VariableExpansion">variable expansion</a>. 434    *  435    * @param name the property name. 436    * @return the value of the <code>name</code> property,  437    *         or null if no such property exists. 438    */ 439   public String getRaw(String name) { 440     return getProps().getProperty(name); 441   } 442   //两种根据名称取得属性值的方法。没有这个属性就返回NULL。 443   //区别是第一个会进行属性扩展,第二个不会 444   /**  445    * Set the <code>value</code> of the <code>name</code> property. 446    *  447    * @param name property name. 448    * @param value property value. 449    */ 450   public void set(String name, String value) { 451     getOverlay().setProperty(name, value); 452     getProps().setProperty(name, value); 453   } 454    455   /** 456    * Sets a property if it is currently unset. 457    * @param name the property name 458    * @param value the new value 459    */ 460   public void setIfUnset(String name, String value) { 461     if (get(name) == null) { 462       set(name, value); 463     } 464   } 465   //两种根据名称设置值得方法。区别不解释 466   private synchronized Properties getOverlay() { 467     if (overlay==null){ 468       overlay=new Properties(); 469     } 470     return overlay; 471   } 472  473   /**  474    * Get the value of the <code>name</code> property. If no such property  475    * exists, then <code>defaultValue</code> is returned. 476    *  477    * @param name property name. 478    * @param defaultValue default value. 479    * @return property value, or <code>defaultValue</code> if the property  480    *         doesn't exist.                     481    */ 482   public String get(String name, String defaultValue) { 483     return substituteVars(getProps().getProperty(name, defaultValue)); 484   } 485      486   /**  487    * Get the value of the <code>name</code> property as an <code>int</code>. 488    *    489    * If no such property exists, or if the specified value is not a valid 490    * <code>int</code>, then <code>defaultValue</code> is returned. 491    *  492    * @param name property name. 493    * @param defaultValue default value. 494    * @return property value as an <code>int</code>,  495    *         or <code>defaultValue</code>.  496    */ 497   public int getInt(String name, int defaultValue) { 498     String valueString = get(name); 499     if (valueString == null) 500       return defaultValue; 501     try { 502       String hexString = getHexDigits(valueString); 503       if (hexString != null) { 504         return Integer.parseInt(hexString, 16); 505       } 506       return Integer.parseInt(valueString); 507     } catch (NumberFormatException e) { 508       return defaultValue; 509     } 510   } 511  512   /**  513    * Set the value of the <code>name</code> property to an <code>int</code>. 514    *  515    * @param name property name. 516    * @param value <code>int</code> value of the property. 517    */ 518   public void setInt(String name, int value) { 519     set(name, Integer.toString(value)); 520   } 521  522  523   /**  524    * Get the value of the <code>name</code> property as a <code>long</code>.   525    * If no such property is specified, or if the specified value is not a valid 526    * <code>long</code>, then <code>defaultValue</code> is returned. 527    *  528    * @param name property name. 529    * @param defaultValue default value. 530    * @return property value as a <code>long</code>,  531    *         or <code>defaultValue</code>.  532    */ 533   public long getLong(String name, long defaultValue) { 534     String valueString = get(name); 535     if (valueString == null) 536       return defaultValue; 537     try { 538       String hexString = getHexDigits(valueString); 539       if (hexString != null) { 540         return Long.parseLong(hexString, 16); 541       } 542       return Long.parseLong(valueString); 543     } catch (NumberFormatException e) { 544       return defaultValue; 545     } 546   } 547  548   private String getHexDigits(String value) { 549     boolean negative = false; 550     String str = value; 551     String hexString = null; 552     if (value.startsWith("-")) { 553       negative = true; 554       str = value.substring(1); 555     } 556     if (str.startsWith("0x") || str.startsWith("0X")) { 557       hexString = str.substring(2); 558       if (negative) { 559         hexString = "-" + hexString; 560       } 561       return hexString; 562     } 563     return null; 564   } 565    566   /**  567    * Set the value of the <code>name</code> property to a <code>long</code>. 568    *  569    * @param name property name. 570    * @param value <code>long</code> value of the property. 571    */ 572   public void setLong(String name, long value) { 573     set(name, Long.toString(value)); 574   } 575  576   /**  577    * Get the value of the <code>name</code> property as a <code>float</code>.   578    * If no such property is specified, or if the specified value is not a valid 579    * <code>float</code>, then <code>defaultValue</code> is returned. 580    *  581    * @param name property name. 582    * @param defaultValue default value. 583    * @return property value as a <code>float</code>,  584    *         or <code>defaultValue</code>.  585    */ 586   public float getFloat(String name, float defaultValue) { 587     String valueString = get(name); 588     if (valueString == null) 589       return defaultValue; 590     try { 591       return Float.parseFloat(valueString); 592     } catch (NumberFormatException e) { 593       return defaultValue; 594     } 595   } 596   /** 597    * Set the value of the <code>name</code> property to a <code>float</code>. 598    *  599    * @param name property name. 600    * @param value property value. 601    */ 602   public void setFloat(String name, float value) { 603     set(name,Float.toString(value)); 604   } 605   606   /**  607    * Get the value of the <code>name</code> property as a <code>boolean</code>.   608    * If no such property is specified, or if the specified value is not a valid 609    * <code>boolean</code>, then <code>defaultValue</code> is returned. 610    *  611    * @param name property name. 612    * @param defaultValue default value. 613    * @return property value as a <code>boolean</code>,  614    *         or <code>defaultValue</code>.  615    */ 616   public boolean getBoolean(String name, boolean defaultValue) { 617     String valueString = get(name); 618     if ("true".equals(valueString)) 619       return true; 620     else if ("false".equals(valueString)) 621       return false; 622     else return defaultValue; 623   } 624  625   /**  626    * Set the value of the <code>name</code> property to a <code>boolean</code>. 627    *  628    * @param name property name. 629    * @param value <code>boolean</code> value of the property. 630    */ 631   public void setBoolean(String name, boolean value) { 632     set(name, Boolean.toString(value)); 633   } 634  635   /** 636    * Set the given property, if it is currently unset. 637    * @param name property name 638    * @param value new value 639    */ 640   public void setBooleanIfUnset(String name, boolean value) { 641     setIfUnset(name, Boolean.toString(value)); 642   } 643  644   /** 645    * Set the value of the <code>name</code> property to the given type. This 646    * is equivalent to <code>set(&lt;name&gt;, value.toString())</code>. 647    * @param name property name 648    * @param value new value 649    */ 650   public <T extends Enum<T>> void setEnum(String name, T value) { 651     set(name, value.toString()); 652   } 653  654   /** 655    * Return value matching this enumerated type. 656    * @param name Property name 657    * @param defaultValue Value returned if no mapping exists 658    * @throws IllegalArgumentException If mapping is illegal for the type 659    * provided 660    */ 661   public <T extends Enum<T>> T getEnum(String name, T defaultValue) { 662     final String val = get(name); 663     return null == val 664       ? defaultValue 665       : Enum.valueOf(defaultValue.getDeclaringClass(), val); 666   } 667   //hadoop常用类型的get/set方法,其中有的做了转换。 668   /** 669    * A class that represents a set of positive integer ranges. It parses  670    * strings of the form: "2-3,5,7-" where ranges are separated by comma and  671    * the lower/upper bounds are separated by dash. Either the lower or upper  672    * bound may be omitted meaning all values up to or over. So the string  673    * above means 2, 3, 5, and 7, 8, 9, ... 674    */ 675   public static class IntegerRanges { 676     private static class Range { 677       int start; 678       int end; 679     } 680  681     List<Range> ranges = new ArrayList<Range>(); 682      683     public IntegerRanges() { 684     } 685      686     public IntegerRanges(String newValue) { 687       StringTokenizer itr = new StringTokenizer(newValue, ","); 688       while (itr.hasMoreTokens()) { 689         String rng = itr.nextToken().trim(); 690         String[] parts = rng.split("-", 3); 691         if (parts.length < 1 || parts.length > 2) { 692           throw new IllegalArgumentException("integer range badly formed: " +  693                                              rng); 694         } 695         Range r = new Range(); 696         r.start = convertToInt(parts[0], 0); 697         if (parts.length == 2) { 698           r.end = convertToInt(parts[1], Integer.MAX_VALUE); 699         } else { 700           r.end = r.start; 701         } 702         if (r.start > r.end) { 703           throw new IllegalArgumentException("IntegerRange from " + r.start +  704                                              " to " + r.end + " is invalid"); 705         } 706         ranges.add(r); 707       } 708     } 709     //嵌套类。所以org.apache.hadoop.conf包中有四个类。 710     //解释一种字符串表示的整数范围。注释中有例子。 711     /** 712      * Convert a string to an int treating empty strings as the default value. 713      * @param value the string value 714      * @param defaultValue the value for if the string is empty 715      * @return the desired integer 716      */ 717     private static int convertToInt(String value, int defaultValue) { 718       String trim = value.trim(); 719       if (trim.length() == 0) { 720         return defaultValue; 721       } 722       return Integer.parseInt(trim); 723     } 724     //字符串转整数方法。如果是空的就是用默认值 725     /** 726      * Is the given value in the set of ranges 727      * @param value the value to check 728      * @return is the value in the ranges? 729      */ 730     public boolean isIncluded(int value) { 731       for(Range r: ranges) { 732         if (r.start <= value && value <= r.end) { 733           return true; 734         } 735       } 736       return false; 737     } 738     //不解释 739     @Override 740     public String toString() { 741       StringBuffer result = new StringBuffer(); 742       boolean first = true; 743       for(Range r: ranges) { 744         if (first) { 745           first = false; 746         } else { 747           result.append(','); 748         } 749         result.append(r.start); 750         result.append('-'); 751         result.append(r.end); 752       } 753       return result.toString(); 754     } 755   } 756   //重写了toString方法 757   /** 758    * Parse the given attribute as a set of integer ranges 759    * @param name the attribute name 760    * @param defaultValue the default value if it is not set 761    * @return a new set of ranges from the configured value 762    */ 763   public IntegerRanges getRange(String name, String defaultValue) { 764     return new IntegerRanges(get(name, defaultValue)); 765   } 766  767   /**  768    * Get the comma delimited values of the <code>name</code> property as  769    * a collection of <code>String</code>s.   770    * If no such property is specified then empty collection is returned. 771    * <p> 772    * This is an optimized version of {@link #getStrings(String)} 773    *  774    * @param name property name. 775    * @return property value as a collection of <code>String</code>s.  776    */ 777   public Collection<String> getStringCollection(String name) { 778     String valueString = get(name); 779     return StringUtils.getStringCollection(valueString); 780   } 781  782   /**  783    * Get the comma delimited values of the <code>name</code> property as  784    * an array of <code>String</code>s.   785    * If no such property is specified then <code>null</code> is returned. 786    *  787    * @param name property name. 788    * @return property value as an array of <code>String</code>s,  789    *         or <code>null</code>.  790    */ 791   public String[] getStrings(String name) { 792     String valueString = get(name); 793     return StringUtils.getStrings(valueString); 794   } 795  796   /**  797    * Get the comma delimited values of the <code>name</code> property as  798    * an array of <code>String</code>s.   799    * If no such property is specified then default value is returned. 800    *  801    * @param name property name. 802    * @param defaultValue The default value 803    * @return property value as an array of <code>String</code>s,  804    *         or default value.  805    */ 806   public String[] getStrings(String name, String... defaultValue) { 807     String valueString = get(name); 808     if (valueString == null) { 809       return defaultValue; 810     } else { 811       return StringUtils.getStrings(valueString); 812     } 813   } 814  815   /**  816    * Set the array of string values for the <code>name</code> property as  817    * as comma delimited values.   818    *  819    * @param name property name. 820    * @param values The values 821    */ 822   public void setStrings(String name, String... values) { 823     set(name, StringUtils.arrayToString(values)); 824   } 825   826   /** 827    * Load a class by name. 828    *  829    * @param name the class name. 830    * @return the class object. 831    * @throws ClassNotFoundException if the class is not found. 832    */ 833   public Class<?> getClassByName(String name) throws ClassNotFoundException { 834