Author: cdouglas
Date: Thu Jan 7 18:55:45 2010
New Revision: 896966
URL: http://svn.apache.org/viewvc?rev=896966&view=rev
Log:
HADOOP-6420. Add functionality permitting subsets of Configuration to be
interpreted as Map<String,String>. Contributed by Aaron Kimball
Modified:
hadoop/common/trunk/CHANGES.txt
hadoop/common/trunk/src/java/org/apache/hadoop/conf/Configuration.java
hadoop/common/trunk/src/test/core/org/apache/hadoop/conf/TestConfiguration.java
Modified: hadoop/common/trunk/CHANGES.txt
URL:
http://svn.apache.org/viewvc/hadoop/common/trunk/CHANGES.txt?rev=896966&r1=896965&r2=896966&view=diff
==============================================================================
--- hadoop/common/trunk/CHANGES.txt (original)
+++ hadoop/common/trunk/CHANGES.txt Thu Jan 7 18:55:45 2010
@@ -94,6 +94,9 @@
HADOOP-6479. TestUTF8 assertions could fail with better text.
(Steve Loughran via tomwhite)
+ HADOOP-6420. Add functionality permitting subsets of Configuration to be
+ interpreted as Map<String,String>. (Aaron Kimball via cdouglas)
+
OPTIMIZATIONS
BUG FIXES
Modified: hadoop/common/trunk/src/java/org/apache/hadoop/conf/Configuration.java
URL:
http://svn.apache.org/viewvc/hadoop/common/trunk/src/java/org/apache/hadoop/conf/Configuration.java?rev=896966&r1=896965&r2=896966&view=diff
==============================================================================
--- hadoop/common/trunk/src/java/org/apache/hadoop/conf/Configuration.java
(original)
+++ hadoop/common/trunk/src/java/org/apache/hadoop/conf/Configuration.java Thu
Jan 7 18:55:45 2010
@@ -31,6 +31,7 @@
import java.io.Reader;
import java.io.Writer;
import java.net.URL;
+import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@@ -1067,7 +1068,139 @@
public void setStrings(String name, String... values) {
set(name, StringUtils.arrayToString(values));
}
-
+
+ /**
+ * Instantiates a map view over a subset of the entries in
+ * the Configuration. This is instantiated by getMap(), which
+ * binds a prefix of the namespace to the ConfigItemMap. This
+ * mapping reflects changes to the underlying Configuration.
+ *
+ * This map does not support iteration.
+ */
+ protected class ConfigItemMap extends AbstractMap<String, String>
+ implements Map<String, String> {
+
+ private final String prefix;
+
+ public ConfigItemMap(String prefix) {
+ this.prefix = prefix;
+ }
+
+ @Override
+ public boolean containsKey(Object key) {
+ return lookup(key.toString()) != null;
+ }
+
+ @Override
+ public Set<Map.Entry<String, String>> entrySet() {
+ throw new UnsupportedOperationException("unsupported");
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ return o != null && o instanceof ConfigItemMap
+ && prefix.equals(((ConfigItemMap) o).prefix)
+ && Configuration.this == ((ConfigItemMap) o).getConfiguration();
+ }
+
+ private Configuration getConfiguration() {
+ return Configuration.this;
+ }
+
+ @Override
+ public String get(Object key) {
+ if (null == key) {
+ return null;
+ }
+
+ return lookup(key.toString());
+ }
+
+ @Override
+ public int hashCode() {
+ return prefix.hashCode();
+ }
+
+ @Override
+ public String put(String key, String val) {
+ if (null == key) {
+ return null;
+ }
+
+ String ret = get(key);
+ Configuration.this.set(prefix + key, val);
+ return ret;
+ }
+
+ @Override
+ public void putAll(Map<? extends String, ? extends String> m) {
+ for (Map.Entry<? extends String, ? extends String> entry : m.entrySet())
{
+ put(entry.getKey(), entry.getValue());
+ }
+ }
+
+ private String lookup(String subKey) {
+ String configKey = prefix + subKey;
+ Properties props = Configuration.this.getProps();
+ Object val = props.get(configKey);
+ String str = null;
+ if (null != val) {
+ str = substituteVars(val.toString());
+ }
+
+ return str;
+ }
+ }
+
+ /**
+ * Given a string -> string map as a value, embed this in the
+ * Configuration by prepending 'name' to all the keys in the valueMap,
+ * and storing it inside the current Configuration.
+ *
+ * e.g., setMap("foo", { "bar" -> "a", "baz" -> "b" }) would
+ * insert "foo.bar" -> "a" and "foo.baz" -> "b" in this
+ * Configuration.
+ *
+ * @param name the prefix to attach to all keys in the valueMap. This
+ * should not have a trailing "." character.
+ * @param valueMap the map to embed in the Configuration.
+ */
+ public void setMap(String name, Map<String, String> valueMap) {
+ // Store all elements of the map proper.
+ for (Map.Entry<String, String> entry : valueMap.entrySet()) {
+ set(name + "." + entry.getKey(), entry.getValue());
+ }
+ }
+
+ /**
+ * Returns a map containing a view of all configuration properties
+ * whose names begin with "name.*", with the "name." prefix removed.
+ * e.g., if "foo.bar" -> "a" and "foo.baz" -> "b" are in the
+ * Configuration, getMap("foo") would return { "bar" -> "a",
+ * "baz" -> "b" }.
+ *
+ * Map name deprecation is handled via "prefix deprecation"; the individual
+ * keys created in a configuration by inserting a map do not need to be
+ * individually deprecated -- it is sufficient to deprecate the 'name'
+ * associated with the map and bind that to a new name. e.g., if "foo"
+ * is deprecated for "newfoo," and the configuration contains entries for
+ * "newfoo.a" and "newfoo.b", getMap("foo") will return a map containing
+ * the keys "a" and "b".
+ *
+ * The returned map does not support iteration; it is a lazy view over
+ * the slice of the configuration whose keys begin with 'name'. Updates
+ * to the underlying configuration are reflected in the returned map,
+ * and updates to the map will modify the underlying configuration.
+ *
+ * @param name The prefix of the key names to extract into the output map.
+ * @return a String->String map that contains all (k, v) pairs
+ * where 'k' begins with 'name.'; the 'name.' prefix is removed in the
output.
+ */
+ public Map<String, String> getMap(String name) {
+ String prefix = handleDeprecation(name) + ".";
+ return new ConfigItemMap(prefix);
+ }
+
/**
* Load a class by name.
*
Modified:
hadoop/common/trunk/src/test/core/org/apache/hadoop/conf/TestConfiguration.java
URL:
http://svn.apache.org/viewvc/hadoop/common/trunk/src/test/core/org/apache/hadoop/conf/TestConfiguration.java?rev=896966&r1=896965&r2=896966&view=diff
==============================================================================
---
hadoop/common/trunk/src/test/core/org/apache/hadoop/conf/TestConfiguration.java
(original)
+++
hadoop/common/trunk/src/test/core/org/apache/hadoop/conf/TestConfiguration.java
Thu Jan 7 18:55:45 2010
@@ -24,6 +24,7 @@
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.HashMap;
+import java.util.Map;
import java.util.Random;
import java.util.regex.Pattern;
@@ -365,6 +366,49 @@
assertTrue(fail);
}
+ public void testMap() throws IOException {
+ Configuration conf = new Configuration();
+
+ // manually create a map in the config; extract
+ // its values as a map object.
+ conf.set("foo.bar", "A");
+ conf.set("foo.baz", "B");
+ assertEquals("A", conf.get("foo.bar"));
+ assertEquals("B", conf.get("foo.baz"));
+
+ Map<String, String> out = conf.getMap("foo");
+ assertEquals("A", out.get("bar"));
+ assertEquals("B", out.get("baz"));
+
+ Map<String, String> in = new HashMap<String, String>();
+ in.put("yak", "123");
+ in.put("bop", "456");
+ conf.setMap("quux", in);
+
+ // Assert that we can extract individual entries in
+ // the nested map ok.
+ assertEquals("123", conf.get("quux.yak"));
+
+ // Assert that we can get the whole map back out again.
+ out = conf.getMap("quux");
+ assertEquals("123", out.get("yak"));
+ assertEquals("456", out.get("bop"));
+
+ // Test that substitution is handled by getMap().
+ conf.set("subparam", "foo");
+ conf.set("mymap.someprop", "AAA${subparam}BBB");
+ out = conf.getMap("mymap");
+ assertEquals("AAAfooBBB", out.get("someprop"));
+
+ // Test deprecation of maps.
+ Configuration.addDeprecation("oldfoo", new String[]{"newfoo"});
+ conf.set("newfoo.a", "A");
+ conf.set("newfoo.b", "B");
+ out = conf.getMap("oldfoo");
+ assertEquals("A", out.get("a"));
+ assertEquals("B", out.get("b"));
+ }
+
public void testPattern() throws IOException {
out = new BufferedWriter(new FileWriter(CONFIG));
startConfig();