001 /** 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018 019 package org.apache.hadoop.conf; 020 021 import java.io.BufferedInputStream; 022 import java.io.DataInput; 023 import java.io.DataOutput; 024 import java.io.File; 025 import java.io.FileInputStream; 026 import java.io.IOException; 027 import java.io.InputStream; 028 import java.io.InputStreamReader; 029 import java.io.OutputStream; 030 import java.io.OutputStreamWriter; 031 import java.io.Reader; 032 import java.io.Writer; 033 import java.net.InetSocketAddress; 034 import java.net.URL; 035 import java.util.ArrayList; 036 import java.util.Arrays; 037 import java.util.Collection; 038 import java.util.Collections; 039 import java.util.Enumeration; 040 import java.util.HashMap; 041 import java.util.HashSet; 042 import java.util.Iterator; 043 import java.util.LinkedList; 044 import java.util.List; 045 import java.util.ListIterator; 046 import java.util.Map; 047 import java.util.Map.Entry; 048 import java.util.Properties; 049 import java.util.Set; 050 import java.util.StringTokenizer; 051 import java.util.WeakHashMap; 052 import java.util.concurrent.CopyOnWriteArrayList; 053 import java.util.regex.Matcher; 054 import java.util.regex.Pattern; 055 import java.util.regex.PatternSyntaxException; 056 057 import javax.xml.parsers.DocumentBuilder; 058 import javax.xml.parsers.DocumentBuilderFactory; 059 import javax.xml.parsers.ParserConfigurationException; 060 import javax.xml.transform.Transformer; 061 import javax.xml.transform.TransformerException; 062 import javax.xml.transform.TransformerFactory; 063 import javax.xml.transform.dom.DOMSource; 064 import javax.xml.transform.stream.StreamResult; 065 066 import org.apache.commons.logging.Log; 067 import org.apache.commons.logging.LogFactory; 068 import org.apache.hadoop.classification.InterfaceAudience; 069 import org.apache.hadoop.classification.InterfaceStability; 070 import org.apache.hadoop.fs.FileSystem; 071 import org.apache.hadoop.fs.Path; 072 import org.apache.hadoop.fs.CommonConfigurationKeys; 073 import org.apache.hadoop.io.Writable; 074 import org.apache.hadoop.io.WritableUtils; 075 import org.apache.hadoop.net.NetUtils; 076 import org.apache.hadoop.util.ReflectionUtils; 077 import org.apache.hadoop.util.StringInterner; 078 import org.apache.hadoop.util.StringUtils; 079 import org.codehaus.jackson.JsonFactory; 080 import org.codehaus.jackson.JsonGenerator; 081 import org.w3c.dom.DOMException; 082 import org.w3c.dom.Document; 083 import org.w3c.dom.Element; 084 import org.w3c.dom.Node; 085 import org.w3c.dom.NodeList; 086 import org.w3c.dom.Text; 087 import org.xml.sax.SAXException; 088 089 /** 090 * Provides access to configuration parameters. 091 * 092 * <h4 id="Resources">Resources</h4> 093 * 094 * <p>Configurations are specified by resources. A resource contains a set of 095 * name/value pairs as XML data. Each resource is named by either a 096 * <code>String</code> or by a {@link Path}. If named by a <code>String</code>, 097 * then the classpath is examined for a file with that name. If named by a 098 * <code>Path</code>, then the local filesystem is examined directly, without 099 * referring to the classpath. 100 * 101 * <p>Unless explicitly turned off, Hadoop by default specifies two 102 * resources, loaded in-order from the classpath: <ol> 103 * <li><tt><a href="{@docRoot}/../core-default.html">core-default.xml</a> 104 * </tt>: Read-only defaults for hadoop.</li> 105 * <li><tt>core-site.xml</tt>: Site-specific configuration for a given hadoop 106 * installation.</li> 107 * </ol> 108 * Applications may add additional resources, which are loaded 109 * subsequent to these resources in the order they are added. 110 * 111 * <h4 id="FinalParams">Final Parameters</h4> 112 * 113 * <p>Configuration parameters may be declared <i>final</i>. 114 * Once a resource declares a value final, no subsequently-loaded 115 * resource can alter that value. 116 * For example, one might define a final parameter with: 117 * <tt><pre> 118 * <property> 119 * <name>dfs.client.buffer.dir</name> 120 * <value>/tmp/hadoop/dfs/client</value> 121 * <b><final>true</final></b> 122 * </property></pre></tt> 123 * 124 * Administrators typically define parameters as final in 125 * <tt>core-site.xml</tt> for values that user applications may not alter. 126 * 127 * <h4 id="VariableExpansion">Variable Expansion</h4> 128 * 129 * <p>Value strings are first processed for <i>variable expansion</i>. The 130 * available properties are:<ol> 131 * <li>Other properties defined in this Configuration; and, if a name is 132 * undefined here,</li> 133 * <li>Properties in {@link System#getProperties()}.</li> 134 * </ol> 135 * 136 * <p>For example, if a configuration resource contains the following property 137 * definitions: 138 * <tt><pre> 139 * <property> 140 * <name>basedir</name> 141 * <value>/user/${<i>user.name</i>}</value> 142 * </property> 143 * 144 * <property> 145 * <name>tempdir</name> 146 * <value>${<i>basedir</i>}/tmp</value> 147 * </property></pre></tt> 148 * 149 * When <tt>conf.get("tempdir")</tt> is called, then <tt>${<i>basedir</i>}</tt> 150 * will be resolved to another property in this Configuration, while 151 * <tt>${<i>user.name</i>}</tt> would then ordinarily be resolved to the value 152 * of the System property with that name. 153 */ 154 @InterfaceAudience.Public 155 @InterfaceStability.Stable 156 public class Configuration implements Iterable<Map.Entry<String,String>>, 157 Writable { 158 private static final Log LOG = 159 LogFactory.getLog(Configuration.class); 160 161 private boolean quietmode = true; 162 163 private static class Resource { 164 private final Object resource; 165 private final String name; 166 167 public Resource(Object resource) { 168 this(resource, resource.toString()); 169 } 170 171 public Resource(Object resource, String name) { 172 this.resource = resource; 173 this.name = name; 174 } 175 176 public String getName(){ 177 return name; 178 } 179 180 public Object getResource() { 181 return resource; 182 } 183 184 @Override 185 public String toString() { 186 return name; 187 } 188 } 189 190 /** 191 * List of configuration resources. 192 */ 193 private ArrayList<Resource> resources = new ArrayList<Resource>(); 194 195 /** 196 * The value reported as the setting resource when a key is set 197 * by code rather than a file resource by dumpConfiguration. 198 */ 199 static final String UNKNOWN_RESOURCE = "Unknown"; 200 201 202 /** 203 * List of configuration parameters marked <b>final</b>. 204 */ 205 private Set<String> finalParameters = new HashSet<String>(); 206 207 private boolean loadDefaults = true; 208 209 /** 210 * Configuration objects 211 */ 212 private static final WeakHashMap<Configuration,Object> REGISTRY = 213 new WeakHashMap<Configuration,Object>(); 214 215 /** 216 * List of default Resources. Resources are loaded in the order of the list 217 * entries 218 */ 219 private static final CopyOnWriteArrayList<String> defaultResources = 220 new CopyOnWriteArrayList<String>(); 221 222 private static final Map<ClassLoader, Map<String, Class<?>>> 223 CACHE_CLASSES = new WeakHashMap<ClassLoader, Map<String, Class<?>>>(); 224 225 /** 226 * Stores the mapping of key to the resource which modifies or loads 227 * the key most recently 228 */ 229 private HashMap<String, String[]> updatingResource; 230 231 /** 232 * Class to keep the information about the keys which replace the deprecated 233 * ones. 234 * 235 * This class stores the new keys which replace the deprecated keys and also 236 * gives a provision to have a custom message for each of the deprecated key 237 * that is being replaced. It also provides method to get the appropriate 238 * warning message which can be logged whenever the deprecated key is used. 239 */ 240 private static class DeprecatedKeyInfo { 241 private String[] newKeys; 242 private String customMessage; 243 private boolean accessed; 244 DeprecatedKeyInfo(String[] newKeys, String customMessage) { 245 this.newKeys = newKeys; 246 this.customMessage = customMessage; 247 accessed = false; 248 } 249 250 /** 251 * Method to provide the warning message. It gives the custom message if 252 * non-null, and default message otherwise. 253 * @param key the associated deprecated key. 254 * @return message that is to be logged when a deprecated key is used. 255 */ 256 private final String getWarningMessage(String key) { 257 String warningMessage; 258 if(customMessage == null) { 259 StringBuilder message = new StringBuilder(key); 260 String deprecatedKeySuffix = " is deprecated. Instead, use "; 261 message.append(deprecatedKeySuffix); 262 for (int i = 0; i < newKeys.length; i++) { 263 message.append(newKeys[i]); 264 if(i != newKeys.length-1) { 265 message.append(", "); 266 } 267 } 268 warningMessage = message.toString(); 269 } 270 else { 271 warningMessage = customMessage; 272 } 273 accessed = true; 274 return warningMessage; 275 } 276 } 277 278 /** 279 * Stores the deprecated keys, the new keys which replace the deprecated keys 280 * and custom message(if any provided). 281 */ 282 private static Map<String, DeprecatedKeyInfo> deprecatedKeyMap = 283 new HashMap<String, DeprecatedKeyInfo>(); 284 285 /** 286 * Stores a mapping from superseding keys to the keys which they deprecate. 287 */ 288 private static Map<String, String> reverseDeprecatedKeyMap = 289 new HashMap<String, String>(); 290 291 /** 292 * Adds the deprecated key to the deprecation map. 293 * It does not override any existing entries in the deprecation map. 294 * This is to be used only by the developers in order to add deprecation of 295 * keys, and attempts to call this method after loading resources once, 296 * would lead to <tt>UnsupportedOperationException</tt> 297 * 298 * If a key is deprecated in favor of multiple keys, they are all treated as 299 * aliases of each other, and setting any one of them resets all the others 300 * to the new value. 301 * 302 * @param key 303 * @param newKeys 304 * @param customMessage 305 * @deprecated use {@link addDeprecation(String key, String newKey, 306 String customMessage)} instead 307 */ 308 @Deprecated 309 public synchronized static void addDeprecation(String key, String[] newKeys, 310 String customMessage) { 311 if (key == null || key.length() == 0 || 312 newKeys == null || newKeys.length == 0) { 313 throw new IllegalArgumentException(); 314 } 315 if (!isDeprecated(key)) { 316 DeprecatedKeyInfo newKeyInfo; 317 newKeyInfo = new DeprecatedKeyInfo(newKeys, customMessage); 318 deprecatedKeyMap.put(key, newKeyInfo); 319 for (String newKey : newKeys) { 320 reverseDeprecatedKeyMap.put(newKey, key); 321 } 322 } 323 } 324 325 /** 326 * Adds the deprecated key to the deprecation map. 327 * It does not override any existing entries in the deprecation map. 328 * This is to be used only by the developers in order to add deprecation of 329 * keys, and attempts to call this method after loading resources once, 330 * would lead to <tt>UnsupportedOperationException</tt> 331 * 332 * @param key 333 * @param newKey 334 * @param customMessage 335 */ 336 public synchronized static void addDeprecation(String key, String newKey, 337 String customMessage) { 338 addDeprecation(key, new String[] {newKey}, customMessage); 339 } 340 341 /** 342 * Adds the deprecated key to the deprecation map when no custom message 343 * is provided. 344 * It does not override any existing entries in the deprecation map. 345 * This is to be used only by the developers in order to add deprecation of 346 * keys, and attempts to call this method after loading resources once, 347 * would lead to <tt>UnsupportedOperationException</tt> 348 * 349 * If a key is deprecated in favor of multiple keys, they are all treated as 350 * aliases of each other, and setting any one of them resets all the others 351 * to the new value. 352 * 353 * @param key Key that is to be deprecated 354 * @param newKeys list of keys that take up the values of deprecated key 355 * @deprecated use {@link addDeprecation(String key, String newKey)} instead 356 */ 357 @Deprecated 358 public synchronized static void addDeprecation(String key, String[] newKeys) { 359 addDeprecation(key, newKeys, null); 360 } 361 362 /** 363 * Adds the deprecated key to the deprecation map when no custom message 364 * is provided. 365 * It does not override any existing entries in the deprecation map. 366 * This is to be used only by the developers in order to add deprecation of 367 * keys, and attempts to call this method after loading resources once, 368 * would lead to <tt>UnsupportedOperationException</tt> 369 * 370 * @param key Key that is to be deprecated 371 * @param newKey key that takes up the value of deprecated key 372 */ 373 public synchronized static void addDeprecation(String key, String newKey) { 374 addDeprecation(key, new String[] {newKey}, null); 375 } 376 377 /** 378 * checks whether the given <code>key</code> is deprecated. 379 * 380 * @param key the parameter which is to be checked for deprecation 381 * @return <code>true</code> if the key is deprecated and 382 * <code>false</code> otherwise. 383 */ 384 public static boolean isDeprecated(String key) { 385 return deprecatedKeyMap.containsKey(key); 386 } 387 388 /** 389 * Returns the alternate name for a key if the property name is deprecated 390 * or if deprecates a property name. 391 * 392 * @param name property name. 393 * @return alternate name. 394 */ 395 private String[] getAlternateNames(String name) { 396 String oldName, altNames[] = null; 397 DeprecatedKeyInfo keyInfo = deprecatedKeyMap.get(name); 398 if (keyInfo == null) { 399 altNames = (reverseDeprecatedKeyMap.get(name) != null ) ? 400 new String [] {reverseDeprecatedKeyMap.get(name)} : null; 401 if(altNames != null && altNames.length > 0) { 402 //To help look for other new configs for this deprecated config 403 keyInfo = deprecatedKeyMap.get(altNames[0]); 404 } 405 } 406 if(keyInfo != null && keyInfo.newKeys.length > 0) { 407 List<String> list = new ArrayList<String>(); 408 if(altNames != null) { 409 list.addAll(Arrays.asList(altNames)); 410 } 411 list.addAll(Arrays.asList(keyInfo.newKeys)); 412 altNames = list.toArray(new String[list.size()]); 413 } 414 return altNames; 415 } 416 417 /** 418 * Checks for the presence of the property <code>name</code> in the 419 * deprecation map. Returns the first of the list of new keys if present 420 * in the deprecation map or the <code>name</code> itself. If the property 421 * is not presently set but the property map contains an entry for the 422 * deprecated key, the value of the deprecated key is set as the value for 423 * the provided property name. 424 * 425 * @param name the property name 426 * @return the first property in the list of properties mapping 427 * the <code>name</code> or the <code>name</code> itself. 428 */ 429 private String[] handleDeprecation(String name) { 430 ArrayList<String > names = new ArrayList<String>(); 431 if (isDeprecated(name)) { 432 DeprecatedKeyInfo keyInfo = deprecatedKeyMap.get(name); 433 warnOnceIfDeprecated(name); 434 for (String newKey : keyInfo.newKeys) { 435 if(newKey != null) { 436 names.add(newKey); 437 } 438 } 439 } 440 if(names.size() == 0) { 441 names.add(name); 442 } 443 for(String n : names) { 444 String deprecatedKey = reverseDeprecatedKeyMap.get(n); 445 if (deprecatedKey != null && !getOverlay().containsKey(n) && 446 getOverlay().containsKey(deprecatedKey)) { 447 getProps().setProperty(n, getOverlay().getProperty(deprecatedKey)); 448 getOverlay().setProperty(n, getOverlay().getProperty(deprecatedKey)); 449 } 450 } 451 return names.toArray(new String[names.size()]); 452 } 453 454 private void handleDeprecation() { 455 LOG.debug("Handling deprecation for all properties in config..."); 456 Set<Object> keys = new HashSet<Object>(); 457 keys.addAll(getProps().keySet()); 458 for (Object item: keys) { 459 LOG.debug("Handling deprecation for " + (String)item); 460 handleDeprecation((String)item); 461 } 462 } 463 464 static{ 465 //print deprecation warning if hadoop-site.xml is found in classpath 466 ClassLoader cL = Thread.currentThread().getContextClassLoader(); 467 if (cL == null) { 468 cL = Configuration.class.getClassLoader(); 469 } 470 if(cL.getResource("hadoop-site.xml")!=null) { 471 LOG.warn("DEPRECATED: hadoop-site.xml found in the classpath. " + 472 "Usage of hadoop-site.xml is deprecated. Instead use core-site.xml, " 473 + "mapred-site.xml and hdfs-site.xml to override properties of " + 474 "core-default.xml, mapred-default.xml and hdfs-default.xml " + 475 "respectively"); 476 } 477 addDefaultResource("core-default.xml"); 478 addDefaultResource("core-site.xml"); 479 //Add code for managing deprecated key mapping 480 //for example 481 //addDeprecation("oldKey1",new String[]{"newkey1","newkey2"}); 482 //adds deprecation for oldKey1 to two new keys(newkey1, newkey2). 483 //so get or set of oldKey1 will correctly populate/access values of 484 //newkey1 and newkey2 485 addDeprecatedKeys(); 486 } 487 488 private Properties properties; 489 private Properties overlay; 490 private ClassLoader classLoader; 491 { 492 classLoader = Thread.currentThread().getContextClassLoader(); 493 if (classLoader == null) { 494 classLoader = Configuration.class.getClassLoader(); 495 } 496 } 497 498 /** A new configuration. */ 499 public Configuration() { 500 this(true); 501 } 502 503 /** A new configuration where the behavior of reading from the default 504 * resources can be turned off. 505 * 506 * If the parameter {@code loadDefaults} is false, the new instance 507 * will not load resources from the default files. 508 * @param loadDefaults specifies whether to load from the default files 509 */ 510 public Configuration(boolean loadDefaults) { 511 this.loadDefaults = loadDefaults; 512 updatingResource = new HashMap<String, String[]>(); 513 synchronized(Configuration.class) { 514 REGISTRY.put(this, null); 515 } 516 } 517 518 /** 519 * A new configuration with the same settings cloned from another. 520 * 521 * @param other the configuration from which to clone settings. 522 */ 523 @SuppressWarnings("unchecked") 524 public Configuration(Configuration other) { 525 this.resources = (ArrayList<Resource>) other.resources.clone(); 526 synchronized(other) { 527 if (other.properties != null) { 528 this.properties = (Properties)other.properties.clone(); 529 } 530 531 if (other.overlay!=null) { 532 this.overlay = (Properties)other.overlay.clone(); 533 } 534 535 this.updatingResource = new HashMap<String, String[]>(other.updatingResource); 536 } 537 538 this.finalParameters = new HashSet<String>(other.finalParameters); 539 synchronized(Configuration.class) { 540 REGISTRY.put(this, null); 541 } 542 this.classLoader = other.classLoader; 543 this.loadDefaults = other.loadDefaults; 544 setQuietMode(other.getQuietMode()); 545 } 546 547 /** 548 * Add a default resource. Resources are loaded in the order of the resources 549 * added. 550 * @param name file name. File should be present in the classpath. 551 */ 552 public static synchronized void addDefaultResource(String name) { 553 if(!defaultResources.contains(name)) { 554 defaultResources.add(name); 555 for(Configuration conf : REGISTRY.keySet()) { 556 if(conf.loadDefaults) { 557 conf.reloadConfiguration(); 558 } 559 } 560 } 561 } 562 563 /** 564 * Add a configuration resource. 565 * 566 * The properties of this resource will override properties of previously 567 * added resources, unless they were marked <a href="#Final">final</a>. 568 * 569 * @param name resource to be added, the classpath is examined for a file 570 * with that name. 571 */ 572 public void addResource(String name) { 573 addResourceObject(new Resource(name)); 574 } 575 576 /** 577 * Add a configuration resource. 578 * 579 * The properties of this resource will override properties of previously 580 * added resources, unless they were marked <a href="#Final">final</a>. 581 * 582 * @param url url of the resource to be added, the local filesystem is 583 * examined directly to find the resource, without referring to 584 * the classpath. 585 */ 586 public void addResource(URL url) { 587 addResourceObject(new Resource(url)); 588 } 589 590 /** 591 * Add a configuration resource. 592 * 593 * The properties of this resource will override properties of previously 594 * added resources, unless they were marked <a href="#Final">final</a>. 595 * 596 * @param file file-path of resource to be added, the local filesystem is 597 * examined directly to find the resource, without referring to 598 * the classpath. 599 */ 600 public void addResource(Path file) { 601 addResourceObject(new Resource(file)); 602 } 603 604 /** 605 * Add a configuration resource. 606 * 607 * The properties of this resource will override properties of previously 608 * added resources, unless they were marked <a href="#Final">final</a>. 609 * 610 * WARNING: The contents of the InputStream will be cached, by this method. 611 * So use this sparingly because it does increase the memory consumption. 612 * 613 * @param in InputStream to deserialize the object from. In will be read from 614 * when a get or set is called next. After it is read the stream will be 615 * closed. 616 */ 617 public void addResource(InputStream in) { 618 addResourceObject(new Resource(in)); 619 } 620 621 /** 622 * Add a configuration resource. 623 * 624 * The properties of this resource will override properties of previously 625 * added resources, unless they were marked <a href="#Final">final</a>. 626 * 627 * @param in InputStream to deserialize the object from. 628 * @param name the name of the resource because InputStream.toString is not 629 * very descriptive some times. 630 */ 631 public void addResource(InputStream in, String name) { 632 addResourceObject(new Resource(in, name)); 633 } 634 635 636 /** 637 * Reload configuration from previously added resources. 638 * 639 * This method will clear all the configuration read from the added 640 * resources, and final parameters. This will make the resources to 641 * be read again before accessing the values. Values that are added 642 * via set methods will overlay values read from the resources. 643 */ 644 public synchronized void reloadConfiguration() { 645 properties = null; // trigger reload 646 finalParameters.clear(); // clear site-limits 647 } 648 649 private synchronized void addResourceObject(Resource resource) { 650 resources.add(resource); // add to resources 651 reloadConfiguration(); 652 } 653 654 private static Pattern varPat = Pattern.compile("\\$\\{[^\\}\\$\u0020]+\\}"); 655 private static int MAX_SUBST = 20; 656 657 private String substituteVars(String expr) { 658 if (expr == null) { 659 return null; 660 } 661 Matcher match = varPat.matcher(""); 662 String eval = expr; 663 for(int s=0; s<MAX_SUBST; s++) { 664 match.reset(eval); 665 if (!match.find()) { 666 return eval; 667 } 668 String var = match.group(); 669 var = var.substring(2, var.length()-1); // remove ${ .. } 670 String val = null; 671 try { 672 val = System.getProperty(var); 673 } catch(SecurityException se) { 674 LOG.warn("Unexpected SecurityException in Configuration", se); 675 } 676 if (val == null) { 677 val = getRaw(var); 678 } 679 if (val == null) { 680 return eval; // return literal ${var}: var is unbound 681 } 682 // substitute 683 eval = eval.substring(0, match.start())+val+eval.substring(match.end()); 684 } 685 throw new IllegalStateException("Variable substitution depth too large: " 686 + MAX_SUBST + " " + expr); 687 } 688 689 /** 690 * Get the value of the <code>name</code> property, <code>null</code> if 691 * no such property exists. If the key is deprecated, it returns the value of 692 * the first key which replaces the deprecated key and is not null 693 * 694 * Values are processed for <a href="#VariableExpansion">variable expansion</a> 695 * before being returned. 696 * 697 * @param name the property name. 698 * @return the value of the <code>name</code> or its replacing property, 699 * or null if no such property exists. 700 */ 701 public String get(String name) { 702 String[] names = handleDeprecation(name); 703 String result = null; 704 for(String n : names) { 705 result = substituteVars(getProps().getProperty(n)); 706 } 707 return result; 708 } 709 710 /** 711 * Get the value of the <code>name</code> property as a trimmed <code>String</code>, 712 * <code>null</code> if no such property exists. 713 * If the key is deprecated, it returns the value of 714 * the first key which replaces the deprecated key and is not null 715 * 716 * Values are processed for <a href="#VariableExpansion">variable expansion</a> 717 * before being returned. 718 * 719 * @param name the property name. 720 * @return the value of the <code>name</code> or its replacing property, 721 * or null if no such property exists. 722 */ 723 public String getTrimmed(String name) { 724 String value = get(name); 725 726 if (null == value) { 727 return null; 728 } else { 729 return value.trim(); 730 } 731 } 732 733 /** 734 * Get the value of the <code>name</code> property, without doing 735 * <a href="#VariableExpansion">variable expansion</a>.If the key is 736 * deprecated, it returns the value of the first key which replaces 737 * the deprecated key and is not null. 738 * 739 * @param name the property name. 740 * @return the value of the <code>name</code> property or 741 * its replacing property and null if no such property exists. 742 */ 743 public String getRaw(String name) { 744 String[] names = handleDeprecation(name); 745 String result = null; 746 for(String n : names) { 747 result = getProps().getProperty(n); 748 } 749 return result; 750 } 751 752 /** 753 * Set the <code>value</code> of the <code>name</code> property. If 754 * <code>name</code> is deprecated or there is a deprecated name associated to it, 755 * it sets the value to both names. 756 * 757 * @param name property name. 758 * @param value property value. 759 */ 760 public void set(String name, String value) { 761 set(name, value, null); 762 } 763 764 /** 765 * Set the <code>value</code> of the <code>name</code> property. If 766 * <code>name</code> is deprecated or there is a deprecated name associated to it, 767 * it sets the value to both names. 768 * 769 * @param name property name. 770 * @param value property value. 771 * @param source the place that this configuration value came from 772 * (For debugging). 773 */ 774 public void set(String name, String value, String source) { 775 if (deprecatedKeyMap.isEmpty()) { 776 getProps(); 777 } 778 getOverlay().setProperty(name, value); 779 getProps().setProperty(name, value); 780 if(source == null) { 781 updatingResource.put(name, new String[] {"programatically"}); 782 } else { 783 updatingResource.put(name, new String[] {source}); 784 } 785 String[] altNames = getAlternateNames(name); 786 if (altNames != null && altNames.length > 0) { 787 String altSource = "because " + name + " is deprecated"; 788 for(String altName : altNames) { 789 if(!altName.equals(name)) { 790 getOverlay().setProperty(altName, value); 791 getProps().setProperty(altName, value); 792 updatingResource.put(altName, new String[] {altSource}); 793 } 794 } 795 } 796 warnOnceIfDeprecated(name); 797 } 798 799 private void warnOnceIfDeprecated(String name) { 800 DeprecatedKeyInfo keyInfo = deprecatedKeyMap.get(name); 801 if (keyInfo != null && !keyInfo.accessed) { 802 LOG.warn(keyInfo.getWarningMessage(name)); 803 } 804 } 805 806 /** 807 * Unset a previously set property. 808 */ 809 public synchronized void unset(String name) { 810 String[] altNames = getAlternateNames(name); 811 getOverlay().remove(name); 812 getProps().remove(name); 813 if (altNames !=null && altNames.length > 0) { 814 for(String altName : altNames) { 815 getOverlay().remove(altName); 816 getProps().remove(altName); 817 } 818 } 819 } 820 821 /** 822 * Sets a property if it is currently unset. 823 * @param name the property name 824 * @param value the new value 825 */ 826 public synchronized void setIfUnset(String name, String value) { 827 if (get(name) == null) { 828 set(name, value); 829 } 830 } 831 832 private synchronized Properties getOverlay() { 833 if (overlay==null){ 834 overlay=new Properties(); 835 } 836 return overlay; 837 } 838 839 /** 840 * Get the value of the <code>name</code>. If the key is deprecated, 841 * it returns the value of the first key which replaces the deprecated key 842 * and is not null. 843 * If no such property exists, 844 * then <code>defaultValue</code> is returned. 845 * 846 * @param name property name. 847 * @param defaultValue default value. 848 * @return property value, or <code>defaultValue</code> if the property 849 * doesn't exist. 850 */ 851 public String get(String name, String defaultValue) { 852 String[] names = handleDeprecation(name); 853 String result = null; 854 for(String n : names) { 855 result = substituteVars(getProps().getProperty(n, defaultValue)); 856 } 857 return result; 858 } 859 860 /** 861 * Get the value of the <code>name</code> property as an <code>int</code>. 862 * 863 * If no such property exists, the provided default value is returned, 864 * or if the specified value is not a valid <code>int</code>, 865 * then an error is thrown. 866 * 867 * @param name property name. 868 * @param defaultValue default value. 869 * @throws NumberFormatException when the value is invalid 870 * @return property value as an <code>int</code>, 871 * or <code>defaultValue</code>. 872 */ 873 public int getInt(String name, int defaultValue) { 874 String valueString = getTrimmed(name); 875 if (valueString == null) 876 return defaultValue; 877 String hexString = getHexDigits(valueString); 878 if (hexString != null) { 879 return Integer.parseInt(hexString, 16); 880 } 881 return Integer.parseInt(valueString); 882 } 883 884 /** 885 * Set the value of the <code>name</code> property to an <code>int</code>. 886 * 887 * @param name property name. 888 * @param value <code>int</code> value of the property. 889 */ 890 public void setInt(String name, int value) { 891 set(name, Integer.toString(value)); 892 } 893 894 895 /** 896 * Get the value of the <code>name</code> property as a <code>long</code>. 897 * If no such property exists, the provided default value is returned, 898 * or if the specified value is not a valid <code>long</code>, 899 * then an error is thrown. 900 * 901 * @param name property name. 902 * @param defaultValue default value. 903 * @throws NumberFormatException when the value is invalid 904 * @return property value as a <code>long</code>, 905 * or <code>defaultValue</code>. 906 */ 907 public long getLong(String name, long defaultValue) { 908 String valueString = getTrimmed(name); 909 if (valueString == null) 910 return defaultValue; 911 String hexString = getHexDigits(valueString); 912 if (hexString != null) { 913 return Long.parseLong(hexString, 16); 914 } 915 return Long.parseLong(valueString); 916 } 917 918 /** 919 * Get the value of the <code>name</code> property as a <code>long</code> or 920 * human readable format. If no such property exists, the provided default 921 * value is returned, or if the specified value is not a valid 922 * <code>long</code> or human readable format, then an error is thrown. You 923 * can use the following suffix (case insensitive): k(kilo), m(mega), g(giga), 924 * t(tera), p(peta), e(exa) 925 * 926 * @param name property name. 927 * @param defaultValue default value. 928 * @throws NumberFormatException when the value is invalid 929 * @return property value as a <code>long</code>, 930 * or <code>defaultValue</code>. 931 */ 932 public long getLongBytes(String name, long defaultValue) { 933 String valueString = getTrimmed(name); 934 if (valueString == null) 935 return defaultValue; 936 return StringUtils.TraditionalBinaryPrefix.string2long(valueString); 937 } 938 939 private String getHexDigits(String value) { 940 boolean negative = false; 941 String str = value; 942 String hexString = null; 943 if (value.startsWith("-")) { 944 negative = true; 945 str = value.substring(1); 946 } 947 if (str.startsWith("0x") || str.startsWith("0X")) { 948 hexString = str.substring(2); 949 if (negative) { 950 hexString = "-" + hexString; 951 } 952 return hexString; 953 } 954 return null; 955 } 956 957 /** 958 * Set the value of the <code>name</code> property to a <code>long</code>. 959 * 960 * @param name property name. 961 * @param value <code>long</code> value of the property. 962 */ 963 public void setLong(String name, long value) { 964 set(name, Long.toString(value)); 965 } 966 967 /** 968 * Get the value of the <code>name</code> property as a <code>float</code>. 969 * If no such property exists, the provided default value is returned, 970 * or if the specified value is not a valid <code>float</code>, 971 * then an error is thrown. 972 * 973 * @param name property name. 974 * @param defaultValue default value. 975 * @throws NumberFormatException when the value is invalid 976 * @return property value as a <code>float</code>, 977 * or <code>defaultValue</code>. 978 */ 979 public float getFloat(String name, float defaultValue) { 980 String valueString = getTrimmed(name); 981 if (valueString == null) 982 return defaultValue; 983 return Float.parseFloat(valueString); 984 } 985 /** 986 * Set the value of the <code>name</code> property to a <code>float</code>. 987 * 988 * @param name property name. 989 * @param value property value. 990 */ 991 public void setFloat(String name, float value) { 992 set(name,Float.toString(value)); 993 } 994 995 /** 996 * Get the value of the <code>name</code> property as a <code>boolean</code>. 997 * If no such property is specified, or if the specified value is not a valid 998 * <code>boolean</code>, then <code>defaultValue</code> is returned. 999 * 1000 * @param name property name. 1001 * @param defaultValue default value. 1002 * @return property value as a <code>boolean</code>, 1003 * or <code>defaultValue</code>. 1004 */ 1005 public boolean getBoolean(String name, boolean defaultValue) { 1006 String valueString = getTrimmed(name); 1007 if (null == valueString || "".equals(valueString)) { 1008 return defaultValue; 1009 } 1010 1011 valueString = valueString.toLowerCase(); 1012 1013 if ("true".equals(valueString)) 1014 return true; 1015 else if ("false".equals(valueString)) 1016 return false; 1017 else return defaultValue; 1018 } 1019 1020 /** 1021 * Set the value of the <code>name</code> property to a <code>boolean</code>. 1022 * 1023 * @param name property name. 1024 * @param value <code>boolean</code> value of the property. 1025 */ 1026 public void setBoolean(String name, boolean value) { 1027 set(name, Boolean.toString(value)); 1028 } 1029 1030 /** 1031 * Set the given property, if it is currently unset. 1032 * @param name property name 1033 * @param value new value 1034 */ 1035 public void setBooleanIfUnset(String name, boolean value) { 1036 setIfUnset(name, Boolean.toString(value)); 1037 } 1038 1039 /** 1040 * Set the value of the <code>name</code> property to the given type. This 1041 * is equivalent to <code>set(<name>, value.toString())</code>. 1042 * @param name property name 1043 * @param value new value 1044 */ 1045 public <T extends Enum<T>> void setEnum(String name, T value) { 1046 set(name, value.toString()); 1047 } 1048 1049 /** 1050 * Return value matching this enumerated type. 1051 * @param name Property name 1052 * @param defaultValue Value returned if no mapping exists 1053 * @throws IllegalArgumentException If mapping is illegal for the type 1054 * provided 1055 */ 1056 public <T extends Enum<T>> T getEnum(String name, T defaultValue) { 1057 final String val = get(name); 1058 return null == val 1059 ? defaultValue 1060 : Enum.valueOf(defaultValue.getDeclaringClass(), val); 1061 } 1062 1063 /** 1064 * Get the value of the <code>name</code> property as a <code>Pattern</code>. 1065 * If no such property is specified, or if the specified value is not a valid 1066 * <code>Pattern</code>, then <code>DefaultValue</code> is returned. 1067 * 1068 * @param name property name 1069 * @param defaultValue default value 1070 * @return property value as a compiled Pattern, or defaultValue 1071 */ 1072 public Pattern getPattern(String name, Pattern defaultValue) { 1073 String valString = get(name); 1074 if (null == valString || "".equals(valString)) { 1075 return defaultValue; 1076 } 1077 try { 1078 return Pattern.compile(valString); 1079 } catch (PatternSyntaxException pse) { 1080 LOG.warn("Regular expression '" + valString + "' for property '" + 1081 name + "' not valid. Using default", pse); 1082 return defaultValue; 1083 } 1084 } 1085 1086 /** 1087 * Set the given property to <code>Pattern</code>. 1088 * If the pattern is passed as null, sets the empty pattern which results in 1089 * further calls to getPattern(...) returning the default value. 1090 * 1091 * @param name property name 1092 * @param pattern new value 1093 */ 1094 public void setPattern(String name, Pattern pattern) { 1095 if (null == pattern) { 1096 set(name, null); 1097 } else { 1098 set(name, pattern.pattern()); 1099 } 1100 } 1101 1102 /** 1103 * Gets information about why a property was set. Typically this is the 1104 * path to the resource objects (file, URL, etc.) the property came from, but 1105 * it can also indicate that it was set programatically, or because of the 1106 * command line. 1107 * 1108 * @param name - The property name to get the source of. 1109 * @return null - If the property or its source wasn't found. Otherwise, 1110 * returns a list of the sources of the resource. The older sources are 1111 * the first ones in the list. So for example if a configuration is set from 1112 * the command line, and then written out to a file that is read back in the 1113 * first entry would indicate that it was set from the command line, while 1114 * the second one would indicate the file that the new configuration was read 1115 * in from. 1116 */ 1117 @InterfaceStability.Unstable 1118 public synchronized String[] getPropertySources(String name) { 1119 if (properties == null) { 1120 // If properties is null, it means a resource was newly added 1121 // but the props were cleared so as to load it upon future 1122 // requests. So lets force a load by asking a properties list. 1123 getProps(); 1124 } 1125 // Return a null right away if our properties still 1126 // haven't loaded or the resource mapping isn't defined 1127 if (properties == null || updatingResource == null) { 1128 return null; 1129 } else { 1130 String[] source = updatingResource.get(name); 1131 if(source == null) { 1132 return null; 1133 } else { 1134 return Arrays.copyOf(source, source.length); 1135 } 1136 } 1137 } 1138 1139 /** 1140 * A class that represents a set of positive integer ranges. It parses 1141 * strings of the form: "2-3,5,7-" where ranges are separated by comma and 1142 * the lower/upper bounds are separated by dash. Either the lower or upper 1143 * bound may be omitted meaning all values up to or over. So the string 1144 * above means 2, 3, 5, and 7, 8, 9, ... 1145 */ 1146 public static class IntegerRanges implements Iterable<Integer>{ 1147 private static class Range { 1148 int start; 1149 int end; 1150 } 1151 1152 private static class RangeNumberIterator implements Iterator<Integer> { 1153 Iterator<Range> internal; 1154 int at; 1155 int end; 1156 1157 public RangeNumberIterator(List<Range> ranges) { 1158 if (ranges != null) { 1159 internal = ranges.iterator(); 1160 } 1161 at = -1; 1162 end = -2; 1163 } 1164 1165 @Override 1166 public boolean hasNext() { 1167 if (at <= end) { 1168 return true; 1169 } else if (internal != null){ 1170 return internal.hasNext(); 1171 } 1172 return false; 1173 } 1174 1175 @Override 1176 public Integer next() { 1177 if (at <= end) { 1178 at++; 1179 return at - 1; 1180 } else if (internal != null){ 1181 Range found = internal.next(); 1182 if (found != null) { 1183 at = found.start; 1184 end = found.end; 1185 at++; 1186 return at - 1; 1187 } 1188 } 1189 return null; 1190 } 1191 1192 @Override 1193 public void remove() { 1194 throw new UnsupportedOperationException(); 1195 } 1196 }; 1197 1198 List<Range> ranges = new ArrayList<Range>(); 1199 1200 public IntegerRanges() { 1201 } 1202 1203 public IntegerRanges(String newValue) { 1204 StringTokenizer itr = new StringTokenizer(newValue, ","); 1205 while (itr.hasMoreTokens()) { 1206 String rng = itr.nextToken().trim(); 1207 String[] parts = rng.split("-", 3); 1208 if (parts.length < 1 || parts.length > 2) { 1209 throw new IllegalArgumentException("integer range badly formed: " + 1210 rng); 1211 } 1212 Range r = new Range(); 1213 r.start = convertToInt(parts[0], 0); 1214 if (parts.length == 2) { 1215 r.end = convertToInt(parts[1], Integer.MAX_VALUE); 1216 } else { 1217 r.end = r.start; 1218 } 1219 if (r.start > r.end) { 1220 throw new IllegalArgumentException("IntegerRange from " + r.start + 1221 " to " + r.end + " is invalid"); 1222 } 1223 ranges.add(r); 1224 } 1225 } 1226 1227 /** 1228 * Convert a string to an int treating empty strings as the default value. 1229 * @param value the string value 1230 * @param defaultValue the value for if the string is empty 1231 * @return the desired integer 1232 */ 1233 private static int convertToInt(String value, int defaultValue) { 1234 String trim = value.trim(); 1235 if (trim.length() == 0) { 1236 return defaultValue; 1237 } 1238 return Integer.parseInt(trim); 1239 } 1240 1241 /** 1242 * Is the given value in the set of ranges 1243 * @param value the value to check 1244 * @return is the value in the ranges? 1245 */ 1246 public boolean isIncluded(int value) { 1247 for(Range r: ranges) { 1248 if (r.start <= value && value <= r.end) { 1249 return true; 1250 } 1251 } 1252 return false; 1253 } 1254 1255 /** 1256 * @return true if there are no values in this range, else false. 1257 */ 1258 public boolean isEmpty() { 1259 return ranges == null || ranges.isEmpty(); 1260 } 1261 1262 @Override 1263 public String toString() { 1264 StringBuilder result = new StringBuilder(); 1265 boolean first = true; 1266 for(Range r: ranges) { 1267 if (first) { 1268 first = false; 1269 } else { 1270 result.append(','); 1271 } 1272 result.append(r.start); 1273 result.append('-'); 1274 result.append(r.end); 1275 } 1276 return result.toString(); 1277 } 1278 1279 @Override 1280 public Iterator<Integer> iterator() { 1281 return new RangeNumberIterator(ranges); 1282 } 1283 1284 } 1285 1286 /** 1287 * Parse the given attribute as a set of integer ranges 1288 * @param name the attribute name 1289 * @param defaultValue the default value if it is not set 1290 * @return a new set of ranges from the configured value 1291 */ 1292 public IntegerRanges getRange(String name, String defaultValue) { 1293 return new IntegerRanges(get(name, defaultValue)); 1294 } 1295 1296 /** 1297 * Get the comma delimited values of the <code>name</code> property as 1298 * a collection of <code>String</code>s. 1299 * If no such property is specified then empty collection is returned. 1300 * <p> 1301 * This is an optimized version of {@link #getStrings(String)} 1302 * 1303 * @param name property name. 1304 * @return property value as a collection of <code>String</code>s. 1305 */ 1306 public Collection<String> getStringCollection(String name) { 1307 String valueString = get(name); 1308 return StringUtils.getStringCollection(valueString); 1309 } 1310 1311 /** 1312 * Get the comma delimited values of the <code>name</code> property as 1313 * an array of <code>String</code>s. 1314 * If no such property is specified then <code>null</code> is returned. 1315 * 1316 * @param name property name. 1317 * @return property value as an array of <code>String</code>s, 1318 * or <code>null</code>. 1319 */ 1320 public String[] getStrings(String name) { 1321 String valueString = get(name); 1322 return StringUtils.getStrings(valueString); 1323 } 1324 1325 /** 1326 * Get the comma delimited values of the <code>name</code> property as 1327 * an array of <code>String</code>s. 1328 * If no such property is specified then default value is returned. 1329 * 1330 * @param name property name. 1331 * @param defaultValue The default value 1332 * @return property value as an array of <code>String</code>s, 1333 * or default value. 1334 */ 1335 public String[] getStrings(String name, String... defaultValue) { 1336 String valueString = get(name); 1337 if (valueString == null) { 1338 return defaultValue; 1339 } else { 1340 return StringUtils.getStrings(valueString); 1341 } 1342 } 1343 1344 /** 1345 * Get the comma delimited values of the <code>name</code> property as 1346 * a collection of <code>String</code>s, trimmed of the leading and trailing whitespace. 1347 * If no such property is specified then empty <code>Collection</code> is returned. 1348 * 1349 * @param name property name. 1350 * @return property value as a collection of <code>String</code>s, or empty <code>Collection</code> 1351 */ 1352 public Collection<String> getTrimmedStringCollection(String name) { 1353 String valueString = get(name); 1354 if (null == valueString) { 1355 Collection<String> empty = new ArrayList<String>(); 1356 return empty; 1357 } 1358 return StringUtils.getTrimmedStringCollection(valueString); 1359 } 1360 1361 /** 1362 * Get the comma delimited values of the <code>name</code> property as 1363 * an array of <code>String</code>s, trimmed of the leading and trailing whitespace. 1364 * If no such property is specified then an empty array is returned. 1365 * 1366 * @param name property name. 1367 * @return property value as an array of trimmed <code>String</code>s, 1368 * or empty array. 1369 */ 1370 public String[] getTrimmedStrings(String name) { 1371 String valueString = get(name); 1372 return StringUtils.getTrimmedStrings(valueString); 1373 } 1374 1375 /** 1376 * Get the comma delimited values of the <code>name</code> property as 1377 * an array of <code>String</code>s, trimmed of the leading and trailing whitespace. 1378 * If no such property is specified then default value is returned. 1379 * 1380 * @param name property name. 1381 * @param defaultValue The default value 1382 * @return property value as an array of trimmed <code>String</code>s, 1383 * or default value. 1384 */ 1385 public String[] getTrimmedStrings(String name, String... defaultValue) { 1386 String valueString = get(name); 1387 if (null == valueString) { 1388 return defaultValue; 1389 } else { 1390 return StringUtils.getTrimmedStrings(valueString); 1391 } 1392 } 1393 1394 /** 1395 * Set the array of string values for the <code>name</code> property as 1396 * as comma delimited values. 1397 * 1398 * @param name property name. 1399 * @param values The values 1400 */ 1401 public void setStrings(String name, String... values) { 1402 set(name, StringUtils.arrayToString(values)); 1403 } 1404 1405 /** 1406 * Get the socket address for <code>name</code> property as a 1407 * <code>InetSocketAddress</code>. 1408 * @param name property name. 1409 * @param defaultAddress the default value 1410 * @param defaultPort the default port 1411 * @return InetSocketAddress 1412 */ 1413 public InetSocketAddress getSocketAddr( 1414 String name, String defaultAddress, int defaultPort) { 1415 final String address = get(name, defaultAddress); 1416 return NetUtils.createSocketAddr(address, defaultPort, name); 1417 } 1418 1419 /** 1420 * Set the socket address for the <code>name</code> property as 1421 * a <code>host:port</code>. 1422 */ 1423 public void setSocketAddr(String name, InetSocketAddress addr) { 1424 set(name, NetUtils.getHostPortString(addr)); 1425 } 1426 1427 /** 1428 * Set the socket address a client can use to connect for the 1429 * <code>name</code> property as a <code>host:port</code>. The wildcard 1430 * address is replaced with the local host's address. 1431 * @param name property name. 1432 * @param addr InetSocketAddress of a listener to store in the given property 1433 * @return InetSocketAddress for clients to connect 1434 */ 1435 public InetSocketAddress updateConnectAddr(String name, 1436 InetSocketAddress addr) { 1437 final InetSocketAddress connectAddr = NetUtils.getConnectAddress(addr); 1438 setSocketAddr(name, connectAddr); 1439 return connectAddr; 1440 } 1441 1442 /** 1443 * Load a class by name. 1444 * 1445 * @param name the class name. 1446 * @return the class object. 1447 * @throws ClassNotFoundException if the class is not found. 1448 */ 1449 public Class<?> getClassByName(String name) throws ClassNotFoundException { 1450 Class<?> ret = getClassByNameOrNull(name); 1451 if (ret == null) { 1452 throw new ClassNotFoundException("Class " + name + " not found"); 1453 } 1454 return ret; 1455 } 1456 1457 /** 1458 * Load a class by name, returning null rather than throwing an exception 1459 * if it couldn't be loaded. This is to avoid the overhead of creating 1460 * an exception. 1461 * 1462 * @param name the class name 1463 * @return the class object, or null if it could not be found. 1464 */ 1465 public Class<?> getClassByNameOrNull(String name) { 1466 Map<String, Class<?>> map; 1467 1468 synchronized (CACHE_CLASSES) { 1469 map = CACHE_CLASSES.get(classLoader); 1470 if (map == null) { 1471 map = Collections.synchronizedMap( 1472 new WeakHashMap<String, Class<?>>()); 1473 CACHE_CLASSES.put(classLoader, map); 1474 } 1475 } 1476 1477 Class<?> clazz = null; 1478 if (!map.containsKey(name)) { 1479 try { 1480 clazz = Class.forName(name, true, classLoader); 1481 } catch (ClassNotFoundException e) { 1482 map.put(name, null); //cache negative that class is not found 1483 return null; 1484 } 1485 // two putters can race here, but they'll put the same class 1486 map.put(name, clazz); 1487 } else { // check already performed on this class name 1488 clazz = map.get(name); 1489 if (clazz == null) { // found the negative 1490 return null; 1491 } 1492 } 1493 1494 return clazz; 1495 } 1496 1497 /** 1498 * Get the value of the <code>name</code> property 1499 * as an array of <code>Class</code>. 1500 * The value of the property specifies a list of comma separated class names. 1501 * If no such property is specified, then <code>defaultValue</code> is 1502 * returned. 1503 * 1504 * @param name the property name. 1505 * @param defaultValue default value. 1506 * @return property value as a <code>Class[]</code>, 1507 * or <code>defaultValue</code>. 1508 */ 1509 public Class<?>[] getClasses(String name, Class<?> ... defaultValue) { 1510 String[] classnames = getTrimmedStrings(name); 1511 if (classnames == null) 1512 return defaultValue; 1513 try { 1514 Class<?>[] classes = new Class<?>[classnames.length]; 1515 for(int i = 0; i < classnames.length; i++) { 1516 classes[i] = getClassByName(classnames[i]); 1517 } 1518 return classes; 1519 } catch (ClassNotFoundException e) { 1520 throw new RuntimeException(e); 1521 } 1522 } 1523 1524 /** 1525 * Get the value of the <code>name</code> property as a <code>Class</code>. 1526 * If no such property is specified, then <code>defaultValue</code> is 1527 * returned. 1528 * 1529 * @param name the class name. 1530 * @param defaultValue default value. 1531 * @return property value as a <code>Class</code>, 1532 * or <code>defaultValue</code>. 1533 */ 1534 public Class<?> getClass(String name, Class<?> defaultValue) { 1535 String valueString = getTrimmed(name); 1536 if (valueString == null) 1537 return defaultValue; 1538 try { 1539 return getClassByName(valueString); 1540 } catch (ClassNotFoundException e) { 1541 throw new RuntimeException(e); 1542 } 1543 } 1544 1545 /** 1546 * Get the value of the <code>name</code> property as a <code>Class</code> 1547 * implementing the interface specified by <code>xface</code>. 1548 * 1549 * If no such property is specified, then <code>defaultValue</code> is 1550 * returned. 1551 * 1552 * An exception is thrown if the returned class does not implement the named 1553 * interface. 1554 * 1555 * @param name the class name. 1556 * @param defaultValue default value. 1557 * @param xface the interface implemented by the named class. 1558 * @return property value as a <code>Class</code>, 1559 * or <code>defaultValue</code>. 1560 */ 1561 public <U> Class<? extends U> getClass(String name, 1562 Class<? extends U> defaultValue, 1563 Class<U> xface) { 1564 try { 1565 Class<?> theClass = getClass(name, defaultValue); 1566 if (theClass != null && !xface.isAssignableFrom(theClass)) 1567 throw new RuntimeException(theClass+" not "+xface.getName()); 1568 else if (theClass != null) 1569 return theClass.asSubclass(xface); 1570 else 1571 return null; 1572 } catch (Exception e) { 1573 throw new RuntimeException(e); 1574 } 1575 } 1576 1577 /** 1578 * Get the value of the <code>name</code> property as a <code>List</code> 1579 * of objects implementing the interface specified by <code>xface</code>. 1580 * 1581 * An exception is thrown if any of the classes does not exist, or if it does 1582 * not implement the named interface. 1583 * 1584 * @param name the property name. 1585 * @param xface the interface implemented by the classes named by 1586 * <code>name</code>. 1587 * @return a <code>List</code> of objects implementing <code>xface</code>. 1588 */ 1589 @SuppressWarnings("unchecked") 1590 public <U> List<U> getInstances(String name, Class<U> xface) { 1591 List<U> ret = new ArrayList<U>(); 1592 Class<?>[] classes = getClasses(name); 1593 for (Class<?> cl: classes) { 1594 if (!xface.isAssignableFrom(cl)) { 1595 throw new RuntimeException(cl + " does not implement " + xface); 1596 } 1597 ret.add((U)ReflectionUtils.newInstance(cl, this)); 1598 } 1599 return ret; 1600 } 1601 1602 /** 1603 * Set the value of the <code>name</code> property to the name of a 1604 * <code>theClass</code> implementing the given interface <code>xface</code>. 1605 * 1606 * An exception is thrown if <code>theClass</code> does not implement the 1607 * interface <code>xface</code>. 1608 * 1609 * @param name property name. 1610 * @param theClass property value. 1611 * @param xface the interface implemented by the named class. 1612 */ 1613 public void setClass(String name, Class<?> theClass, Class<?> xface) { 1614 if (!xface.isAssignableFrom(theClass)) 1615 throw new RuntimeException(theClass+" not "+xface.getName()); 1616 set(name, theClass.getName()); 1617 } 1618 1619 /** 1620 * Get a local file under a directory named by <i>dirsProp</i> with 1621 * the given <i>path</i>. If <i>dirsProp</i> contains multiple directories, 1622 * then one is chosen based on <i>path</i>'s hash code. If the selected 1623 * directory does not exist, an attempt is made to create it. 1624 * 1625 * @param dirsProp directory in which to locate the file. 1626 * @param path file-path. 1627 * @return local file under the directory with the given path. 1628 */ 1629 public Path getLocalPath(String dirsProp, String path) 1630 throws IOException { 1631 String[] dirs = getTrimmedStrings(dirsProp); 1632 int hashCode = path.hashCode(); 1633 FileSystem fs = FileSystem.getLocal(this); 1634 for (int i = 0; i < dirs.length; i++) { // try each local dir 1635 int index = (hashCode+i & Integer.MAX_VALUE) % dirs.length; 1636 Path file = new Path(dirs[index], path); 1637 Path dir = file.getParent(); 1638 if (fs.mkdirs(dir) || fs.exists(dir)) { 1639 return file; 1640 } 1641 } 1642 LOG.warn("Could not make " + path + 1643 " in local directories from " + dirsProp); 1644 for(int i=0; i < dirs.length; i++) { 1645 int index = (hashCode+i & Integer.MAX_VALUE) % dirs.length; 1646 LOG.warn(dirsProp + "[" + index + "]=" + dirs[index]); 1647 } 1648 throw new IOException("No valid local directories in property: "+dirsProp); 1649 } 1650 1651 /** 1652 * Get a local file name under a directory named in <i>dirsProp</i> with 1653 * the given <i>path</i>. If <i>dirsProp</i> contains multiple directories, 1654 * then one is chosen based on <i>path</i>'s hash code. If the selected 1655 * directory does not exist, an attempt is made to create it. 1656 * 1657 * @param dirsProp directory in which to locate the file. 1658 * @param path file-path. 1659 * @return local file under the directory with the given path. 1660 */ 1661 public File getFile(String dirsProp, String path) 1662 throws IOException { 1663 String[] dirs = getTrimmedStrings(dirsProp); 1664 int hashCode = path.hashCode(); 1665 for (int i = 0; i < dirs.length; i++) { // try each local dir 1666 int index = (hashCode+i & Integer.MAX_VALUE) % dirs.length; 1667 File file = new File(dirs[index], path); 1668 File dir = file.getParentFile(); 1669 if (dir.exists() || dir.mkdirs()) { 1670 return file; 1671 } 1672 } 1673 throw new IOException("No valid local directories in property: "+dirsProp); 1674 } 1675 1676 /** 1677 * Get the {@link URL} for the named resource. 1678 * 1679 * @param name resource name. 1680 * @return the url for the named resource. 1681 */ 1682 public URL getResource(String name) { 1683 return classLoader.getResource(name); 1684 } 1685 1686 /** 1687 * Get an input stream attached to the configuration resource with the 1688 * given <code>name</code>. 1689 * 1690 * @param name configuration resource name. 1691 * @return an input stream attached to the resource. 1692 */ 1693 public InputStream getConfResourceAsInputStream(String name) { 1694 try { 1695 URL url= getResource(name); 1696 1697 if (url == null) { 1698 LOG.info(name + " not found"); 1699 return null; 1700 } else { 1701 LOG.info("found resource " + name + " at " + url); 1702 } 1703 1704 return url.openStream(); 1705 } catch (Exception e) { 1706 return null; 1707 } 1708 } 1709 1710 /** 1711 * Get a {@link Reader} attached to the configuration resource with the 1712 * given <code>name</code>. 1713 * 1714 * @param name configuration resource name. 1715 * @return a reader attached to the resource. 1716 */ 1717 public Reader getConfResourceAsReader(String name) { 1718 try { 1719 URL url= getResource(name); 1720 1721 if (url == null) { 1722 LOG.info(name + " not found"); 1723 return null; 1724 } else { 1725 LOG.info("found resource " + name + " at " + url); 1726 } 1727 1728 return new InputStreamReader(url.openStream()); 1729 } catch (Exception e) { 1730 return null; 1731 } 1732 } 1733 1734 protected synchronized Properties getProps() { 1735 if (properties == null) { 1736 properties = new Properties(); 1737 HashMap<String, String[]> backup = 1738 new HashMap<String, String[]>(updatingResource); 1739 loadResources(properties, resources, quietmode); 1740 if (overlay!= null) { 1741 properties.putAll(overlay); 1742 for (Map.Entry<Object,Object> item: overlay.entrySet()) { 1743 String key = (String)item.getKey(); 1744 updatingResource.put(key, backup.get(key)); 1745 } 1746 } 1747 } 1748 return properties; 1749 } 1750 1751 /** 1752 * Return the number of keys in the configuration. 1753 * 1754 * @return number of keys in the configuration. 1755 */ 1756 public int size() { 1757 return getProps().size(); 1758 } 1759 1760 /** 1761 * Clears all keys from the configuration. 1762 */ 1763 public void clear() { 1764 getProps().clear(); 1765 getOverlay().clear(); 1766 } 1767 1768 /** 1769 * Get an {@link Iterator} to go through the list of <code>String</code> 1770 * key-value pairs in the configuration. 1771 * 1772 * @return an iterator over the entries. 1773 */ 1774 public Iterator<Map.Entry<String, String>> iterator() { 1775 // Get a copy of just the string to string pairs. After the old object 1776 // methods that allow non-strings to be put into configurations are removed, 1777 // we could replace properties with a Map<String,String> and get rid of this 1778 // code. 1779 Map<String,String> result = new HashMap<String,String>(); 1780 for(Map.Entry<Object,Object> item: getProps().entrySet()) { 1781 if (item.getKey() instanceof String && 1782 item.getValue() instanceof String) { 1783 result.put((String) item.getKey(), (String) item.getValue()); 1784 } 1785 } 1786 return result.entrySet().iterator(); 1787 } 1788 1789 private void loadResources(Properties properties, 1790 ArrayList<Resource> resources, 1791 boolean quiet) { 1792 if(loadDefaults) { 1793 for (String resource : defaultResources) { 1794 loadResource(properties, new Resource(resource), quiet); 1795 } 1796 1797 //support the hadoop-site.xml as a deprecated case 1798 if(getResource("hadoop-site.xml")!=null) { 1799 loadResource(properties, new Resource("hadoop-site.xml"), quiet); 1800 } 1801 } 1802 1803 for (int i = 0; i < resources.size(); i++) { 1804 Resource ret = loadResource(properties, resources.get(i), quiet); 1805 if (ret != null) { 1806 resources.set(i, ret); 1807 } 1808 } 1809 } 1810 1811 private Resource loadResource(Properties properties, Resource wrapper, boolean quiet) { 1812 String name = UNKNOWN_RESOURCE; 1813 try { 1814 Object resource = wrapper.getResource(); 1815 name = wrapper.getName(); 1816 1817 DocumentBuilderFactory docBuilderFactory 1818 = DocumentBuilderFactory.newInstance(); 1819 //ignore all comments inside the xml file 1820 docBuilderFactory.setIgnoringComments(true); 1821 1822 //allow includes in the xml file 1823 docBuilderFactory.setNamespaceAware(true); 1824 try { 1825 docBuilderFactory.setXIncludeAware(true); 1826 } catch (UnsupportedOperationException e) { 1827 LOG.error("Failed to set setXIncludeAware(true) for parser " 1828 + docBuilderFactory 1829 + ":" + e, 1830 e); 1831 } 1832 DocumentBuilder builder = docBuilderFactory.newDocumentBuilder(); 1833 Document doc = null; 1834 Element root = null; 1835 boolean returnCachedProperties = false; 1836 1837 if (resource instanceof URL) { // an URL resource 1838 URL url = (URL)resource; 1839 if (url != null) { 1840 if (!quiet) { 1841 LOG.info("parsing " + url); 1842 } 1843 doc = builder.parse(url.toString()); 1844 } 1845 } else if (resource instanceof String) { // a CLASSPATH resource 1846 URL url = getResource((String)resource); 1847 if (url != null) { 1848 if (!quiet) { 1849 LOG.info("parsing " + url); 1850 } 1851 doc = builder.parse(url.toString()); 1852 } 1853 } else if (resource instanceof Path) { // a file resource 1854 // Can't use FileSystem API or we get an infinite loop 1855 // since FileSystem uses Configuration API. Use java.io.File instead. 1856 File file = new File(((Path)resource).toUri().getPath()) 1857 .getAbsoluteFile(); 1858 if (file.exists()) { 1859 if (!quiet) { 1860 LOG.info("parsing " + file); 1861 } 1862 InputStream in = new BufferedInputStream(new FileInputStream(file)); 1863 try { 1864 doc = builder.parse(in); 1865 } finally { 1866 in.close(); 1867 } 1868 } 1869 } else if (resource instanceof InputStream) { 1870 try { 1871 doc = builder.parse((InputStream)resource); 1872 returnCachedProperties = true; 1873 } finally { 1874 ((InputStream)resource).close(); 1875 } 1876 } else if (resource instanceof Properties) { 1877 overlay(properties, (Properties)resource); 1878 } else if (resource instanceof Element) { 1879 root = (Element)resource; 1880 } 1881 1882 if (doc == null && root == null) { 1883 if (quiet) 1884 return null; 1885 throw new RuntimeException(resource + " not found"); 1886 } 1887 1888 if (root == null) { 1889 root = doc.getDocumentElement(); 1890 } 1891 Properties toAddTo = properties; 1892 if(returnCachedProperties) { 1893 toAddTo = new Properties(); 1894 } 1895 if (!"configuration".equals(root.getTagName())) 1896 LOG.fatal("bad conf file: top-level element not <configuration>"); 1897 NodeList props = root.getChildNodes(); 1898 for (int i = 0; i < props.getLength(); i++) { 1899 Node propNode = props.item(i); 1900 if (!(propNode instanceof Element)) 1901 continue; 1902 Element prop = (Element)propNode; 1903 if ("configuration".equals(prop.getTagName())) { 1904 loadResource(toAddTo, new Resource(prop, name), quiet); 1905 continue; 1906 } 1907 if (!"property".equals(prop.getTagName())) 1908 LOG.warn("bad conf file: element not <property>"); 1909 NodeList fields = prop.getChildNodes(); 1910 String attr = null; 1911 String value = null; 1912 boolean finalParameter = false; 1913 LinkedList<String> source = new LinkedList<String>(); 1914 for (int j = 0; j < fields.getLength(); j++) { 1915 Node fieldNode = fields.item(j); 1916 if (!(fieldNode instanceof Element)) 1917 continue; 1918 Element field = (Element)fieldNode; 1919 if ("name".equals(field.getTagName()) && field.hasChildNodes()) 1920 attr = StringInterner.weakIntern( 1921 ((Text)field.getFirstChild()).getData().trim()); 1922 if ("value".equals(field.getTagName()) && field.hasChildNodes()) 1923 value = StringInterner.weakIntern( 1924 ((Text)field.getFirstChild()).getData()); 1925 if ("final".equals(field.getTagName()) && field.hasChildNodes()) 1926 finalParameter = "true".equals(((Text)field.getFirstChild()).getData()); 1927 if ("source".equals(field.getTagName()) && field.hasChildNodes()) 1928 source.add(StringInterner.weakIntern( 1929 ((Text)field.getFirstChild()).getData())); 1930 } 1931 source.add(name); 1932 1933 // Ignore this parameter if it has already been marked as 'final' 1934 if (attr != null) { 1935 if (deprecatedKeyMap.containsKey(attr)) { 1936 DeprecatedKeyInfo keyInfo = deprecatedKeyMap.get(attr); 1937 keyInfo.accessed = false; 1938 for (String key:keyInfo.newKeys) { 1939 // update new keys with deprecated key's value 1940 loadProperty(toAddTo, name, key, value, finalParameter, 1941 source.toArray(new String[source.size()])); 1942 } 1943 } 1944 else { 1945 loadProperty(toAddTo, name, attr, value, finalParameter, 1946 source.toArray(new String[source.size()])); 1947 } 1948 } 1949 } 1950 1951 if (returnCachedProperties) { 1952 overlay(properties, toAddTo); 1953 return new Resource(toAddTo, name); 1954 } 1955 return null; 1956 } catch (IOException e) { 1957 LOG.fatal("error parsing conf " + name, e); 1958 throw new RuntimeException(e); 1959 } catch (DOMException e) { 1960 LOG.fatal("error parsing conf " + name, e); 1961 throw new RuntimeException(e); 1962 } catch (SAXException e) { 1963 LOG.fatal("error parsing conf " + name, e); 1964 throw new RuntimeException(e); 1965 } catch (ParserConfigurationException e) { 1966 LOG.fatal("error parsing conf " + name , e); 1967 throw new RuntimeException(e); 1968 } 1969 } 1970 1971 private void overlay(Properties to, Properties from) { 1972 for (Entry<Object, Object> entry: from.entrySet()) { 1973 to.put(entry.getKey(), entry.getValue()); 1974 } 1975 } 1976 1977 private void loadProperty(Properties properties, String name, String attr, 1978 String value, boolean finalParameter, String[] source) { 1979 if (value != null) { 1980 if (!finalParameters.contains(attr)) { 1981 properties.setProperty(attr, value); 1982 updatingResource.put(attr, source); 1983 } else { 1984 LOG.warn(name+":an attempt to override final parameter: "+attr 1985 +"; Ignoring."); 1986 } 1987 } 1988 if (finalParameter) { 1989 finalParameters.add(attr); 1990 } 1991 } 1992 1993 /** 1994 * Write out the non-default properties in this configuration to the given 1995 * {@link OutputStream}. 1996 * 1997 * @param out the output stream to write to. 1998 */ 1999 public void writeXml(OutputStream out) throws IOException { 2000 writeXml(new OutputStreamWriter(out)); 2001 } 2002 2003 /** 2004 * Write out the non-default properties in this configuration to the given 2005 * {@link Writer}. 2006 * 2007 * @param out the writer to write to. 2008 */ 2009 public void writeXml(Writer out) throws IOException { 2010 Document doc = asXmlDocument(); 2011 2012 try { 2013 DOMSource source = new DOMSource(doc); 2014 StreamResult result = new StreamResult(out); 2015 TransformerFactory transFactory = TransformerFactory.newInstance(); 2016 Transformer transformer = transFactory.newTransformer(); 2017 2018 // Important to not hold Configuration log while writing result, since 2019 // 'out' may be an HDFS stream which needs to lock this configuration 2020 // from another thread. 2021 transformer.transform(source, result); 2022 } catch (TransformerException te) { 2023 throw new IOException(te); 2024 } 2025 } 2026 2027 /** 2028 * Return the XML DOM corresponding to this Configuration. 2029 */ 2030 private synchronized Document asXmlDocument() throws IOException { 2031 Document doc; 2032 try { 2033 doc = 2034 DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument(); 2035 } catch (ParserConfigurationException pe) { 2036 throw new IOException(pe); 2037 } 2038 Element conf = doc.createElement("configuration"); 2039 doc.appendChild(conf); 2040 conf.appendChild(doc.createTextNode("\n")); 2041 handleDeprecation(); //ensure properties is set and deprecation is handled 2042 for (Enumeration e = properties.keys(); e.hasMoreElements();) { 2043 String name = (String)e.nextElement(); 2044 Object object = properties.get(name); 2045 String value = null; 2046 if (object instanceof String) { 2047 value = (String) object; 2048 }else { 2049 continue; 2050 } 2051 Element propNode = doc.createElement("property"); 2052 conf.appendChild(propNode); 2053 2054 Element nameNode = doc.createElement("name"); 2055 nameNode.appendChild(doc.createTextNode(name)); 2056 propNode.appendChild(nameNode); 2057 2058 Element valueNode = doc.createElement("value"); 2059 valueNode.appendChild(doc.createTextNode(value)); 2060 propNode.appendChild(valueNode); 2061 2062 if (updatingResource != null) { 2063 String[] sources = updatingResource.get(name); 2064 if(sources != null) { 2065 for(String s : sources) { 2066 Element sourceNode = doc.createElement("source"); 2067 sourceNode.appendChild(doc.createTextNode(s)); 2068 propNode.appendChild(sourceNode); 2069 } 2070 } 2071 } 2072 2073 conf.appendChild(doc.createTextNode("\n")); 2074 } 2075 return doc; 2076 } 2077 2078 /** 2079 * Writes out all the parameters and their properties (final and resource) to 2080 * the given {@link Writer} 2081 * The format of the output would be 2082 * { "properties" : [ {key1,value1,key1.isFinal,key1.resource}, {key2,value2, 2083 * key2.isFinal,key2.resource}... ] } 2084 * It does not output the parameters of the configuration object which is 2085 * loaded from an input stream. 2086 * @param out the Writer to write to 2087 * @throws IOException 2088 */ 2089 public static void dumpConfiguration(Configuration config, 2090 Writer out) throws IOException { 2091 JsonFactory dumpFactory = new JsonFactory(); 2092 JsonGenerator dumpGenerator = dumpFactory.createJsonGenerator(out); 2093 dumpGenerator.writeStartObject(); 2094 dumpGenerator.writeFieldName("properties"); 2095 dumpGenerator.writeStartArray(); 2096 dumpGenerator.flush(); 2097 synchronized (config) { 2098 for (Map.Entry<Object,Object> item: config.getProps().entrySet()) { 2099 dumpGenerator.writeStartObject(); 2100 dumpGenerator.writeStringField("key", (String) item.getKey()); 2101 dumpGenerator.writeStringField("value", 2102 config.get((String) item.getKey())); 2103 dumpGenerator.writeBooleanField("isFinal", 2104 config.finalParameters.contains(item.getKey())); 2105 String[] resources = config.updatingResource.get(item.getKey()); 2106 String resource = UNKNOWN_RESOURCE; 2107 if(resources != null && resources.length > 0) { 2108 resource = resources[0]; 2109 } 2110 dumpGenerator.writeStringField("resource", resource); 2111 dumpGenerator.writeEndObject(); 2112 } 2113 } 2114 dumpGenerator.writeEndArray(); 2115 dumpGenerator.writeEndObject(); 2116 dumpGenerator.flush(); 2117 } 2118 2119 /** 2120 * Get the {@link ClassLoader} for this job. 2121 * 2122 * @return the correct class loader. 2123 */ 2124 public ClassLoader getClassLoader() { 2125 return classLoader; 2126 } 2127 2128 /** 2129 * Set the class loader that will be used to load the various objects. 2130 * 2131 * @param classLoader the new class loader. 2132 */ 2133 public void setClassLoader(ClassLoader classLoader) { 2134 this.classLoader = classLoader; 2135 } 2136 2137 @Override 2138 public String toString() { 2139 StringBuilder sb = new StringBuilder(); 2140 sb.append("Configuration: "); 2141 if(loadDefaults) { 2142 toString(defaultResources, sb); 2143 if(resources.size()>0) { 2144 sb.append(", "); 2145 } 2146 } 2147 toString(resources, sb); 2148 return sb.toString(); 2149 } 2150 2151 private <T> void toString(List<T> resources, StringBuilder sb) { 2152 ListIterator<T> i = resources.listIterator(); 2153 while (i.hasNext()) { 2154 if (i.nextIndex() != 0) { 2155 sb.append(", "); 2156 } 2157 sb.append(i.next()); 2158 } 2159 } 2160 2161 /** 2162 * Set the quietness-mode. 2163 * 2164 * In the quiet-mode, error and informational messages might not be logged. 2165 * 2166 * @param quietmode <code>true</code> to set quiet-mode on, <code>false</code> 2167 * to turn it off. 2168 */ 2169 public synchronized void setQuietMode(boolean quietmode) { 2170 this.quietmode = quietmode; 2171 } 2172 2173 synchronized boolean getQuietMode() { 2174 return this.quietmode; 2175 } 2176 2177 /** For debugging. List non-default properties to the terminal and exit. */ 2178 public static void main(String[] args) throws Exception { 2179 new Configuration().writeXml(System.out); 2180 } 2181 2182 @Override 2183 public void readFields(DataInput in) throws IOException { 2184 clear(); 2185 int size = WritableUtils.readVInt(in); 2186 for(int i=0; i < size; ++i) { 2187 String key = org.apache.hadoop.io.Text.readString(in); 2188 String value = org.apache.hadoop.io.Text.readString(in); 2189 set(key, value); 2190 String sources[] = WritableUtils.readCompressedStringArray(in); 2191 updatingResource.put(key, sources); 2192 } 2193 } 2194 2195 //@Override 2196 public void write(DataOutput out) throws IOException { 2197 Properties props = getProps(); 2198 WritableUtils.writeVInt(out, props.size()); 2199 for(Map.Entry<Object, Object> item: props.entrySet()) { 2200 org.apache.hadoop.io.Text.writeString(out, (String) item.getKey()); 2201 org.apache.hadoop.io.Text.writeString(out, (String) item.getValue()); 2202 WritableUtils.writeCompressedStringArray(out, 2203 updatingResource.get(item.getKey())); 2204 } 2205 } 2206 2207 /** 2208 * get keys matching the the regex 2209 * @param regex 2210 * @return Map<String,String> with matching keys 2211 */ 2212 public Map<String,String> getValByRegex(String regex) { 2213 Pattern p = Pattern.compile(regex); 2214 2215 Map<String,String> result = new HashMap<String,String>(); 2216 Matcher m; 2217 2218 for(Map.Entry<Object,Object> item: getProps().entrySet()) { 2219 if (item.getKey() instanceof String && 2220 item.getValue() instanceof String) { 2221 m = p.matcher((String)item.getKey()); 2222 if(m.find()) { // match 2223 result.put((String) item.getKey(), (String) item.getValue()); 2224 } 2225 } 2226 } 2227 return result; 2228 } 2229 2230 //Load deprecated keys in common 2231 private static void addDeprecatedKeys() { 2232 Configuration.addDeprecation("topology.script.file.name", 2233 new String[]{CommonConfigurationKeys.NET_TOPOLOGY_SCRIPT_FILE_NAME_KEY}); 2234 Configuration.addDeprecation("topology.script.number.args", 2235 new String[]{CommonConfigurationKeys.NET_TOPOLOGY_SCRIPT_NUMBER_ARGS_KEY}); 2236 Configuration.addDeprecation("hadoop.configured.node.mapping", 2237 new String[]{CommonConfigurationKeys.NET_TOPOLOGY_CONFIGURED_NODE_MAPPING_KEY}); 2238 Configuration.addDeprecation("topology.node.switch.mapping.impl", 2239 new String[]{CommonConfigurationKeys.NET_TOPOLOGY_NODE_SWITCH_MAPPING_IMPL_KEY}); 2240 Configuration.addDeprecation("dfs.df.interval", 2241 new String[]{CommonConfigurationKeys.FS_DF_INTERVAL_KEY}); 2242 Configuration.addDeprecation("dfs.client.buffer.dir", 2243 new String[]{CommonConfigurationKeys.FS_CLIENT_BUFFER_DIR_KEY}); 2244 Configuration.addDeprecation("hadoop.native.lib", 2245 new String[]{CommonConfigurationKeys.IO_NATIVE_LIB_AVAILABLE_KEY}); 2246 Configuration.addDeprecation("fs.default.name", 2247 new String[]{CommonConfigurationKeys.FS_DEFAULT_NAME_KEY}); 2248 Configuration.addDeprecation("dfs.umaskmode", 2249 new String[]{CommonConfigurationKeys.FS_PERMISSIONS_UMASK_KEY}); 2250 } 2251 }