|
@@ -31,6 +31,7 @@ import java.io.OutputStreamWriter;
|
|
|
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 class Configuration implements Iterable<Map.Entry<String,String>>,
|
|
|
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.
|
|
|
*
|