juneau-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From jamesbog...@apache.org
Subject [juneau] branch master updated: Config API changes.
Date Mon, 26 Feb 2018 01:10:41 GMT
This is an automated email from the ASF dual-hosted git repository.

jamesbognar pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/juneau.git


The following commit(s) were added to refs/heads/master by this push:
     new 2da2017  Config API changes.
2da2017 is described below

commit 2da2017e37944d6a574aa6d73f6c6e164482cdf2
Author: JamesBognar <jamesbognar@apache.org>
AuthorDate: Sun Feb 25 20:10:32 2018 -0500

    Config API changes.
---
 .../main/java/org/apache/juneau/config/Config.java |  27 +-
 .../apache/juneau/config/event/ConfigEvent.java    |   2 +-
 .../org/apache/juneau/config/store/ConfigMap.java  |  30 +-
 .../apache/juneau/config/ConfigBuilderTest.java    |   4 +-
 .../juneau/config/ConfigMapListenerTest.java       |  24 +-
 .../org/apache/juneau/config/ConfigMapTest.java    |  78 +-
 .../java/org/apache/juneau/config/ConfigTest.java  |  74 +-
 juneau-doc/src/main/javadoc/overview.html          | 953 +++++++++------------
 8 files changed, 506 insertions(+), 686 deletions(-)

diff --git a/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/Config.java b/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/Config.java
index 9d99aa1..3630319 100644
--- a/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/Config.java
+++ b/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/Config.java
@@ -275,7 +275,6 @@ public final class Config extends Context implements ConfigEventListener, Writab
 	private final boolean beansOnSeparateLines, readOnly;
 	private final ConfigMap configMap;
 	private final BeanSession beanSession;
-	private volatile boolean closed;
 	private final List<ConfigEventListener> listeners = Collections.synchronizedList(new LinkedList<ConfigEventListener>());
 
 
@@ -1015,7 +1014,7 @@ public final class Config extends Context implements ConfigEventListener, Writab
 	 * 
 	 * @param section 
 	 * 	The section name to write from.
-	 * 	<br>If empty or <js>"default"</js>, refers to the default section.
+	 * 	<br>If empty, refers to the default section.
 	 * 	<br>Must not be <jk>null</jk>.
 	 * @return
 	 * 	An unmodifiable set of keys, or an empty set if the section doesn't exist.
@@ -1029,7 +1028,7 @@ public final class Config extends Context implements ConfigEventListener, Writab
 	 * 
 	 * @param section 
 	 * 	The section name to write from.
-	 * 	<br>If empty or <js>"default"</js>, refers to the default section.
+	 * 	<br>If empty, refers to the default section.
 	 * 	<br>Must not be <jk>null</jk>.
 	 * @param bean The bean to set the properties on.
 	 * @param ignoreUnknownProperties
@@ -1070,7 +1069,7 @@ public final class Config extends Context implements ConfigEventListener, Writab
 	 * 
 	 * @param section 
 	 * 	The section name to write from.
-	 * 	<br>If empty or <js>"default"</js>, refers to the default section.
+	 * 	<br>If empty, refers to the default section.
 	 * 	<br>Must not be <jk>null</jk>.
 	 * @param c The bean class to create.
 	 * @return A new bean instance.
@@ -1113,7 +1112,7 @@ public final class Config extends Context implements ConfigEventListener, Writab
 	 * 
 	 * @param section 
 	 * 	The section name to write from.
-	 * 	<br>If empty or <js>"default"</js>, refers to the default section.
+	 * 	<br>If empty, refers to the default section.
 	 * 	<br>Must not be <jk>null</jk>.
 	 * @param c The bean class to create.
 	 * @param ignoreUnknownProperties
@@ -1150,7 +1149,7 @@ public final class Config extends Context implements ConfigEventListener, Writab
 	 * 
 	 * @param section 
 	 * 	The section name to write from.
-	 * 	<br>If empty or <js>"default"</js>, refers to the default section.
+	 * 	<br>If empty, refers to the default section.
 	 * 	<br>Must not be <jk>null</jk>.
 	 * @return A new {@link ObjectMap}, or <jk>null</jk> if the section doesn't exist.
 	 * @throws ParseException 
@@ -1229,7 +1228,7 @@ public final class Config extends Context implements ConfigEventListener, Writab
 	 * 
 	 * @param section 
 	 * 	The section name to write from.
-	 * 	<br>If empty or <js>"default"</js>, refers to the default section.
+	 * 	<br>If empty, refers to the default section.
 	 * 	<br>Must not be <jk>null</jk>.
 	 * @param c The proxy interface class.
 	 * @return The proxy interface.
@@ -1280,7 +1279,7 @@ public final class Config extends Context implements ConfigEventListener, Writab
 	 * @param name 
 	 * 	The section name.
 	 * 	<br>Must not be <jk>null</jk>.
-	 * 	<br>Use blank or <js>"default"</js> for the default section.
+	 * 	<br>Use blank for the default section.
 	 * @param preLines 
 	 * 	Optional comment and blank lines to add immediately before the section.
 	 * 	<br>If <jk>null</jk>, previous pre-lines will not be replaced.
@@ -1301,7 +1300,7 @@ public final class Config extends Context implements ConfigEventListener, Writab
 	 * @param name 
 	 * 	The section name.
 	 * 	<br>Must not be <jk>null</jk>.
-	 * 	<br>Use <js>"default"</js> for the default section.
+	 * 	<br>Use blank for the default section.
 	 * @param preLines 
 	 * 	Optional comment and blank lines to add immediately before the section.
 	 * 	<br>If <jk>null</jk>, previous pre-lines will not be replaced.
@@ -1411,7 +1410,6 @@ public final class Config extends Context implements ConfigEventListener, Writab
 	 */
 	public void close() throws IOException {
 		configMap.unregister(this);
-		closed = true;
 	}
 	
 	/**
@@ -1604,7 +1602,7 @@ public final class Config extends Context implements ConfigEventListener, Writab
 		assertFieldNotNull(key, "key");
 		int i = key.indexOf('/');
 		if (i == -1)
-			return "default";
+			return "";
 		return key.substring(0, i);
 	}
 
@@ -1618,7 +1616,7 @@ public final class Config extends Context implements ConfigEventListener, Writab
 	private String section(String section) {
 		assertFieldNotNull(section, "section");
 		if (isEmpty(section))
-			return "default";
+			return "";
 		return section;
 	}
 	
@@ -1639,9 +1637,6 @@ public final class Config extends Context implements ConfigEventListener, Writab
 	
 	@Override /* Object */
 	protected void finalize() throws Throwable {
-		// If Config objects are not closed, listeners on the underlying ConfigMap don't get cleaned up.
-		if (! closed) {
-			System.err.println("Config object not closed.");
-		}
+		close();
 	}
 }
diff --git a/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/event/ConfigEvent.java b/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/event/ConfigEvent.java
index 70fd1ce..1870dfa 100644
--- a/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/event/ConfigEvent.java
+++ b/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/event/ConfigEvent.java
@@ -189,7 +189,7 @@ public class ConfigEvent {
 			case REMOVE_SECTION:
 				return "REMOVE_SECTION("+section+")";
 			case REMOVE_ENTRY:
-				return "REMOVE_ENTRY("+section+"/"+key+")";
+				return "REMOVE_ENTRY("+section+(section.isEmpty() ? "" : "/")+key+")";
 			case SET_SECTION:
 				return "SET_SECTION("+section+", preLines="+StringUtils.join(preLines, '|')+")";
 			case SET_ENTRY:
diff --git a/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/store/ConfigMap.java b/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/store/ConfigMap.java
index efa837d..89f0747 100644
--- a/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/store/ConfigMap.java
+++ b/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/store/ConfigMap.java
@@ -93,7 +93,7 @@ public class ConfigMap implements ConfigStoreListener {
 			}
 		}
 		
-		// Add [default] section.
+		// Add [blank] section.
 		boolean inserted = false;
 		boolean foundComment = false;
 		for (ListIterator<String> li = lines.listIterator(); li.hasNext();) {
@@ -101,7 +101,7 @@ public class ConfigMap implements ConfigStoreListener {
 			char c = StringUtils.firstNonWhitespaceChar(l);
 			if (c != '#') {
 				if (c == 0 && foundComment) {
-					li.set("[default]");
+					li.set("[]");
 					inserted = true;
 				}
 				break;
@@ -109,7 +109,7 @@ public class ConfigMap implements ConfigStoreListener {
 			foundComment = true;
 		}
 		if (! inserted)
-			lines.add(0, "[default]");
+			lines.add(0, "[]");
 		
 		// Collapse any multi-lines.
 		ListIterator<String> li = lines.listIterator(lines.size());
@@ -181,7 +181,7 @@ public class ConfigMap implements ConfigStoreListener {
 	 * @param section 
 	 * 	The section name.
 	 * 	<br>Must not be <jk>null</jk>.
-	 * 	<br>Use <js>"default"</js> to refer to the default section.
+	 * 	<br>Use blank to refer to the default section.
 	 * @param key 
 	 * 	The entry key.
 	 * 	<br>Must not be <jk>null</jk>.
@@ -208,7 +208,7 @@ public class ConfigMap implements ConfigStoreListener {
 	 * @param section 
 	 * 	The section name.
 	 * 	<br>Must not be <jk>null</jk>.
-	 * 	<br>Use <js>"default"</js> to refer to the default section.
+	 * 	<br>Use blank to refer to the default section.
 	 * @return
 	 * 	An unmodifiable list of lines, or <jk>null</jk> if the section doesn't exist.
 	 */
@@ -239,7 +239,7 @@ public class ConfigMap implements ConfigStoreListener {
 	 * @param section 
 	 * 	The section name.
 	 * 	<br>Must not be <jk>null</jk>.
-	 * 	<br>Use <js>"default"</js> to refer to the default section.
+	 * 	<br>Use blank to refer to the default section.
 	 * @return
 	 * 	An unmodifiable set of keys, or an empty set if the section doesn't exist.
 	 */
@@ -255,7 +255,7 @@ public class ConfigMap implements ConfigStoreListener {
 	 * @param section 
 	 * 	The section name.
 	 * 	<br>Must not be <jk>null</jk>.
-	 * 	<br>Use <js>"default"</js> to refer to the default section.
+	 * 	<br>Use blank to refer to the default section.
 	 * @return <jk>true</jk> if this config has the specified section.
 	 */
 	public boolean hasSection(String section) {
@@ -273,7 +273,7 @@ public class ConfigMap implements ConfigStoreListener {
 	 * @param section 
 	 * 	The section name.
 	 * 	<br>Must not be <jk>null</jk>.
-	 * 	<br>Use <js>"default"</js> to refer to the default section.
+	 * 	<br>Use blank to refer to the default section.
 	 * @param preLines
 	 * 	The pre-lines on the section.
 	 * 	<br>If <jk>null</jk>, the previous value will not be overwritten.
@@ -290,7 +290,7 @@ public class ConfigMap implements ConfigStoreListener {
 	 * @param section 
 	 * 	The section name.
 	 * 	<br>Must not be <jk>null</jk>.
-	 * 	<br>Use <js>"default"</js> to refer to the default section.
+	 * 	<br>Use blank to refer to the default section.
 	 * @param key 
 	 * 	The entry key.
 	 * 	<br>Must not be <jk>null</jk>.
@@ -325,7 +325,7 @@ public class ConfigMap implements ConfigStoreListener {
 	 * @param section 
 	 * 	The section name.
 	 * 	<br>Must not be <jk>null</jk>.
-	 * 	<br>Use <js>"default"</js> to refer to the default section.
+	 * 	<br>Use blank to refer to the default section.
 	 * @return This object (for method chaining).
 	 */
 	public ConfigMap removeSection(String section) {
@@ -339,7 +339,7 @@ public class ConfigMap implements ConfigStoreListener {
 	 * @param section 
 	 * 	The section name.
 	 * 	<br>Must not be <jk>null</jk>.
-	 * 	<br>Use <js>"default"</js> to refer to the default section.
+	 * 	<br>Use blank to refer to the default section.
 	 * @param key 
 	 * 	The entry key.
 	 * 	<br>Must not be <jk>null</jk>.
@@ -606,7 +606,7 @@ public class ConfigMap implements ConfigStoreListener {
 	}
 
 	private void checkSectionName(String s) {
-		if (! ("default".equals(s) || isValidNewSectionName(s)))
+		if (! ("".equals(s) || isValidNewSectionName(s)))
 			throw new IllegalArgumentException("Invalid section name: '" + s + "'");
 	}
 
@@ -635,8 +635,6 @@ public class ConfigMap implements ConfigStoreListener {
 		s = s.trim();
 		if (s.isEmpty())
 			return false;
-		if ("default".equals(s))
-			return false;
 		for (int i = 0; i < s.length(); i++) {
 			char c = s.charAt(i);
 			if (c == '/' || c == '\\' || c == '[' || c == ']')
@@ -705,7 +703,7 @@ public class ConfigMap implements ConfigStoreListener {
 	
 	class ConfigSection {
 
-		final String name;   // The config section name, or "default" if the default section.  Never null.
+		final String name;   // The config section name, or blank if the default section.  Never null.
 
 		final List<String> preLines = Collections.synchronizedList(new ArrayList<String>());
 		private final String rawLine;
@@ -778,7 +776,7 @@ public class ConfigMap implements ConfigStoreListener {
 			for (String s : preLines)
 				w.append(s).append('\n');
 			
-			if (! name.equals("default"))
+			if (! name.equals(""))
 				w.append(rawLine).append('\n');
 			else {
 				// Need separation between default prelines and first-entry prelines.
diff --git a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/config/ConfigBuilderTest.java b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/config/ConfigBuilderTest.java
index 9cebe35..1e2aee8 100755
--- a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/config/ConfigBuilderTest.java
+++ b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/config/ConfigBuilderTest.java
@@ -51,10 +51,10 @@ public class ConfigBuilderTest {
 		assertFalse(f.exists());
 
 		cf.save();
-		assertObjectEquals("{'default':{},Test:{A:'a'}}", cf.asMap());
+		assertObjectEquals("{'':{},Test:{A:'a'}}", cf.asMap());
 
 		String NL = System.getProperty("line.separator");
 		cf = cf.write("[Test]"+NL+"A = b"+NL, true);
-		assertObjectEquals("{'default':{},Test:{A:'b'}}", cf.asMap());
+		assertObjectEquals("{'':{},Test:{A:'b'}}", cf.asMap());
 	}
 }
\ No newline at end of file
diff --git a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/config/ConfigMapListenerTest.java b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/config/ConfigMapListenerTest.java
index ee2fbca..52b0e50 100644
--- a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/config/ConfigMapListenerTest.java
+++ b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/config/ConfigMapListenerTest.java
@@ -46,7 +46,7 @@ public class ConfigMapListenerTest {
 		
 		ConfigMap cm = s.getMap("Foo.cfg");
 		cm.register(l);
-		cm.setEntry("default", "foo", "baz", null, null, null);
+		cm.setEntry("", "foo", "baz", null, null, null);
 		cm.save();
 		wait(latch);
 		assertNull(l.error);
@@ -102,7 +102,7 @@ public class ConfigMapListenerTest {
 
 		ConfigMap cm = s.getMap("Foo.cfg");
 		cm.register(l);
-		cm.setEntry("default", "k", "vb", null, null, null);
+		cm.setEntry("", "k", "vb", null, null, null);
 		cm.setEntry("S1", "k1", "v1b", null, null, null);
 		cm.save();
 		wait(latch);
@@ -128,7 +128,7 @@ public class ConfigMapListenerTest {
 
 		ConfigMap cm = s.getMap("Foo.cfg");
 		cm.register(l);
-		cm.setEntry("default", "k", "kb", "^*", "C", Arrays.asList("#k"));
+		cm.setEntry("", "k", "kb", "^*", "C", Arrays.asList("#k"));
 		cm.setEntry("S1", "k1", "k1b", "^*", "C1", Arrays.asList("#k1"));
 		cm.save();
 		wait(latch);
@@ -160,7 +160,7 @@ public class ConfigMapListenerTest {
 
 		ConfigMap cm = s.getMap("Foo.cfg");
 		cm.register(l);
-		cm.setEntry("default", "k", "kb", "^*", "Cb", Arrays.asList("#kb"));
+		cm.setEntry("", "k", "kb", "^*", "Cb", Arrays.asList("#kb"));
 		cm.setEntry("S1", "k1", "k1b", "^*", "Cb1", Arrays.asList("#k1b"));
 		cm.save();
 		wait(latch);
@@ -187,13 +187,13 @@ public class ConfigMapListenerTest {
 		LatchedListener l = new LatchedListener(latch) {
 			@Override
 			public void check(List<ConfigEvent> events) throws Exception {
-				assertObjectEquals("['REMOVE_ENTRY(default/k)','REMOVE_ENTRY(S1/k1)']", events);
+				assertObjectEquals("['REMOVE_ENTRY(k)','REMOVE_ENTRY(S1/k1)']", events);
 			}
 		};
 
 		ConfigMap cm = s.getMap("Foo.cfg");
 		cm.register(l);
-		cm.removeEntry("default", "k");
+		cm.removeEntry("", "k");
 		cm.removeEntry("S1", "k1");
 		cm.save();
 		wait(latch);
@@ -219,13 +219,13 @@ public class ConfigMapListenerTest {
 		LatchedListener l = new LatchedListener(latch) {
 			@Override
 			public void check(List<ConfigEvent> events) throws Exception {
-				assertObjectEquals("['REMOVE_ENTRY(default/k)','REMOVE_ENTRY(S1/k1)']", events);
+				assertObjectEquals("['REMOVE_ENTRY(k)','REMOVE_ENTRY(S1/k1)']", events);
 			}
 		};
 
 		ConfigMap cm = s.getMap("Foo.cfg");
 		cm.register(l);
-		cm.removeEntry("default", "k");
+		cm.removeEntry("", "k");
 		cm.removeEntry("S1", "k1");
 		cm.save();
 		wait(latch);
@@ -255,7 +255,7 @@ public class ConfigMapListenerTest {
 
 		ConfigMap cm = s.getMap("Foo.cfg");
 		cm.register(l);
-		cm.setSection("default", Arrays.asList("#D1"));
+		cm.setSection("", Arrays.asList("#D1"));
 		cm.setSection("S1", Arrays.asList("#S1"));
 		cm.setSection("S2", null);
 		cm.setSection("S3", Collections.<String>emptyList());
@@ -290,7 +290,7 @@ public class ConfigMapListenerTest {
 
 		ConfigMap cm = s.getMap("Foo.cfg");
 		cm.register(l);
-		cm.setSection("default", Arrays.asList("#Db"));
+		cm.setSection("", Arrays.asList("#Db"));
 		cm.setSection("S1", Arrays.asList("#S1b"));
 		cm.setSection("S2", null);
 		cm.setSection("S3", Collections.<String>emptyList());
@@ -329,13 +329,13 @@ public class ConfigMapListenerTest {
 		LatchedListener l = new LatchedListener(latch) {
 			@Override
 			public void check(List<ConfigEvent> events) throws Exception {
-				assertObjectEquals("['REMOVE_ENTRY(default/k)','REMOVE_ENTRY(S1/k1)','REMOVE_ENTRY(S2/k2)']", events);
+				assertObjectEquals("['REMOVE_ENTRY(k)','REMOVE_ENTRY(S1/k1)','REMOVE_ENTRY(S2/k2)']", events);
 			}
 		};
 
 		ConfigMap cm = s.getMap("Foo.cfg");
 		cm.register(l);
-		cm.removeSection("default");
+		cm.removeSection("");
 		cm.removeSection("S1");
 		cm.removeSection("S2");
 		cm.removeSection("S3");
diff --git a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/config/ConfigMapTest.java b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/config/ConfigMapTest.java
index fb6c865..b70bf84 100644
--- a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/config/ConfigMapTest.java
+++ b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/config/ConfigMapTest.java
@@ -64,10 +64,10 @@ public class ConfigMapTest {
 		
 		assertTextEquals("foo=bar|", cm);
 		
-		assertEquals("", join(cm.getPreLines("default"), '|'));
-		assertEquals("", join(cm.getEntry("default", "foo").getPreLines(), '|'));
+		assertEquals("", join(cm.getPreLines(""), '|'));
+		assertEquals("", join(cm.getEntry("", "foo").getPreLines(), '|'));
 		
-		assertEquals("bar", cm.getEntry("default", "foo").getValue());
+		assertEquals("bar", cm.getEntry("", "foo").getValue());
 		
 		// Round trip.
 		s.update("Foo.cfg", cm.toString());
@@ -88,10 +88,10 @@ public class ConfigMapTest {
 		
 		assertTextEquals("#comment|foo=bar|", cm);
 
-		assertEquals("", join(cm.getPreLines("default"), '|'));
-		assertEquals("#comment", join(cm.getEntry("default", "foo").getPreLines(), '|'));
+		assertEquals("", join(cm.getPreLines(""), '|'));
+		assertEquals("#comment", join(cm.getEntry("", "foo").getPreLines(), '|'));
 
-		assertEquals("bar", cm.getEntry("default", "foo").getValue());
+		assertEquals("bar", cm.getEntry("", "foo").getValue());
 		
 		// Round trip.
 		s.update("Foo.cfg", cm.toString());
@@ -112,7 +112,7 @@ public class ConfigMapTest {
 		
 		assertTextEquals("[MySection]|foo=bar|", cm);
 		
-		assertEquals("", join(cm.getPreLines("default"), '|'));
+		assertEquals("", join(cm.getPreLines(""), '|'));
 		assertEquals("", join(cm.getPreLines("MySection"), '|'));
 		assertEquals("", join(cm.getEntry("MySection", "foo").getPreLines(), '|'));
 		
@@ -137,7 +137,7 @@ public class ConfigMapTest {
 		
 		assertTextEquals("[MySection]|foo=bar|", cm);
 		
-		assertEquals("", join(cm.getPreLines("default"), '|'));
+		assertEquals("", join(cm.getPreLines(""), '|'));
 		
 		assertNull(cm.getPreLines("XXX"));
 
@@ -163,7 +163,7 @@ public class ConfigMapTest {
 		ConfigMap cm = s.getMap("Foo.cfg");
 		assertTextEquals("#S1|[S1]|#k1|k1=v1|#S2|[S2]|#k2|k2=v2|", cm);
 		
-		assertEquals("", join(cm.getPreLines("default"), '|'));
+		assertEquals("", join(cm.getPreLines(""), '|'));
 		assertEquals("#S1", join(cm.getPreLines("S1"), '|'));
 		assertEquals("#k1", join(cm.getEntry("S1", "k1").getPreLines(), '|'));
 		assertEquals("#S2", join(cm.getPreLines("S2"), '|'));
@@ -196,12 +196,12 @@ public class ConfigMapTest {
 		ConfigMap cm = s.getMap("Foo.cfg");
 		assertTextEquals("#D||#k|k=v|#S1|[S1]|#k1|k1=v1|", cm);
 
-		assertEquals("#D", join(cm.getPreLines("default"), '|'));
-		assertEquals("#k", join(cm.getEntry("default", "k").getPreLines(), '|'));
+		assertEquals("#D", join(cm.getPreLines(""), '|'));
+		assertEquals("#k", join(cm.getEntry("", "k").getPreLines(), '|'));
 		assertEquals("#S1", join(cm.getPreLines("S1"), '|'));
 		assertEquals("#k1", join(cm.getEntry("S1", "k1").getPreLines(), '|'));
 		
-		assertEquals("v", cm.getEntry("default", "k").getValue());
+		assertEquals("v", cm.getEntry("", "k").getValue());
 		assertEquals("v1", cm.getEntry("S1", "k1").getValue());
 		
 		// Round trip.
@@ -240,12 +240,12 @@ public class ConfigMapTest {
 		ConfigMap cm = s.getMap("Foo.cfg");
 		assertTextEquals("#Da|#Db||#ka||#kb||k=v||#S1a||#S1b||[S1]||#k1a||#k1b||k1=v1|", cm);
 
-		assertEquals("#Da|#Db", join(cm.getPreLines("default"), '|'));
-		assertEquals("#ka||#kb|", join(cm.getEntry("default", "k").getPreLines(), '|'));
+		assertEquals("#Da|#Db", join(cm.getPreLines(""), '|'));
+		assertEquals("#ka||#kb|", join(cm.getEntry("", "k").getPreLines(), '|'));
 		assertEquals("|#S1a||#S1b|", join(cm.getPreLines("S1"), '|'));
 		assertEquals("|#k1a||#k1b|", join(cm.getEntry("S1", "k1").getPreLines(), '|'));
 		
-		assertEquals("v", cm.getEntry("default", "k").getValue());
+		assertEquals("v", cm.getEntry("", "k").getValue());
 		assertEquals("v1", cm.getEntry("S1", "k1").getValue());
 		
 		// Round trip.
@@ -261,7 +261,7 @@ public class ConfigMapTest {
 	public void testMalformedSectionHeaders() throws Exception {
 		
 		String[] test = {
-			"[default]", "[ default ]", " [ default ] ", "\t[\tdefault\t]\t",
+			"[]", "[  ]", " [  ] ", "\t[\t\t]\t",
 			"[/]", "[[]", "[]]", "[\\]", 
 			"[foo/bar]", "[foo[bar]", "[foo]bar]", "[foo\\bar]", 
 			"[]", "[ ]", "[\t]", " [] ",
@@ -315,13 +315,13 @@ public class ConfigMapTest {
 		);		
 		ConfigMap cm = s.getMap("Foo.cfg");
 		
-		assertEquals("", join(cm.getEntry("default", "k1").getPreLines(), '|'));
-		assertEquals("", join(cm.getEntry("default", "k2").getPreLines(), '|'));
+		assertEquals("", join(cm.getEntry("", "k1").getPreLines(), '|'));
+		assertEquals("", join(cm.getEntry("", "k2").getPreLines(), '|'));
 
 		assertTextEquals("k1 = v1a,|\tv1b,|\tv1c|k2 = v2a,|\tv2b,|\tv2c|", cm);
 
-		assertEquals("v1a,\nv1b,\nv1c", cm.getEntry("default", "k1").getValue());
-		assertEquals("v2a,\nv2b,\nv2c", cm.getEntry("default", "k2").getValue());
+		assertEquals("v1a,\nv1b,\nv1c", cm.getEntry("", "k1").getValue());
+		assertEquals("v2a,\nv2b,\nv2c", cm.getEntry("", "k2").getValue());
 		
 		// Round trip.
 		s.update("Foo.cfg", cm.toString());
@@ -347,13 +347,13 @@ public class ConfigMapTest {
 		);		
 		ConfigMap cm = s.getMap("Foo.cfg");
 		
-		assertEquals("|#k1|", join(cm.getEntry("default", "k1").getPreLines(), '|'));
-		assertEquals("|#k2|", join(cm.getEntry("default", "k2").getPreLines(), '|'));
+		assertEquals("|#k1|", join(cm.getEntry("", "k1").getPreLines(), '|'));
+		assertEquals("|#k2|", join(cm.getEntry("", "k2").getPreLines(), '|'));
 
 		assertTextEquals("|#k1||k1 = v1a,|	v1b,|	v1c||#k2||k2 = v2a,|	v2b,|	v2c|", cm);
 
-		assertEquals("v1a,\nv1b,\nv1c", cm.getEntry("default", "k1").getValue());
-		assertEquals("v2a,\nv2b,\nv2c", cm.getEntry("default", "k2").getValue());
+		assertEquals("v1a,\nv1b,\nv1c", cm.getEntry("", "k1").getValue());
+		assertEquals("v2a,\nv2b,\nv2c", cm.getEntry("", "k2").getValue());
 		
 		// Round trip.
 		s.update("Foo.cfg", cm.toString());
@@ -549,12 +549,12 @@ public class ConfigMapTest {
 		ConfigStore s = initStore("Foo.cfg");		
 		ConfigMap cm = s.getMap("Foo.cfg");
 		
-		cm.setEntry("default", "k", "v1\nv2\nv3", null, null, null);
+		cm.setEntry("", "k", "v1\nv2\nv3", null, null, null);
 		cm.setEntry("S1", "k1", "v1\nv2\nv3", null, null, null);
 		
 		assertTextEquals("k = v1|	v2|	v3|[S1]|k1 = v1|	v2|	v3|", cm);
 		
-		assertEquals("v1\nv2\nv3", cm.getEntry("default", "k").getValue());
+		assertEquals("v1\nv2\nv3", cm.getEntry("", "k").getValue());
 		assertEquals("v1\nv2\nv3", cm.getEntry("S1", "k1").getValue());
 		cm.save();
 		assertTextEquals("k = v1|	v2|	v3|[S1]|k1 = v1|	v2|	v3|", cm);
@@ -569,12 +569,12 @@ public class ConfigMapTest {
 		ConfigStore s = initStore("Foo.cfg");		
 		ConfigMap cm = s.getMap("Foo.cfg");
 		
-		cm.setEntry("default", "k", "v1 \n v2 \n v3", null, null, null);
+		cm.setEntry("", "k", "v1 \n v2 \n v3", null, null, null);
 		cm.setEntry("S1", "k1", "v1\t\n\tv2\t\n\tv3", null, null, null);
 		
 		assertTextEquals("k = v1 |	 v2 |	 v3|[S1]|k1 = v1	|		v2	|		v3|", cm);
 		
-		assertEquals("v1 \n v2 \n v3", cm.getEntry("default", "k").getValue());
+		assertEquals("v1 \n v2 \n v3", cm.getEntry("", "k").getValue());
 		assertEquals("v1\t\n\tv2\t\n\tv3", cm.getEntry("S1", "k1").getValue());
 		cm.save();
 		assertTextEquals("k = v1 |	 v2 |	 v3|[S1]|k1 = v1	|		v2	|		v3|", cm);
@@ -611,11 +611,11 @@ public class ConfigMapTest {
 		);		
 		ConfigMap cm = s.getMap("Foo.cfg");
 		
-		cm.setSection("default", Arrays.asList("#D"));
+		cm.setSection("", Arrays.asList("#D"));
 		assertTextEquals("#D||[S1]|k1 = v1|", cm);
-		cm.setSection("default", Collections.<String>emptyList());
+		cm.setSection("", Collections.<String>emptyList());
 		assertTextEquals("[S1]|k1 = v1|", cm);
-		cm.setSection("default", null);
+		cm.setSection("", null);
 		assertTextEquals("[S1]|k1 = v1|", cm);
 	}
 
@@ -643,7 +643,7 @@ public class ConfigMapTest {
 		String[] test = {
 			"/", "[", "]",
 			"foo/bar", "foo[bar", "foo]bar", 
-			"", " ",
+			" ",
 			null
 		};
 		
@@ -711,12 +711,6 @@ public class ConfigMapTest {
 		assertTextEquals("[S1]|k1 = v1|[S2]|k2 = v2|", cm);
 		
 		try {
-			cm.removeSection("");
-			fail();
-		} catch (IllegalArgumentException e) {
-			assertEquals("Invalid section name: ''", e.getLocalizedMessage());
-		}
-		try {
 			cm.removeSection(null);
 			fail();
 		} catch (IllegalArgumentException e) {
@@ -736,7 +730,7 @@ public class ConfigMapTest {
 		);		
 		ConfigMap cm = s.getMap("Foo.cfg");
 		
-		cm.removeSection("default");
+		cm.removeSection("");
 		assertTextEquals("[S1]|k1 = v1|[S2]|k2 = v2|", cm);
 	}
 	
@@ -755,7 +749,7 @@ public class ConfigMapTest {
 		);		
 		ConfigMap cm = s.getMap("Foo.cfg");
 		
-		cm.removeSection("default");
+		cm.removeSection("");
 		assertTextEquals("[S1]|k1 = v1|[S2]|k2 = v2|", cm);
 	}
 	
@@ -890,7 +884,7 @@ public class ConfigMapTest {
 		String[] test = {
 			"/", "[", "]",
 			"foo/bar", "foo[bar", "foo]bar", 
-			"", " ",
+			" ",
 			null
 		};
 		
@@ -1086,7 +1080,7 @@ public class ConfigMapTest {
 		String[] test = {
 			"/", "[", "]",
 			"foo/bar", "foo[bar", "foo]bar", 
-			"", " ",
+			" ",
 			null
 		};
 		
diff --git a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/config/ConfigTest.java b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/config/ConfigTest.java
index 0bd1bfe..9795ace 100755
--- a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/config/ConfigTest.java
+++ b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/config/ConfigTest.java
@@ -49,7 +49,7 @@ public class ConfigTest {
 		Config c = init("a=1", "[S]", "b=2");
 		
 		assertEquals("1", c.get("a"));
-		assertEquals("1", c.get("default/a"));
+		assertEquals("1", c.get("a"));
 		assertEquals("2", c.get("S/b"));
 		assertNull(c.get("b"));
 		assertNull(c.get("S/c"));
@@ -73,13 +73,13 @@ public class ConfigTest {
 		
 		c.set("a1", "2");
 		c.set("a2", "3");
-		c.set("default/a3", "4");
+		c.set("a3", "4");
 		c.set("S/b1", "5");
 		c.set("S/b2", "6");
 		c.set("T/c1", "7");
 		
 		assertEquals("2", c.get("a1"));
-		assertEquals("3", c.get("default/a2"));
+		assertEquals("3", c.get("a2"));
 		assertEquals("4", c.get("a3"));
 		assertEquals("5", c.get("S/b1"));
 		assertEquals("6", c.get("S/b2"));
@@ -88,7 +88,7 @@ public class ConfigTest {
 		c.save();
 		
 		assertEquals("2", c.get("a1"));
-		assertEquals("3", c.get("default/a2"));
+		assertEquals("3", c.get("a2"));
 		assertEquals("4", c.get("a3"));
 		assertEquals("5", c.get("S/b1"));
 		assertEquals("6", c.get("S/b2"));
@@ -97,7 +97,7 @@ public class ConfigTest {
 		c = cb.build();
 		
 		assertEquals("2", c.get("a1"));
-		assertEquals("3", c.get("default/a2"));
+		assertEquals("3", c.get("a2"));
 		assertEquals("4", c.get("a3"));
 		assertEquals("5", c.get("S/b1"));
 		assertEquals("6", c.get("S/b2"));
@@ -115,13 +115,13 @@ public class ConfigTest {
 		
 		c.set("a1", 2);
 		c.set("a2", 3);
-		c.set("default/a3", 4);
+		c.set("a3", 4);
 		c.set("S/b1", 5);
 		c.set("S/b2", 6);
 		c.set("T/c1", 7);
 		
 		assertEquals("2", c.get("a1"));
-		assertEquals("3", c.get("default/a2"));
+		assertEquals("3", c.get("a2"));
 		assertEquals("4", c.get("a3"));
 		assertEquals("5", c.get("S/b1"));
 		assertEquals("6", c.get("S/b2"));
@@ -130,7 +130,7 @@ public class ConfigTest {
 		c.save();
 		
 		assertEquals("2", c.get("a1"));
-		assertEquals("3", c.get("default/a2"));
+		assertEquals("3", c.get("a2"));
 		assertEquals("4", c.get("a3"));
 		assertEquals("5", c.get("S/b1"));
 		assertEquals("6", c.get("S/b2"));
@@ -139,7 +139,7 @@ public class ConfigTest {
 		c = cb.build();
 		
 		assertEquals("2", c.get("a1"));
-		assertEquals("3", c.get("default/a2"));
+		assertEquals("3", c.get("a2"));
 		assertEquals("4", c.get("a3"));
 		assertEquals("5", c.get("S/b1"));
 		assertEquals("6", c.get("S/b2"));
@@ -158,13 +158,13 @@ public class ConfigTest {
 		ABean b = new ABean().init();
 		c.set("a1", b, UonSerializer.DEFAULT);
 		c.set("a2", b, UonSerializer.DEFAULT);
-		c.set("default/a3", b, UonSerializer.DEFAULT);
+		c.set("a3", b, UonSerializer.DEFAULT);
 		c.set("S/b1", b, UonSerializer.DEFAULT);
 		c.set("S/b2", b, UonSerializer.DEFAULT);
 		c.set("T/c1", b, UonSerializer.DEFAULT);
 		
 		assertEquals("(foo=bar)", c.get("a1"));
-		assertEquals("(foo=bar)", c.get("default/a2"));
+		assertEquals("(foo=bar)", c.get("a2"));
 		assertEquals("(foo=bar)", c.get("a3"));
 		assertEquals("(foo=bar)", c.get("S/b1"));
 		assertEquals("(foo=bar)", c.get("S/b2"));
@@ -181,7 +181,7 @@ public class ConfigTest {
 		ABean b = new ABean().init();
 		c.set("a1", b, UonSerializer.DEFAULT, ENCODED, "comment", Arrays.asList("#c1","#c2"));
 		c.set("a2", b, UonSerializer.DEFAULT, ENCODED, "comment", Arrays.asList("#c1","#c2"));
-		c.set("default/a3", b, UonSerializer.DEFAULT, ENCODED, "comment", Arrays.asList("#c1","#c2"));
+		c.set("a3", b, UonSerializer.DEFAULT, ENCODED, "comment", Arrays.asList("#c1","#c2"));
 		c.set("S/b1", b, UonSerializer.DEFAULT, ENCODED, "comment", Arrays.asList("#c1","#c2"));
 		c.set("S/b2", b, UonSerializer.DEFAULT, ENCODED, "comment", Arrays.asList("#c1","#c2"));
 		c.set("T/c1", b, UonSerializer.DEFAULT, ENCODED, "comment", Arrays.asList("#c1","#c2"));
@@ -193,7 +193,7 @@ public class ConfigTest {
 		assertTextEquals("#c1|#c2|a1* = {RhMWWFIFVksf} # comment|#c1|#c2|a2* = {RhMWWFIFVksf} # comment|#c1|#c2|a3* = {RhMWWFIFVksf} # comment|[S]|#c1|#c2|b1* = {RhMWWFIFVksf} # comment|#c1|#c2|b2* = {RhMWWFIFVksf} # comment|[T]|#c1|#c2|c1* = {RhMWWFIFVksf} # comment|", c.toString());
 
 		assertEquals("(foo=bar)", c.get("a1"));
-		assertEquals("(foo=bar)", c.get("default/a2"));
+		assertEquals("(foo=bar)", c.get("a2"));
 		assertEquals("(foo=bar)", c.get("a3"));
 		assertEquals("(foo=bar)", c.get("S/b1"));
 		assertEquals("(foo=bar)", c.get("S/b2"));
@@ -208,8 +208,8 @@ public class ConfigTest {
 		Config c = init("a1=1", "a2=2", "[S]", "b1=1");
 		
 		c.remove("a1");
-		c.remove("default/a2");
-		c.remove("default/a3");
+		c.remove("a2");
+		c.remove("a3");
 		c.remove("S/b1");
 		c.remove("T/c1");
 		
@@ -228,7 +228,7 @@ public class ConfigTest {
 		Config c = init("a1=1", "a2=2", "[S]", "b1=1", "b2=");
 		
 		assertEquals("1", c.getString("a1"));
-		assertEquals("2", c.getString("default/a2"));
+		assertEquals("2", c.getString("a2"));
 		assertEquals(null, c.getString("a3"));
 		assertEquals("1", c.getString("S/b1"));
 		assertEquals("", c.getString("S/b2"));
@@ -244,7 +244,7 @@ public class ConfigTest {
 		Config c = init("a1=1", "a2=2", "[S]", "b1=1", "b2=");
 		
 		assertEquals("1", c.getString("a1", "foo"));
-		assertEquals("2", c.getString("default/a2", "foo"));
+		assertEquals("2", c.getString("a2", "foo"));
 		assertEquals("foo", c.getString("a3", "foo"));
 		assertEquals("1", c.getString("S/b1", "foo"));
 		assertEquals("foo", c.getString("S/b2", "foo"));
@@ -260,7 +260,7 @@ public class ConfigTest {
 		Config c = init("a1=1,2", "a2= 2 , 3 ", "[S]", "b1=1", "b2=");
 		
 		assertObjectEquals("['1','2']", c.getStringArray("a1"));
-		assertObjectEquals("['2','3']", c.getStringArray("default/a2"));
+		assertObjectEquals("['2','3']", c.getStringArray("a2"));
 		assertObjectEquals("[]", c.getStringArray("a3"));
 		assertObjectEquals("['1']", c.getStringArray("S/b1"));
 		assertObjectEquals("[]", c.getStringArray("S/b2"));
@@ -276,7 +276,7 @@ public class ConfigTest {
 		Config c = init("a1=1,2", "a2= 2 , 3 ", "[S]", "b1=1", "b2=");
 		
 		assertObjectEquals("['1','2']", c.getStringArray("a1", new String[] {"foo"}));
-		assertObjectEquals("['2','3']", c.getStringArray("default/a2", new String[] {"foo"}));
+		assertObjectEquals("['2','3']", c.getStringArray("a2", new String[] {"foo"}));
 		assertObjectEquals("['foo']", c.getStringArray("a3", new String[] {"foo"}));
 		assertObjectEquals("['1']", c.getStringArray("S/b1", new String[] {"foo"}));
 		assertObjectEquals("['foo']", c.getStringArray("S/b2", new String[] {"foo"}));
@@ -292,7 +292,7 @@ public class ConfigTest {
 		Config c = init("a1=1", "a2=2", "[S]", "b1=1", "b2=");
 		
 		assertEquals(1, c.getInt("a1"));
-		assertEquals(2, c.getInt("default/a2"));
+		assertEquals(2, c.getInt("a2"));
 		assertEquals(0, c.getInt("a3"));
 		assertEquals(1, c.getInt("S/b1"));
 		assertEquals(0, c.getInt("S/b2"));
@@ -330,7 +330,7 @@ public class ConfigTest {
 		Config c = init("a1=1", "a2=2", "[S]", "b1=1", "b2=");
 		
 		assertEquals(1, c.getInt("a1", -1));
-		assertEquals(2, c.getInt("default/a2", -1));
+		assertEquals(2, c.getInt("a2", -1));
 		assertEquals(-1, c.getInt("a3", -1));
 		assertEquals(1, c.getInt("S/b1", -1));
 		assertEquals(-1, c.getInt("S/b2", -1));
@@ -368,7 +368,7 @@ public class ConfigTest {
 		Config c = init("a1=true", "a2=false", "[S]", "b1=TRUE", "b2=");
 		
 		assertEquals(true, c.getBoolean("a1"));
-		assertEquals(false, c.getBoolean("default/a2"));
+		assertEquals(false, c.getBoolean("a2"));
 		assertEquals(false, c.getBoolean("a3"));
 		assertEquals(true, c.getBoolean("S/b1"));
 		assertEquals(false, c.getBoolean("S/b2"));
@@ -394,7 +394,7 @@ public class ConfigTest {
 		Config c = init("a1=true", "a2=false", "[S]", "b1=TRUE", "b2=");
 		
 		assertEquals(true, c.getBoolean("a1", true));
-		assertEquals(false, c.getBoolean("default/a2", true));
+		assertEquals(false, c.getBoolean("a2", true));
 		assertEquals(true, c.getBoolean("a3", true));
 		assertEquals(true, c.getBoolean("S/b1", true));
 		assertEquals(true, c.getBoolean("S/b2", true));
@@ -420,7 +420,7 @@ public class ConfigTest {
 		Config c = init("a1=1", "a2=2", "[S]", "b1=1", "b2=");
 		
 		assertEquals(1l, c.getLong("a1"));
-		assertEquals(2l, c.getLong("default/a2"));
+		assertEquals(2l, c.getLong("a2"));
 		assertEquals(0l, c.getLong("a3"));
 		assertEquals(1l, c.getLong("S/b1"));
 		assertEquals(0l, c.getLong("S/b2"));
@@ -458,7 +458,7 @@ public class ConfigTest {
 		Config c = init("a1=1", "a2=2", "[S]", "b1=1", "b2=");
 		
 		assertEquals(1l, c.getLong("a1", Long.MAX_VALUE));
-		assertEquals(2l, c.getLong("default/a2", Long.MAX_VALUE));
+		assertEquals(2l, c.getLong("a2", Long.MAX_VALUE));
 		assertEquals(Long.MAX_VALUE, c.getLong("a3", Long.MAX_VALUE));
 		assertEquals(1l, c.getLong("S/b1", Long.MAX_VALUE));
 		assertEquals(Long.MAX_VALUE, c.getLong("S/b2", Long.MAX_VALUE));
@@ -496,7 +496,7 @@ public class ConfigTest {
 		Config c = init("a1=Zm9v", "a2=Zm", "\t9v", "a3=");
 		
 		assertObjectEquals("[102,111,111]", c.getBytes("a1"));
-		assertObjectEquals("[102,111,111]", c.getBytes("default/a2"));
+		assertObjectEquals("[102,111,111]", c.getBytes("a2"));
 		assertObjectEquals("[]", c.getBytes("a3"));
 		assertNull(null, c.getBytes("a4"));
 	}
@@ -509,7 +509,7 @@ public class ConfigTest {
 		Config c = init("a1=Zm9v", "a2=Zm", "\t9v", "a3=");
 		
 		assertObjectEquals("[102,111,111]", c.getBytes("a1", new byte[] {1}));
-		assertObjectEquals("[102,111,111]", c.getBytes("default/a2", new byte[] {1}));
+		assertObjectEquals("[102,111,111]", c.getBytes("a2", new byte[] {1}));
 		assertObjectEquals("[1]", c.getBytes("a3", new byte[] {1}));
 		assertObjectEquals("[1]", c.getBytes("a4", new byte[] {1}));
 	}
@@ -865,7 +865,7 @@ public class ConfigTest {
 	public void getKeys() throws Exception {
 		Config c = init("a1=1", "a2=2", "[S]", "b1=1", "b2=");
 		
-		assertObjectEquals("['a1','a2']", c.getKeys("default"));
+		assertObjectEquals("['a1','a2']", c.getKeys(""));
 		assertObjectEquals("['a1','a2']", c.getKeys(""));
 		assertObjectEquals("['b1','b2']", c.getKeys("S"));
 		assertTrue(c.getKeys("T").isEmpty());
@@ -913,7 +913,7 @@ public class ConfigTest {
 
 		c.writeProperties("", b, true);
 		assertObjectEquals("{foo:'qux'}", b);
-		c.writeProperties("default", a, true);
+		c.writeProperties("", a, true);
 		assertObjectEquals("{foo:'qux'}", a);
 
 		try {
@@ -935,14 +935,14 @@ public class ConfigTest {
 		
 		a = c.getSectionAsBean("", ABean.class);
 		assertObjectEquals("{foo:'qux'}", a);
-		a = c.getSectionAsBean("default", ABean.class);
+		a = c.getSectionAsBean("", ABean.class);
 		assertObjectEquals("{foo:'qux'}", a);
 		a = c.getSectionAsBean("S", ABean.class);
 		assertObjectEquals("{foo:'baz'}", a);
 		
 		b = c.getSectionAsBean("", BBean.class);
 		assertObjectEquals("{foo:'qux'}", b);
-		b = c.getSectionAsBean("default", BBean.class);
+		b = c.getSectionAsBean("", BBean.class);
 		assertObjectEquals("{foo:'qux'}", b);
 		b = c.getSectionAsBean("S", BBean.class);
 		assertObjectEquals("{foo:'baz'}", b);
@@ -1026,7 +1026,7 @@ public class ConfigTest {
 		Config c = init("a=1", "[S]", "b=2", "[T]");
 		
 		assertObjectEquals("{a:'1'}", c.getSectionAsMap(""));
-		assertObjectEquals("{a:'1'}", c.getSectionAsMap("default"));
+		assertObjectEquals("{a:'1'}", c.getSectionAsMap(""));
 		assertObjectEquals("{b:'2'}", c.getSectionAsMap("S"));
 		assertObjectEquals("{}", c.getSectionAsMap("T"));
 		assertNull(c.getSectionAsMap("U"));
@@ -1049,7 +1049,7 @@ public class ConfigTest {
 		a = c.getSectionAsInterface("", AInterface.class);
 		assertEquals("qux", a.getFoo());
 	
-		a = c.getSectionAsInterface("default", AInterface.class);
+		a = c.getSectionAsInterface("", AInterface.class);
 		assertEquals("qux", a.getFoo());
 
 		a = c.getSectionAsInterface("S", AInterface.class);
@@ -1101,7 +1101,7 @@ public class ConfigTest {
 		c.setSection("", Arrays.asList("#C1", "#C2"));
 		assertTextEquals("#C1|#C2||", c);
 
-		c.setSection("default", Arrays.asList("#C3", "#C4"));
+		c.setSection("", Arrays.asList("#C3", "#C4"));
 		assertTextEquals("#C3|#C4||", c);
 		
 		c.setSection("S1", Arrays.asList("", "#C5", "#C6"));
@@ -1132,7 +1132,7 @@ public class ConfigTest {
 		c.setSection("", Arrays.asList("#C1", "#C2"), m);
 		assertTextEquals("#C1|#C2||a = b|", c);
 
-		c.setSection("default", Arrays.asList("#C3", "#C4"), m);
+		c.setSection("", Arrays.asList("#C3", "#C4"), m);
 		assertTextEquals("#C3|#C4||a = b|", c);
 		
 		c.setSection("S1", Arrays.asList("", "#C5", "#C6"), m);
@@ -1164,7 +1164,7 @@ public class ConfigTest {
 		
 		assertTextEquals("a=1|", c);
 		
-		c.removeSection("default");
+		c.removeSection("");
 		assertTextEquals("", c);
 	}
 
@@ -1426,7 +1426,7 @@ public class ConfigTest {
 				@Override
 				public void onConfigChange(List<ConfigEvent> events) {
 					for (ConfigEvent ce : events) {
-						String key = (ce.getSection().equals("default") ? "" : (ce.getSection() + '/')) + ce.getKey();
+						String key = (ce.getSection().equals("") ? "" : (ce.getSection() + '/')) + ce.getKey();
 						if (ce.getType() == ConfigEventType.REMOVE_ENTRY) {
 							changes.add("REMOVE_ENTRY("+key+")");
 						} else if (ce.getType() == ConfigEventType.REMOVE_SECTION) {
diff --git a/juneau-doc/src/main/javadoc/overview.html b/juneau-doc/src/main/javadoc/overview.html
index ed2ca98..e15f399 100644
--- a/juneau-doc/src/main/javadoc/overview.html
+++ b/juneau-doc/src/main/javadoc/overview.html
@@ -4672,372 +4672,276 @@
 	<a id="juneau-config.Overview"></a>
 	<h3 class='topic' onclick='toggle(this)'>6.1 - Overview</h3>
 	<div class='topic'>
-	</div>
-
-	<!-- ======================================================================================================== -->
-	<a id="juneau-config.EntryTypes"></a>
-	<h3 class='topic' onclick='toggle(this)'>6.2 - Entry Types</h3>
-	<div class='topic'>
-
-		<!-- ======================================================================================================== -->
-		<a id="juneau-config.PrimitiveTypes"></a>
-		<h4 class='topic' onclick='toggle(this)'>6.2.1 - Primitive Types</h4>
-		<div class='topic'>
-		</div>
-
-		<!-- ======================================================================================================== -->
-		<a id="juneau-config.POJOs"></a>
-		<h4 class='topic' onclick='toggle(this)'>6.2.2 - POJOs</h4>
-		<div class='topic'>
-		</div>
-
-		<!-- ======================================================================================================== -->
-		<a id="juneau-config.Arrays"></a>
-		<h4 class='topic' onclick='toggle(this)'>6.2.3 - Arrays</h4>
-		<div class='topic'>
-		</div>
-
-		<!-- ======================================================================================================== -->
-		<a id="juneau-config.Collections"></a>
-		<h4 class='topic' onclick='toggle(this)'>6.2.4 - Collections</h4>
-		<div class='topic'>
-		</div>
-
-		<!-- ======================================================================================================== -->
-		<a id="juneau-config.BinaryData"></a>
-		<h4 class='topic' onclick='toggle(this)'>6.2.5 - Binary Data</h4>
-		<div class='topic'>
-		</div>
-
-	</div>
-
-	<!-- ======================================================================================================== -->
-	<a id="juneau-config.Variables"></a>
-	<h3 class='topic' onclick='toggle(this)'>6.3 - Variables</h3>
-	<div class='topic'>
-	</div>
-
-	<!-- ======================================================================================================== -->
-	<a id="juneau-config.EncodedEntries"></a>
-	<h3 class='topic' onclick='toggle(this)'>6.4 - Encoded Entries</h3>
-	<div class='topic'>
-	</div>
-
-	<!-- ======================================================================================================== -->
-	<a id="juneau-config.SectionMaps"></a>
-	<h3 class='topic' onclick='toggle(this)'>6.5 - Section Maps</h3>
-	<div class='topic'>
-	</div>
-
-	<!-- ======================================================================================================== -->
-	<a id="juneau-config.SectionBeans"></a>
-	<h3 class='topic' onclick='toggle(this)'>6.6 - Section Beans</h3>
-	<div class='topic'>
-	</div>
-
-	<!-- ======================================================================================================== -->
-	<a id="juneau-config.SectionInterfaces"></a>
-	<h3 class='topic' onclick='toggle(this)'>6.7 - Section Interfaces</h3>
-	<div class='topic'>
-	</div>
-
-	<!-- ======================================================================================================== -->
-	<a id="juneau-config.SettingValues"></a>
-	<h3 class='topic' onclick='toggle(this)'>6.8 - Setting Values</h3>
-	<div class='topic'>
-
-		<!-- ======================================================================================================== -->
-		<a id="juneau-config.CustomEntrySerialization"></a>
-		<h4 class='topic' onclick='toggle(this)'>6.8.1 - Custom Entry Serialization</h4>
-		<div class='topic'>
-		</div>
-
-		<!-- ======================================================================================================== -->
-		<a id="juneau-config.BulkSettingValues"></a>
-		<h4 class='topic' onclick='toggle(this)'>6.8.2 - Setting Values in Bulk</h4>
-		<div class='topic'>
-		</div>
-
-	</div>
-
-	<!-- ======================================================================================================== -->
-	<a id="juneau-config.Listeners"></a>
-	<h3 class='topic' onclick='toggle(this)'>6.9 - Listeners</h3>
-	<div class='topic'>
-	</div>
-
-	<!-- ======================================================================================================== -->
-	<a id="juneau-config.Serializing"></a>
-	<h3 class='topic' onclick='toggle(this)'>6.10 - Serializing</h3>
-	<div class='topic'>
-	</div>
-
-	<!-- ======================================================================================================== -->
-	<a id="juneau-config.ConfigStores"></a>
-	<h3 class='topic' onclick='toggle(this)'>6.11 - Config Stores</h3>
-	<div class='topic'>
-		
-		<!-- ======================================================================================================== -->
-		<a id="juneau-config.ConfigMemoryStore"></a>
-		<h4 class='topic' onclick='toggle(this)'>6.11.1 - ConfigMemoryStore</h4>
-		<div class='topic'>
-		</div>
-		
-		<!-- ======================================================================================================== -->
-		<a id="juneau-config.ConfigFileStore"></a>
-		<h4 class='topic' onclick='toggle(this)'>6.11.2 - ConfigFileStoren</h4>
-		<div class='topic'>
-		</div>
-
-	</div>
-
-	<!-- ======================================================================================================== -->
-	<a id="juneau-config.ReadOnlyConfigs"></a>
-	<h3 class='topic' onclick='toggle(this)'>6.12 - Read-only Configs</h3>
-	<div class='topic'>
-	</div>
-
-	<!-- ======================================================================================================== -->
-	<a id="#juneau-config.ClosingConfigs"></a>
-	<h3 class='topic' onclick='toggle(this)'>6.13 - Closing Configs</h3>
-	<div class='topic'>
-	</div>
-
-	
-	<!-- ======================================================================================================== -->
-	<a id="juneau-config.Overview"></a>
-	<h3 class='topic' onclick='toggle(this)'>6.1 - Overview</h3>
-	<div class='topic'>
 		<p>
 			The <code>juneau-config</code> library contains a powerful API for creating and using INI-style config files.
 		</p>
 		<p>
-			An example of the cotents of a config file:
+			An example of the contents of a config file:
 		</p>
 		<p class='bcode'>
-	<cc># Default section</cc>
+	<cs>[Section1]</cs>
+
+	<cc># An integer</cc>
 	<ck>key1</ck> = <cv>1</cv>
+
+	<cc># A boolean</cc>
 	<ck>key2</ck> = <cv>true</cv>
-	<ck>key3</ck> = <cv>[1,2,3]</cv>
-	<ck>key4</ck> = <cv>http://foo</cv>
 	
-	<cc># Section 1</cc>
-	<cs>[Section1]</cs>
-	<ck>key1</ck> = <cv>2</cv>
-	<ck>key2</ck> = <cv>false</cv>
-	<ck>key3</ck> = <cv>[4,5,6]</cv>
+	<cc># An array</cc>
+	<ck>key3</ck> = <cv>1,2,3</cv>
+
+	<cc># A POJO</cc>
 	<ck>key4</ck> = <cv>http://bar</cv>
 		</p>
 		<p>
-			This class can be used to easily access contents of the file:
+			This code shows how the file can be accessed:
 		</p>
 		<p class='bcode'>
-	<jk>int</jk> key1;
-	<jk>boolean</jk> key2;
-	<jk>int</jk>[] key3;
-	URL key4;
-	
 	<jc>// Load our config file</jc>
-	Config f = Config.<jsm>create</jsm>().name(<js>"MyConfig.cfg"</js>).build();
-	
-	<jc>// Read values from default section</jc>
-	key1 = f.getInt(<js>"key1"</js>);
-	key2 = f.getBoolean(<js>"key2"</js>);
-	key3 = f.getObject(<jk>int</jk>[].<jk>class</jk>, <js>"key3"</js>);
-	key4 = f.getObject(URL.<jk>class</jk>, <js>"key4"</js>);
+	Config c = Config.<jsm>create</jsm>().name(<js>"MyConfig.cfg"</js>).build();
 	
 	<jc>// Read values from section #1</jc>
-	key1 = f.getInt(<js>"Section1/key1"</js>);
-	key2 = f.getBoolean(<js>"Section1/key2"</js>);
-	key3 = f.getObject(<jk>int</jk>[].<jk>class</jk>, <js>"Section1/key3"</js>);
-	key4 = f.getObject(URL.<jk>class</jk>, <js>"Section1/key4"</js>);
+	<jk>int</jk> key1 = c.getInt(<js>"Section1/key1"</js>);
+	<jk>boolean</jk>key2 = c.getBoolean(<js>"Section1/key2"</js>);
+	<jk>int</jk>[]key3 = c.getObject(<js>"Section1/key3"</js>, <jk>int</jk>[].<jk>class</jk>, );
+	URL key4 = c.getObject(<js>"Section1/key4"</js>, URL.<jk>class</jk>);
 		</p>
 		<p>
-			The interface also allows a config file to be easily constructed programmatically:
-		</p>
-		<p class='bcode'>
-	<jc>// Construct the sample config file programmatically</jc>
-	Config cf = Config.<jsm>create</jsm>().name(<js>"MyConfig.cfg"</js>).build()
-		.addLines(<jk>null</jk>,
-			<js>"# Default section"</js>,
-			<js>"key1 = 1"</js>,
-			<js>"key2 = true"</js>,
-			<js>"key3 = [1,2,3]"</js>,
-			<js>"key4 = http://foo"</js>,
-			<js>""</js>)
-		.addHeaderComments(<js>"Section1"</js>,
-			<js>"# Section 1"</js>)
-		.addLines(<js>"Section1"</js>,
-			<js>"key1 = 2"</js>,
-			<js>"key2 = false"</js>,
-			<js>"key3 = [4,5,6]"</js>,
-			<js>"key4 = http://bar"</js>)
-		.save();
-		</p>
-		<p>
-			The following is equivalent, except that it uses <code><del>Config#put(String, Object)</del></code> 
-			to set values:
-		</p>
-		<p class='bcode'>
-	<jc>// Construct the sample config file programmatically</jc>
-	Config cf = Config.<jsm>create</jsm>().name(<js>"MyConfig.cfg"</js>).build()
-		.addLines(<jk>null</jk>,
-			<js>"# Default section"</js>)
-		.addHeaderComments(<js>"section1"</js>,
-			<js>"# Section 1"</js>);
-	cf.put(<js>"key1"</js>, 1);
-	cf.put(<js>"key2"</js>, <jk>true</jk>);
-	cf.put(<js>"key3"</js>, <jk>new int</jk>[]{1,2,3});
-	cf.put(<js>"key4"</js>, <jk>new</jk> URL(<js>"http://foo"</js>));
-	cf.put(<js>"Section1/key1"</js>, 2);
-	cf.put(<js>"Section1/key2"</js>, <jk>false</jk>);
-	cf.put(<js>"Section1/key3"</js>, <jk>new int</jk>[]{4,5,6});
-	cf.put(<js>"Section1/key4"</js>, <jk>new</jk> URL(<js>"http://bar"</js>));
-	cf.save();
-		</p>
-		<p>
-			Values are LAX JSON (i.e. unquoted attributes, single quotes) except for top-level strings which are left 
-			unquoted.  
-			<br>Any <a class='doclink' href='#juneau-marshall.PojoCategories'>parsable</a> types are supported as values (e.g. arrays, collections, beans, swappable objects, 
-			enums, etc...).
-		</p>
-		<p>
-			The config file looks deceptively simple, the config file API is a very powerful feature with many 
-			capabilities, including:
+			The config language may look simple, but it is a very powerful feature with many capabilities including:
 		</p>
 		<ul class='spaced-list'>
 			<li>
-				The ability to use variables to reference environment variables, system properties, other config file 
-				entries, and a host of other types.
-			<li>
 				APIs for updating, modifying, and saving configuration files <b style='text-decoration: underline;'>without losing comments or formatting</b>!
 			<li>
+				The ability to use variables to reference environment variables, system properties, other config file entries, and a host of other types.
+			<li>
 				Extensive listener APIs.
+			<li>
+				Full file system watcher integration.
+			<li>
+				Support for user-defined storage mechanisms.
 		</ul>
 		
-		<h5 class='figure'>Example:</h5>
-		<p class='bcode'>
-	<cc>#--------------------------</cc>
-	<cc># My section</cc>
-	<cc>#--------------------------</cc>
-	<cs>[MySection]</cs>
-	
-	<cc># An integer</cc>
-	<ck>anInt</ck> = <cv>1</cv> 
-	
-	<cc># A boolean</cc>
-	<ck>aBoolean</ck> = <cv>true</cv>
-	
-	<cc># An int array</cc>
-	<ck>anIntArray</ck> = <cv>[1,2,3]</cv>
-	
-	<cc># A POJO that can be converted from a String</cc>
-	<ck>aURL</ck> = <cv>http://foo </cv>
-	
-	<cc># A POJO that can be converted from JSON</cc>
-	<ck>aBean</ck> = <cv>{foo:'bar',baz:123}</cv>
-		</p>
-		<p class='bcode'>
-	<jc>// Java code for accessing config entries above.</jc>
-	Config cf = Config.<jsf>create</jsf>().name(<js>"MyConfig.cfg"</js>).build();
+		<!-- ======================================================================================================== -->
+		<a id="juneau-config.EntryTypes"></a>
+		<h4 class='topic' onclick='toggle(this)'>6.1.1 - Formatting Rules</h4>
+		<div class='topic'>
+			<p>
+				Each config file contains zero or more sections containing zero or more entries:
+			</p>
+			<p class='bcode'>
+		<cs>[Section1]</cs>
+		<ck>key1</ck> = <cv>1</cv>
 	
-	<jk>int</jk> anInt = cf.getInt(<js>"MySection/anInt"</js>); 
-	<jk>boolean</jk> aBoolean = cf.getBoolean(<js>"MySection/aBoolean"</js>); 
-	<jk>int</jk>[] anIntArray = cf.getObject(<jk>int</jk>[].<jk>class</jk>, <js>"MySection/anIntArray"</js>); 
-	URL aURL = cf.getObject(URL.<jk>class</jk>, <js>"MySection/aURL"</js>); 
-	MyBean aBean = cf.getObject(MyBean.<jk>class</jk>, <js>"MySection/aBean"</js>); 
-		</p>
+		<cs>[Section2]</cs>
+		<ck>key1</ck> = <cv>2</cv>
+			</p>
+			<p>
+				Comments start with the <js>'#'</js> character and can be placed on lines before sections and entries:
+			</p>
+			<p class='bcode'>
+		<cs># A comment about this section</cs>
+		<cs>[Section1]</cs>
+		
+		<cs># A comment about this entry</cs>
+		<ck>key1</ck> = <cv>1</cv>
+			</p>
+			<p>
+				Comments can also be placed on the same line as entries:
+			</p>
+			<p class='bcode'>
+		
+		<ck>key1</ck> = <cv>1</cv> <cs># A comment about this entry
+			</p>
+			<p>
+				Values containing <js>'#'</js> must be escaped to prevent identification as a comment character:
+			</p>
+			<p class='bcode'>
+		<ck>valueContainingPound</ck> = <cv>Value containing \# character</cv>
+			</p>
+			<p>
+				Values containing newlines can span multiple lines.
+				<br>Subsequent lines start with a tab character.
+			</p>
+			<p class='bcode'>
+		<ck>multiLineValue</ck> = <cv>Line 1,</cv>
+			<cv>Line 2,</cv>
+			<cv>Line 3</cv>
+			</p>
+			<p>
+				Blank lines can be used anywhere in the file.
+			</p>
+			<p class='bcode'>
+		<cs># A comment line</cs>
+		
+		<cs># Another comment line</cs>
+		<cs>[Section1]</cs>
+			</p>
+			<p>
+				Values located before any sections are considered part of the no-name section, meaning
+				they are accessed simply by key and not section+key.
+			</p>
+			<p class='bcode'>
+		<cs># Top of file</cs>
+		
+		<cs># A value in the no-name section</cs>
+		<ck>key1</ck> = <cv>val1</cv>
+		
+		<cs># The first section</cs>
+		<cs>[Section1]</cs>
+			</p>
+			<p>
+				Section and key names must be at least one character long and not consist of any of the following
+				characters:
+				<br><code>/ \ [ ] = #</code>
+			</p>
+			<p>
+				Leading and trailing whitespace on values are ignored.
+			</p>
+		</div>
 	</div>
-	
+		
 	<!-- ======================================================================================================== -->
-	<a id="juneau-config.SectionBeans"></a>
-	<h3 class='topic' onclick='toggle(this)'>6.2 - Section Beans</h3>
+	<a id="juneau-config.EntryTypes"></a>
+	<h3 class='topic' onclick='toggle(this)'>6.2 - Entry Types</h3>
 	<div class='topic'>
 		<p>
-			Config files can also be used to directly populate beans using the 
-			{@link org.apache.juneau.config.Config#getSectionAsBean(String,Class,boolean)}:
+			Configuration files can contain entries for anything from primitive types up to complex hierarchies of POJOs consisting of maps, collections, and/or beans.
 		</p>
-		<p class='bcode'>
-	<jc>// Example config file</jc>
-	<cs>[MyAddress]</cs>
-	<ck>name</ck> = <cv>John Smith</cv>
-	<ck>street</ck> = <cv>123 Main Street</cv>
-	<ck>city</ck> = <cv>Anywhere</cv>
-	<ck>state</ck> = <cv>NY</cv>
-	<ck>zip</ck> = <cv>12345</cv>
-
-	<jc>// Example bean</jc>
-	<jk>public class</jk> Address {
-		public String name, street, city;
-		public StateEnum state;
-		public int zip;
-	}
-
-	<jc>// Example usage</jc>
-	Config cf = Config.<jsm>create</jsm>().name(<js>"MyConfig.cfg"</js>).build();
-	Address myAddress = cf.getSectionAsBean(<js>"MySection"</js>, Address.<jk>class</jk>);
-		</p>
-	</div>
 
-	<!-- ======================================================================================================== -->
-	<a id="juneau-config.SectionInterfaces"></a>
-	<h3 class='topic' onclick='toggle(this)'>6.3 - Section Interfaces</h3>
-	<div class='topic'>
-		<p>
-			Config file sections can also be accessed via interface proxies using 
-			{@link org.apache.juneau.config.Config#getSectionAsInterface(String,Class)}:
-		</p>
-		<p class='bcode'>
-	<jc>// Example config file</jc>
-	<cs>[MySection]</cs>
-	<ck>string</ck> = <cv>foo</cv>
-	<ck>int</ck> = <cv>123</cv>
-	<ck>enum</ck> = <cv>ONE</cv>
-	<ck>bean</ck> = <cv>{foo:'bar',baz:123}</cv>
-	<ck>int3dArray</ck> = <cv>[[[123,null],null],null]</cv>
-	<ck>bean1d3dListMap</ck> = <cv>{key:[[[[{foo:'bar',baz:123}]]]]}</cv>
+		<!-- ======================================================================================================== -->
+		<a id="juneau-config.PrimitiveTypes"></a>
+		<h4 class='topic' onclick='toggle(this)'>6.2.1 - Primitive Types</h4>
+		<div class='topic'>
+			<p>
+				The most common case for configuration values are primitives.
+			</p>
+			<p class='bcode'>
+	<cc># A string</cc>
+	<ck>key1</ck> = <cv>foo</cv>
 
-	<jc>// Example interface.</jc>
-	<jc>// Setters are optional.</jc>
-	<jk>public interface</jk> MyConfigInterface {
+	<cc># A boolean</cc>
+	<ck>key2</ck> = <cv>true</cv>
 
-		String getString();
-		<jk>void</jk> setString(String x);
+	<cc># An integer</cc>
+	<ck>key3</ck> = <cv>123</cv>
+	
+	<cc># A long</cc>
+	<ck>key4</ck> = <cv>10000000000</cv>
+			</p>
+			<p>
+				The following methods are provided for accessing primitive values:
+			</p>
+			<ul class='doctree'>
+				<li class='jc'>{@link org.apache.juneau.config.Config}
+				<ul>
+					<li class='jm'>{@link org.apache.juneau.config.Config#getString(String) getString(String)}
+					<li class='jm'>{@link org.apache.juneau.config.Config#getString(String,String) getString(String,String)}
+					<li class='jm'>{@link org.apache.juneau.config.Config#getBoolean(String) getBoolean(String)}
+					<li class='jm'>{@link org.apache.juneau.config.Config#getBoolean(String,boolean) getBoolean(String,boolean)}
+					<li class='jm'>{@link org.apache.juneau.config.Config#getInt(String) getInt(String)}
+					<li class='jm'>{@link org.apache.juneau.config.Config#getInt(String,int) getInt(String,int)}
+					<li class='jm'>{@link org.apache.juneau.config.Config#getLong(String) getLong(String)}
+					<li class='jm'>{@link org.apache.juneau.config.Config#getLong(String,long) getLong(String,long)}
+				</ul>
+			</ul>
+			<p>
+				On integers and longs, <js>"K"</js>, <js>"M"</js>, and <js>"G"</js> can be used to identify kilo, mega, and giga.
+			</p>	
+			<p class='bcode'>
+	<ck>key1</ck> = <cv>100K</cv> <cc># Same as 1024000</cc>
+	<ck>key2</ck> = <cv>100M</cv> <cc># Same as 104857600</cc>
+			</p>
+			<p>
+				Strings can be broken into separate lines by starting the next line with a tab:
+			</p>
+			<p class='bcode'>
+	<ck>key1</ck> = <cv>This is a particularly long sentence that we want to split</cv>
+		<cv>onto separate lines</cv>.
+			</p>
+			<p>
+				Broken lines are not trimmed between lines, and are concatenated with newlines.
+				<br>The example above translates to <js>"This is a particularly....split\nonto separate lines"</js>, but
+				could could pad the start and end of lines with spaces if you wish.
+			</p>
 
-		<jk>int</jk> getInt();
-		<jk>void</jk> setInt(<jk>int</jk> x);
+		</div>
 
-		MyEnum getEnum();
-		<jk>void</jk> setEnum(MyEnum x);
+		<!-- ======================================================================================================== -->
+		<a id="juneau-config.POJOs"></a>
+		<h4 class='topic' onclick='toggle(this)'>6.2.2 - POJOs</h4>
+		<div class='topic'>
+			<p>
+				The following methods are provided for accessing POJO values:
+			</p>
+			<ul class='doctree'>
+				<li class='jc'>{@link org.apache.juneau.config.Config}
+				<ul>
+					<li class='jm'>{@link org.apache.juneau.config.Config#getObject(String,Class) getObject(String,Class)}
+					<li class='jm'>{@link org.apache.juneau.config.Config#getObject(String,Parser,Class) getObject(String,Parser,Class)}
+					<li class='jm'>{@link org.apache.juneau.config.Config#getObjectWithDefault(String,T,Class) getObjectWithDefault(String,T,Class)}
+					<li class='jm'>{@link org.apache.juneau.config.Config#getObjectWithDefault(String,T,Parser,Class) getObjectWithDefault(String,T,Parser,Class)}
+				</ul>
+			</ul>
+		</div>
 
-		MyBean getBean();
-		<jk>void</jk> setBean(MyBean x);
+		<!-- ======================================================================================================== -->
+		<a id="juneau-config.Arrays"></a>
+		<h4 class='topic' onclick='toggle(this)'>6.2.3 - Arrays</h4>
+		<div class='topic'>
+			<p>
+				The following methods are provided for accessing arrays:
+			</p>
+			<ul class='doctree'>
+				<li class='jc'>{@link org.apache.juneau.config.Config}
+				<ul>
+					<li class='jm'>{@link org.apache.juneau.config.Config#getStringArray(String) getStringArray(String)}
+					<li class='jm'>{@link org.apache.juneau.config.Config#getStringArray(String,String[]) getStringArray(String,String)}
+					<li class='jm'>{@link org.apache.juneau.config.Config#getObject(String,Class) getObject(String,Class)}
+					<li class='jm'>{@link org.apache.juneau.config.Config#getObject(String,Parser,Class) getObject(String,Parser,Class)}
+				</ul>
+			</ul>
+		</div>
 
-		<jk>int</jk>[][][] getInt3dArray();
-		<jk>void</jk> setInt3dArray(<jk>int</jk>[][][] x);
-		
-		Map&lt;String,List&lt;MyBean[][][]&gt;&gt; getBean1d3dListMap();
-		<jk>void</jk> setBean1d3dListMap(Map&lt;String,List&lt;MyBean[][][]&gt;&gt; x);
-	}
-	
-	<jc>// Example usage.</jc>
-	Config cf = Config.<jsm>create</jsm>().name(<js>"MyConfig.cfg"</js>).build();
-	MyConfigInterface ci = cf.getSectionAsInterface(<js>"MySection"</js>, MyConfigInterface.<jk>class</jk>);
-	
-	<jc>// Read a value.</jc>
-	<jk>int</jk> myInt = ci.getInt();
+		<!-- ======================================================================================================== -->
+		<a id="juneau-config.Collections"></a>
+		<h4 class='topic' onclick='toggle(this)'>6.2.4 - Collections</h4>
+		<div class='topic'>
+			<p>
+				The following methods are provided for accessing maps and collections:
+			</p>
+			<ul class='doctree'>
+				<li class='jc'>{@link org.apache.juneau.config.Config}
+				<ul>
+					<li class='jm'>{@link org.apache.juneau.config.Config#getObject(String,Type,Type...) getObject(String,Type,Type...)}
+					<li class='jm'>{@link org.apache.juneau.config.Config#getObject(String,Parser,Type,Type...) getObject(String,Parser,Type,Type...)}
+					<li class='jm'>{@link org.apache.juneau.config.Config#getObjectWithDefault(String,T,Type,Type...) getObjectWithDefault(String,T,Type,Type...)}
+					<li class='jm'>{@link org.apache.juneau.config.Config#getObjectWithDefault(String,T,Parser,Type,Type...) getObjectWithDefault(String,T,Parser,Type,Type...)}
+				</ul>
+			</ul>
+		</div>
 
-	<jc>// Write a value.</jc>
-	ci.setBean(<jk>new</jk> MyBean());
+		<!-- ======================================================================================================== -->
+		<a id="juneau-config.BinaryData"></a>
+		<h4 class='topic' onclick='toggle(this)'>6.2.5 - Binary Data</h4>
+		<div class='topic'>
+			<p>
+				The following methods are provided for accessing maps and collections:
+			</p>
+			<ul class='doctree'>
+				<li class='jc'>{@link org.apache.juneau.config.Config}
+				<ul>
+					<li class='jm'>{@link org.apache.juneau.config.Config#getBytes(String) getBytes(String)}
+					<li class='jm'>{@link org.apache.juneau.config.Config#getBytes(String,byte[]) getBytes(String,byte[])}
+				</ul>
+			</ul>
+		</div>
 
-	<jc>// Save your changes.</jc>
-	cf.save();
-		</p>
 	</div>
 
 	<!-- ======================================================================================================== -->
 	<a id="juneau-config.Variables"></a>
-	<h3 class='topic' onclick='toggle(this)'>6.4 - Variables</h3>
+	<h3 class='topic' onclick='toggle(this)'>6.3 - Variables</h3>
 	<div class='topic'>
 		<p>
 			Config files can contain variables that get resolved dynamically using the 
@@ -5134,10 +5038,10 @@
 			<li><code>$UE</code> - URL-encoding function.
 		</ul>
 	</div>
-	
+
 	<!-- ======================================================================================================== -->
 	<a id="juneau-config.EncodedEntries"></a>
-	<h3 class='topic' onclick='toggle(this)'>6.5 - Encoded Entries</h3>
+	<h3 class='topic' onclick='toggle(this)'>6.4 - Encoded Entries</h3>
 	<div class='topic'>
 		<p>
 			If a config file contains sensitive information such as passwords, those values can be 
@@ -5169,10 +5073,138 @@
 			<code><del>ConfigBuilder#encoder(Encoder)</del></code> method.
 		</p>
 	</div>
+
+	<!-- ======================================================================================================== -->
+	<a id="juneau-config.SectionMaps"></a>
+	<h3 class='topic' onclick='toggle(this)'>6.5 - Section Maps</h3>
+	<div class='topic'>
+	</div>
+
+	<!-- ======================================================================================================== -->
+	<a id="juneau-config.SectionBeans"></a>
+	<h3 class='topic' onclick='toggle(this)'>6.6 - Section Beans</h3>
+	<div class='topic'>
+		<p>
+			Config files can also be used to directly populate beans using the 
+			{@link org.apache.juneau.config.Config#getSectionAsBean(String,Class,boolean)}:
+		</p>
+		<p class='bcode'>
+	<jc>// Example config file</jc>
+	<cs>[MyAddress]</cs>
+	<ck>name</ck> = <cv>John Smith</cv>
+	<ck>street</ck> = <cv>123 Main Street</cv>
+	<ck>city</ck> = <cv>Anywhere</cv>
+	<ck>state</ck> = <cv>NY</cv>
+	<ck>zip</ck> = <cv>12345</cv>
+
+	<jc>// Example bean</jc>
+	<jk>public class</jk> Address {
+		public String name, street, city;
+		public StateEnum state;
+		public int zip;
+	}
+
+	<jc>// Example usage</jc>
+	Config cf = Config.<jsm>create</jsm>().name(<js>"MyConfig.cfg"</js>).build();
+	Address myAddress = cf.getSectionAsBean(<js>"MySection"</js>, Address.<jk>class</jk>);
+		</p>
+	</div>
+
+	<!-- ======================================================================================================== -->
+	<a id="juneau-config.SectionInterfaces"></a>
+	<h3 class='topic' onclick='toggle(this)'>6.7 - Section Interfaces</h3>
+	<div class='topic'>
+		<p>
+			Config file sections can also be accessed via interface proxies using 
+			{@link org.apache.juneau.config.Config#getSectionAsInterface(String,Class)}:
+		</p>
+		<p class='bcode'>
+	<jc>// Example config file</jc>
+	<cs>[MySection]</cs>
+	<ck>string</ck> = <cv>foo</cv>
+	<ck>int</ck> = <cv>123</cv>
+	<ck>enum</ck> = <cv>ONE</cv>
+	<ck>bean</ck> = <cv>{foo:'bar',baz:123}</cv>
+	<ck>int3dArray</ck> = <cv>[[[123,null],null],null]</cv>
+	<ck>bean1d3dListMap</ck> = <cv>{key:[[[[{foo:'bar',baz:123}]]]]}</cv>
+
+	<jc>// Example interface.</jc>
+	<jc>// Setters are optional.</jc>
+	<jk>public interface</jk> MyConfigInterface {
+
+		String getString();
+		<jk>void</jk> setString(String x);
+
+		<jk>int</jk> getInt();
+		<jk>void</jk> setInt(<jk>int</jk> x);
+
+		MyEnum getEnum();
+		<jk>void</jk> setEnum(MyEnum x);
+
+		MyBean getBean();
+		<jk>void</jk> setBean(MyBean x);
+
+		<jk>int</jk>[][][] getInt3dArray();
+		<jk>void</jk> setInt3dArray(<jk>int</jk>[][][] x);
+		
+		Map&lt;String,List&lt;MyBean[][][]&gt;&gt; getBean1d3dListMap();
+		<jk>void</jk> setBean1d3dListMap(Map&lt;String,List&lt;MyBean[][][]&gt;&gt; x);
+	}
+	
+	<jc>// Example usage.</jc>
+	Config cf = Config.<jsm>create</jsm>().name(<js>"MyConfig.cfg"</js>).build();
+	MyConfigInterface ci = cf.getSectionAsInterface(<js>"MySection"</js>, MyConfigInterface.<jk>class</jk>);
 	
+	<jc>// Read a value.</jc>
+	<jk>int</jk> myInt = ci.getInt();
+
+	<jc>// Write a value.</jc>
+	ci.setBean(<jk>new</jk> MyBean());
+
+	<jc>// Save your changes.</jc>
+	cf.save();
+		</p>
+	</div>
+
+	<!-- ======================================================================================================== -->
+	<a id="juneau-config.SettingValues"></a>
+	<h3 class='topic' onclick='toggle(this)'>6.8 - Setting Values</h3>
+	<div class='topic'>
+
+		<p>
+			The interface also allows a config file to be easily constructed programmatically:
+		</p>
+		<p class='bcode'>
+	<jc>// Construct the sample config file programmatically</jc>
+	Config cf = Config.<jsm>create</jsm>().name(<js>"MyConfig.cfg"</js>).build()
+		.set(<js>"key1"</js>, 1)
+		.set(<js>"key2"</js>, <jk>true</jk>)
+		.set(<js>"key3"</js>, <jk>new int</jk>[]{1,2,3})
+		.set(<js>"key4"</js>, <jk>new</jk> URI(<js>"http://foo"</js>))
+		.set(<js>"Section1/key1"</js>, 2)
+		.set(<js>"Section1/key2"</js>, <jk>false</jk>)
+		.set(<js>"Section1/key3"</js>, <jk>new int</jk>[]{4,5,6})
+		.set(<js>"Section1/key4"</js>, <jk>new</jk> URI(<js>"http://bar"</js>))
+		.save();
+		</p>
+
+		<!-- ======================================================================================================== -->
+		<a id="juneau-config.CustomEntrySerialization"></a>
+		<h4 class='topic' onclick='toggle(this)'>6.8.1 - Custom Entry Serialization</h4>
+		<div class='topic'>
+		</div>
+
+		<!-- ======================================================================================================== -->
+		<a id="juneau-config.BulkSettingValues"></a>
+		<h4 class='topic' onclick='toggle(this)'>6.8.2 - Setting Values in Bulk</h4>
+		<div class='topic'>
+		</div>
+
+	</div>
+
 	<!-- ======================================================================================================== -->
 	<a id="juneau-config.Listeners"></a>
-	<h3 class='topic' onclick='toggle(this)'>6.6 - Listeners</h3>
+	<h3 class='topic' onclick='toggle(this)'>6.9 - Listeners</h3>
 	<div class='topic'>
 		<p>
 			The following method is provided for listening to changes made on config files:
@@ -5208,256 +5240,57 @@
 	);
 		</p>
 	</div>
-	
-	
+
 	<!-- ======================================================================================================== -->
 	<a id="juneau-config.Serializing"></a>
-	<h3 class='topic' onclick='toggle(this)'>6.8 - Serializing Config Files</h3>
+	<h3 class='topic' onclick='toggle(this)'>6.10 - Serializing</h3>
 	<div class='topic'>
-		<p>
-			Instances of {@link org.apache.juneau.config.Config} are POJOs that can be serialized to and parsed from
-				all supported Juneau languages.
-		</p>
-		<p>
-			The <code>org.apache.juneau.microservice.resources.ConfigResource</code> is a predefined REST interface that
-			allows access to the config file used by a microservice.
-			<br>The <code>juneau-examples-rest</code> project is a microservice that includes this resource
-			at <code>http://localhost:10000/sample/config</code>.
-			<br>The sample microservice uses the following config file <code>juneau-examples.cfg</code>:
-		</p>
-		<p class='bcode'>
-	<cc>#================================================================================
-	# Basic configuration file for SaaS microservices
-	# Subprojects can use this as a starting point.
-	#================================================================================</cc>
-	
-	<cc>#================================================================================
-	# REST settings
-	#================================================================================</cc>
-	<cs>[REST]</cs>
-	
-	<cc># The HTTP port number to use.
-	# Default is Rest-Port setting in manifest file, or 8000.</cc>
-	<ck>port</ck> = <cv>10000</cv>
-	
-	<cc># A JSON map of servlet paths to servlet classes.
-	# Example:  
-	# 	resourceMap = {'/*':'com.foo.MyServlet'}
-	# Either resourceMap or resources must be specified.</cc>
-	<ck>resourceMap</ck> = 
-
-	<cc># A comma-delimited list of names of classes that extend from Servlet.
-	# Resource paths are pulled from @RestResource.path() annotation, or
-	# 	"/*" if annotation not specified.
-	# Example:  
-	# 	resources = com.foo.MyServlet
-	# Default is Rest-Resources in manifest file.
-	# Either resourceMap or resources must be specified.</cc>
-	<ck>resources</ck> = 
-
-	<cc># The context root of the Jetty server.
-	# Default is Rest-ContextPath in manifest file, or "/".</cc>
-	<ck>contextPath</ck> = 
+	</div>
 
-	<cc># Authentication:  NONE, BASIC.</cc>
-	<ck>authType</ck> = <cv>NONE</cv>
-	
-	<cc># The BASIC auth username.
-	# Default is Rest-LoginUser in manifest file.</cc>
-	<ck>loginUser</ck> = 
-	
-	<cc># The BASIC auth password.
-	# Default is Rest-LoginPassword in manifest file.</cc>
-	<ck>loginPassword</ck> = 
-	
-	<cc># The BASIC auth realm.
-	# Default is Rest-AuthRealm in manifest file.</cc>
-	<ck>authRealm</ck> = 
-	
-	<cc># Stylesheet to use for HTML views.
-	# The default options are:
-	#  - styles/juneau.css
-	#  - styles/devops.css
-	# Other stylesheets can be referenced relative to the servlet package or working
-	# 	directory.</cc>
-	<ck>stylesheet</ck> = <cv>styles/devops.css</cv>
-	
-	<cc># What to do when the config file is saved.
-	# Possible values:
-	# 	NOTHING - Don't do anything. 
-	#	RESTART_SERVER - Restart the Jetty server.
-	#	RESTART_SERVICE - Shutdown and exit with code '3'.</cc>
-	<ck>saveConfigAction</ck> = <cv>RESTART_SERVER</cv>
-	
-	<cc># Enable SSL support.</cc>
-	<ck>useSsl</ck> = false
-	
-	<cc>#================================================================================
-	# Bean properties on the org.eclipse.jetty.util.ssl.SslSocketFactory class
-	#--------------------------------------------------------------------------------
-	# Ignored if REST/useSsl is false.
-	#================================================================================</cc>
-	<cs>[REST-SslContextFactory]</cs>
-	<ck>keyStorePath</ck> = <cv>client_keystore.jks</cv>
-	<ck>keyStorePassword*</ck> = <cv>{HRAaRQoT}</cv>
-	<ck>excludeCipherSuites</ck> = <cv>TLS_DHE.*, TLS_EDH.*</cv>
-	<ck>excludeProtocols</ck> = <cv>SSLv3</cv>
-	<ck>allowRenegotiate</ck> = <cv>false</cv>
-	
-	<cc>#================================================================================
-	# Logger settings
-	# See FileHandler Java class for details.
-	#================================================================================</cc>
-	<cs>[Logging]</cs>
+	<!-- ======================================================================================================== -->
+	<a id="juneau-config.ConfigStores"></a>
+	<h3 class='topic' onclick='toggle(this)'>6.11 - Config Stores</h3>
+	<div class='topic'>
+		
+		<!-- ======================================================================================================== -->
+		<a id="juneau-config.ConfigMemoryStore"></a>
+		<h4 class='topic' onclick='toggle(this)'>6.11.1 - ConfigMemoryStore</h4>
+		<div class='topic'>
+		</div>
+		
+		<!-- ======================================================================================================== -->
+		<a id="juneau-config.ConfigFileStore"></a>
+		<h4 class='topic' onclick='toggle(this)'>6.11.2 - ConfigFileStoren</h4>
+		<div class='topic'>
+		</div>
 
-	<cc># The directory where to create the log file.
-	# Default is "."</cc>
-	<ck>logDir</ck> = <cv>logs</cv>
-	
-	<cc># The name of the log file to create for the main logger.
-	# The logDir and logFile make up the pattern that's passed to the FileHandler
-	# constructor.
-	# If value is not specified, then logging to a file will not be set up.</cc>
-	<ck>logFile</ck> = <cv>microservice.%g.log</cv>
-	
-	<cc># Whether to append to the existing log file or create a new one.
-	# Default is false.</cc>
-	<ck>append</ck> = 
-	
-	<cc># The SimpleDateFormat format to use for dates.
-	# Default is "yyyy.MM.dd hh:mm:ss".</cc>
-	<ck>dateFormat</ck> = 
-	
-	<cc># The log message format.
-	# The value can contain any of the following variables:
-	# 	{date} - The date, formatted per dateFormat.
-	#	{class} - The class name.
-	#	{method} - The method name.
-	#	{logger} - The logger name.
-	#	{level} - The log level name.
-	#	{msg} - The log message.
-	#	{threadid} - The thread ID.
-	#	{exception} - The localized exception message.
-	# Default is "[{date} {level}] {msg}%n".</cc>
-	<ck>format</ck> =
-	
-	<cc># The maximum log file size.
-	# Suffixes available for numbers.
-	# See ConfigFile.getInt(String,int) for details.
-	# Default is 1M.</cc>
-	<ck>limit</ck> = <cv>10M</cv>
-	
-	<cc># Max number of log files.
-	# Default is 1.</cc>
-	<ck>count</ck> = <cv>5</cv>
-	
-	<cc># Default log levels.
-	# Keys are logger names.
-	# Values are serialized Level POJOs.</cc>
-	<ck>levels</ck> = <cv>{ org.apache.juneau:'INFO' }</cv>
-	
-	<cc># Only print unique stack traces once and then refer to them by a simple 8 character hash identifier.
-	# Useful for preventing log files from filling up with duplicate stack traces.
-	# Default is false.</cc>
-	<ck>useStackTraceHashes</ck> = <cv>true</cv>
-	
-	<cc># The default level for the console logger.
-	# Default is WARNING.</cc>
-	<ck>consoleLevel</ck> = 
-	
-	<cc>#================================================================================
-	# System properties
-	#--------------------------------------------------------------------------------
-	# These are arbitrary system properties that are set during startup.
-	#================================================================================</cc>
-	<cs>[SystemProperties]</cs>
-	
-	<cc># Configure Jetty for StdErrLog Logging</cc>
-	<ck>org.eclipse.jetty.util.log.class</ck> = <cv>org.eclipse.jetty.util.log.StrErrLog</cv>
-	
-	<cc># Jetty logging level</cc>
-	<ck>org.eclipse.jetty.LEVEL</ck> = <cv>WARN</cv>		
-		</p>
-		<p>
-			The config file looks deceivingly simple.
-			However, it should be noticed that the config file is a VERY powerful feature with many capabilities including:
-		</p>
-		<p>
-			When you point your browser to this resource, you'll notice that the contents of the config file are being 
-			serialized to HTML as a POJO: 
-		</p>
-		<img class='bordered' src="doc-files/juneau-config.Serializing.1.png">
-		<p>
-			Likewise, the config file can also be serialized as any of the supported languages such as JSON: 
-		</p>
-		<img class='bordered' src="doc-files/juneau-config.Serializing.2.png">
-		<p>
-			The code for implementing this page could not be any simpler, since it simply returns the config file returned 
-			by the <code>RestServlet.getConfig()</code> method.
-		</p>
-		<p class='bcode'>
-	<ja>@RestMethod</ja>(name=<jsf>GET</jsf>, path=<js>"/"</js>, description=<js>"Show contents of config file."</js>)
-	<jk>public</jk> Config getConfigContents() <jk>throws</jk> Exception {
-		<jk>return</jk> getConfig();
-	}
-		</p>
-		<p>
-			The edit page takes you to an editor that allows you to modify the contents of the config file: 
-		</p>
-		<img class='bordered' src="doc-files/juneau-config.Serializing.3.png">
-		<p>
-			This latter page uses the {@link org.apache.juneau.config.Config#toString()} method to retrieve the
-			contents of the config file in INI format.
-		</p>
-		<p>
-			Since config files are serializable, that mean they can also be retrieved through the <code>RestClient</code> 
-			API.
-		</p>
-		<p class='bcode'>
-	<jc>// Create a new REST client with JSON support</jc>
-	RestClient c = RestClient.<jsm>create</jsm>().build();
+	</div>
 
-	<jc>// Retrieve config file through REST interface</jc>
-	Config cf = c.doGet(<js>"http://localhost:10000/sample/config"</js>).getResponse(Config.<jk>class</jk>);
-		</p>
+	<!-- ======================================================================================================== -->
+	<a id="juneau-config.ReadOnlyConfigs"></a>
+	<h3 class='topic' onclick='toggle(this)'>6.12 - Read-only Configs</h3>
+	<div class='topic'>
 	</div>
-	
+
 	<!-- ======================================================================================================== -->
-	<a id="juneau-config.Merging"></a>
-	<h3 class='topic' onclick='toggle(this)'>6.9 - Merging Config Files</h3>
+	<a id="#juneau-config.ClosingConfigs"></a>
+	<h3 class='topic' onclick='toggle(this)'>6.13 - Closing Configs</h3>
 	<div class='topic'>
-		<!--p>
-			In the previous example, an edit page was shown that allows you to edit config files through
-			a REST interface.
-			<br>Note that if only a single entry is modified in the config file, we only want to trigger
-			listeners for that change, not trigger all listeners.
-			<br>This is where the <code><del>Config#merge(ConfigFile)</del></code> method comes into play.
-			<br>This method will copy the contents of one config file over to another config file, but only
-			trigger listeners when the values are different.
-		</p>
 		<p>
-			The edit page is implemented with this method which is a simple PUT with the contents of the new config file as 
-			the body of the HTTP request:
+			In general, it's good practice to close Config if you're only creating them temporarily so that
+			their listeners get unregistered from the underlying storage APIs.
 		</p>
 		<p class='bcode'>
-	<ja>@RestMethod</ja>(name=<jsf>PUT</jsf>, path=<js>"/"</js>,
-		description=<js>"Sets contents of config file."</js>,
-		parameters={
-			<ja>@Parameter</ja>(in=<js>"body"</js>, description=<js>"New contents in INI file format."</js>)
-		}
-	)
-	<jk>public</jk> ConfigFile setConfigContents(<ja>@Body</ja> Reader contents) <jk>throws</jk> Exception {
-		
-		<jc>// Create a new in-memory config file based on the contents of the HTTP request.</jc>
-		ConfigFile cf2 = new ConfigFileBuilder.build().load(contents);
-		
-		<jc>// Merge the in-memory config file into the existing config file and save it.
-		// Then return the modified config file to be parsed as a POJO.</jc>
-		<jk>return</jk> getConfig().merge(cf2).save();
-	}
-		</p-->
+			<jc>// Create a transient config.</jc>
+			Config c = Config.<jsm>create</jsm>().name(<js>"MyConfig.cfg"</js>).build();
+			
+			<jc>// Do stuff with it.</jc>
+			
+			<jc>// Then close the config to unregister the listeners.</jc>
+			c.close();
+		</p>
 	</div>
-	
+
 </div>
 
 <!-- =========================================================================================================== -->

-- 
To stop receiving notification emails like this one, please contact
jamesbognar@apache.org.

Mime
View raw message