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 1df74a4 Config API refactoring.
1df74a4 is described below
commit 1df74a4602b80083a08c8533322e92a038f5acf6
Author: JamesBognar <[email protected]>
AuthorDate: Wed Feb 28 17:22:43 2018 -0500
Config API refactoring.
---
.../main/java/org/apache/juneau/config/Config.java | 35 +-
.../apache/juneau/config/encode/ConfigEncoder.java | 2 +-
.../juneau/config/encode/ConfigXorEncoder.java | 2 +-
.../config/{store => internal}/ConfigEntry.java | 2 +-
.../config/{store => internal}/ConfigMap.java | 7 +-
.../juneau/config/store/ConfigMemoryStore.java | 3 +-
.../apache/juneau/config/store/ConfigStore.java | 1 +
.../apache/juneau/config/ConfigBuilderTest.java | 4 +-
.../juneau/config/ConfigMapListenerTest.java | 29 +-
.../org/apache/juneau/config/ConfigMapTest.java | 15 +-
.../java/org/apache/juneau/config/ConfigTest.java | 40 +-
.../java/org/apache/juneau/svl/VarResolver.java | 1 -
.../org/apache/juneau/svl/VarResolverBuilder.java | 3 +-
.../juneau/svl/vars/CoalesceAndRecurseVar.java | 49 --
.../org/apache/juneau/svl/vars/CoalesceVar.java | 14 -
juneau-doc/src/main/javadoc/overview.html | 666 +++++++++++++++++++--
.../juneau/microservice/RestMicroservice.java | 2 +-
.../microservice/resources/ConfigResource.java | 2 +-
.../org/apache/juneau/rest/RestContextBuilder.java | 6 +-
.../juneau/rest/annotation/ResourceSwagger.java | 6 -
20 files changed, 710 insertions(+), 179 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 0fbdfd4..d56a3cf 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
@@ -25,6 +25,7 @@ import org.apache.juneau.*;
import org.apache.juneau.config.encode.*;
import org.apache.juneau.config.encode.ConfigEncoder;
import org.apache.juneau.config.event.*;
+import org.apache.juneau.config.internal.*;
import org.apache.juneau.config.store.*;
import org.apache.juneau.config.vars.*;
import org.apache.juneau.http.*;
@@ -35,7 +36,12 @@ import org.apache.juneau.serializer.*;
import org.apache.juneau.svl.*;
/**
- * TODO
+ * Main configuration API class.
+ *
+ * <h5 class='section'>See Also:</h5>
+ * <ul class='doctree'>
+ * <li class='link'><a class='doclink'
href='../../../../overview-summary.html#juneau-config'>Overview >
juneau-config</a>
+ * </ul>
*/
public final class Config extends Context implements ConfigEventListener,
Writable {
@@ -290,6 +296,19 @@ public final class Config extends Context implements
ConfigEventListener, Writab
return new ConfigBuilder();
}
+ /**
+ * Same as {@link #create()} but initializes the builder with the
specified config name.
+ *
+ * <p>
+ * This is equivalent to simply calling <code><jk>new</jk>
ConfigBuilder().name(name)</code>.
+ *
+ * @param name The configuration name.
+ * @return A new {@link ConfigBuilder} object.
+ */
+ public static ConfigBuilder create(String name) {
+ return new ConfigBuilder().name(name);
+ }
+
@Override /* Context */
public ConfigBuilder builder() {
return new ConfigBuilder(getPropertyStore());
@@ -1435,15 +1454,15 @@ public final class Config extends Context implements
ConfigEventListener, Writab
}
/**
- * Saves this config to the store.
+ * Commit the changes in this config to the store.
*
* @return This object (for method chaining).
* @throws IOException
* @throws UnsupportedOperationException If configuration is read only.
*/
- public Config save() throws IOException {
+ public Config commit() throws IOException {
checkWrite();
- configMap.save();
+ configMap.commit();
return this;
}
@@ -1506,9 +1525,9 @@ public final class Config extends Context implements
ConfigEventListener, Writab
* @throws InterruptedException
* @throws UnsupportedOperationException If configuration is read only.
*/
- public Config write(Reader contents, boolean synchronous) throws
IOException, InterruptedException {
+ public Config load(Reader contents, boolean synchronous) throws
IOException, InterruptedException {
checkWrite();
- configMap.write(IOUtils.read(contents), synchronous);
+ configMap.load(IOUtils.read(contents), synchronous);
return this;
}
@@ -1522,9 +1541,9 @@ public final class Config extends Context implements
ConfigEventListener, Writab
* @throws InterruptedException
* @throws UnsupportedOperationException If configuration is read only.
*/
- public Config write(String contents, boolean synchronous) throws
IOException, InterruptedException {
+ public Config load(String contents, boolean synchronous) throws
IOException, InterruptedException {
checkWrite();
- configMap.write(contents, synchronous);
+ configMap.load(contents, synchronous);
return this;
}
diff --git
a/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/encode/ConfigEncoder.java
b/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/encode/ConfigEncoder.java
index 4ddf74d..4dacb98 100644
---
a/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/encode/ConfigEncoder.java
+++
b/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/encode/ConfigEncoder.java
@@ -19,7 +19,7 @@ import org.apache.juneau.config.*;
*
* <h5 class='section'>See Also:</h5>
* <ul class='doctree'>
- * <li class='link'><a class='doclink'
href='../../../../overview-summary.html#juneau-config.EncodedEntries'>Overview
> juneau-config > Encoded Entries</a>
+ * <li class='link'><a class='doclink'
href='../../../../../overview-summary.html#juneau-config.EncodedEntries'>Overview
> juneau-config > Encoded Entries</a>
* </ul>
*/
public interface ConfigEncoder {
diff --git
a/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/encode/ConfigXorEncoder.java
b/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/encode/ConfigXorEncoder.java
index 3a32ea6..dd97a29 100644
---
a/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/encode/ConfigXorEncoder.java
+++
b/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/encode/ConfigXorEncoder.java
@@ -24,7 +24,7 @@ import static org.apache.juneau.internal.IOUtils.*;
*
* <h5 class='section'>See Also:</h5>
* <ul class='doctree'>
- * <li class='link'><a class='doclink'
href='../../../../overview-summary.html#juneau-config.EncodedEntries'>Overview
> juneau-config > Encoded Entries</a>
+ * <li class='link'><a class='doclink'
href='../../../../../overview-summary.html#juneau-config.EncodedEntries'>Overview
> juneau-config > Encoded Entries</a>
* </ul>
*/
public final class ConfigXorEncoder implements ConfigEncoder {
diff --git
a/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/store/ConfigEntry.java
b/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/internal/ConfigEntry.java
similarity index 99%
rename from
juneau-core/juneau-config/src/main/java/org/apache/juneau/config/store/ConfigEntry.java
rename to
juneau-core/juneau-config/src/main/java/org/apache/juneau/config/internal/ConfigEntry.java
index 4513f96..bee83cb 100644
---
a/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/store/ConfigEntry.java
+++
b/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/internal/ConfigEntry.java
@@ -10,7 +10,7 @@
// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
express or implied. See the License for the *
// * specific language governing permissions and limitations under the
License. *
//
***************************************************************************************************************************
-package org.apache.juneau.config.store;
+package org.apache.juneau.config.internal;
import static org.apache.juneau.internal.CollectionUtils.*;
import static org.apache.juneau.internal.StringUtils.*;
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/internal/ConfigMap.java
similarity index 99%
rename from
juneau-core/juneau-config/src/main/java/org/apache/juneau/config/store/ConfigMap.java
rename to
juneau-core/juneau-config/src/main/java/org/apache/juneau/config/internal/ConfigMap.java
index 89f0747..dd7c69c 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/internal/ConfigMap.java
@@ -10,7 +10,7 @@
// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
express or implied. See the License for the *
// * specific language governing permissions and limitations under the
License. *
//
***************************************************************************************************************************
-package org.apache.juneau.config.store;
+package org.apache.juneau.config.internal;
import static org.apache.juneau.internal.StringUtils.*;
import static org.apache.juneau.config.event.ConfigEventType.*;
@@ -22,6 +22,7 @@ import java.util.concurrent.locks.*;
import org.apache.juneau.*;
import org.apache.juneau.config.event.*;
+import org.apache.juneau.config.store.*;
import org.apache.juneau.internal.*;
/**
@@ -404,7 +405,7 @@ public class ConfigMap implements ConfigStoreListener {
* @throws IOException
* @throws InterruptedException
*/
- public ConfigMap write(String contents, boolean synchronous) throws
IOException, InterruptedException {
+ public ConfigMap load(String contents, boolean synchronous) throws
IOException, InterruptedException {
if (synchronous) {
final CountDownLatch latch = new CountDownLatch(1);
@@ -445,7 +446,7 @@ public class ConfigMap implements ConfigStoreListener {
* @return This object (for method chaining).
* @throws IOException
*/
- public ConfigMap save() throws IOException {
+ public ConfigMap commit() throws IOException {
writeLock();
try {
String newContents = asString();
diff --git
a/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/store/ConfigMemoryStore.java
b/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/store/ConfigMemoryStore.java
index 5bbbd2d..8c522cd 100644
---
a/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/store/ConfigMemoryStore.java
+++
b/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/store/ConfigMemoryStore.java
@@ -81,7 +81,6 @@ public class ConfigMemoryStore extends ConfigStore {
if (expectedContents != null && ! isEquals(currentContents,
expectedContents))
return currentContents;
- cache.put(name, newContents);
update(name, newContents);
return null;
@@ -91,7 +90,7 @@ public class ConfigMemoryStore extends ConfigStore {
@Override /* ConfigStore */
public synchronized ConfigMemoryStore update(String name, String
newContents) {
cache.put(name, newContents);
- super.update(name, newContents);
+ super.update(name, newContents); // Trigger any listeners.
return this;
}
diff --git
a/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/store/ConfigStore.java
b/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/store/ConfigStore.java
index f805670..7012c19 100644
---
a/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/store/ConfigStore.java
+++
b/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/store/ConfigStore.java
@@ -17,6 +17,7 @@ import java.util.*;
import java.util.concurrent.*;
import org.apache.juneau.*;
+import org.apache.juneau.config.internal.*;
/**
* Represents a storage location for configuration files.
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 1e2aee8..75737d4 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
@@ -50,11 +50,11 @@ public class ConfigBuilderTest {
f = new File(tempDir, "TestGet.cfg");
assertFalse(f.exists());
- cf.save();
+ cf.commit();
assertObjectEquals("{'':{},Test:{A:'a'}}", cf.asMap());
String NL = System.getProperty("line.separator");
- cf = cf.write("[Test]"+NL+"A = b"+NL, true);
+ cf = cf.load("[Test]"+NL+"A = b"+NL, true);
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 52b0e50..9d7e602 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
@@ -20,6 +20,7 @@ import java.util.concurrent.*;
import org.apache.juneau.*;
import org.apache.juneau.config.event.*;
+import org.apache.juneau.config.internal.*;
import org.apache.juneau.config.store.*;
import org.junit.*;
@@ -47,7 +48,7 @@ public class ConfigMapListenerTest {
ConfigMap cm = s.getMap("Foo.cfg");
cm.register(l);
cm.setEntry("", "foo", "baz", null, null, null);
- cm.save();
+ cm.commit();
wait(latch);
assertNull(l.error);
cm.unregister(l);
@@ -74,7 +75,7 @@ public class ConfigMapListenerTest {
ConfigMap cm = s.getMap("Foo.cfg");
cm.register(l);
cm.setEntry("S1", "foo", "baz", null, null, null);
- cm.save();
+ cm.commit();
wait(latch);
assertNull(l.error);
cm.unregister(l);
@@ -104,7 +105,7 @@ public class ConfigMapListenerTest {
cm.register(l);
cm.setEntry("", "k", "vb", null, null, null);
cm.setEntry("S1", "k1", "v1b", null, null, null);
- cm.save();
+ cm.commit();
wait(latch);
assertNull(l.error);
cm.unregister(l);
@@ -130,7 +131,7 @@ public class ConfigMapListenerTest {
cm.register(l);
cm.setEntry("", "k", "kb", "^*", "C", Arrays.asList("#k"));
cm.setEntry("S1", "k1", "k1b", "^*", "C1",
Arrays.asList("#k1"));
- cm.save();
+ cm.commit();
wait(latch);
assertNull(l.error);
cm.unregister(l);
@@ -162,7 +163,7 @@ public class ConfigMapListenerTest {
cm.register(l);
cm.setEntry("", "k", "kb", "^*", "Cb", Arrays.asList("#kb"));
cm.setEntry("S1", "k1", "k1b", "^*", "Cb1",
Arrays.asList("#k1b"));
- cm.save();
+ cm.commit();
wait(latch);
assertNull(l.error);
cm.unregister(l);
@@ -195,7 +196,7 @@ public class ConfigMapListenerTest {
cm.register(l);
cm.removeEntry("", "k");
cm.removeEntry("S1", "k1");
- cm.save();
+ cm.commit();
wait(latch);
assertNull(l.error);
cm.unregister(l);
@@ -227,7 +228,7 @@ public class ConfigMapListenerTest {
cm.register(l);
cm.removeEntry("", "k");
cm.removeEntry("S1", "k1");
- cm.save();
+ cm.commit();
wait(latch);
assertNull(l.error);
cm.unregister(l);
@@ -260,7 +261,7 @@ public class ConfigMapListenerTest {
cm.setSection("S2", null);
cm.setSection("S3", Collections.<String>emptyList());
cm.setEntry("S3", "k3", "v3", null, null, null);
- cm.save();
+ cm.commit();
wait(latch);
assertNull(l.error);
cm.unregister(l);
@@ -295,7 +296,7 @@ public class ConfigMapListenerTest {
cm.setSection("S2", null);
cm.setSection("S3", Collections.<String>emptyList());
cm.setEntry("S3", "k3", "v3", null, null, null);
- cm.save();
+ cm.commit();
wait(latch);
assertNull(l.error);
cm.unregister(l);
@@ -339,7 +340,7 @@ public class ConfigMapListenerTest {
cm.removeSection("S1");
cm.removeSection("S2");
cm.removeSection("S3");
- cm.save();
+ cm.commit();
wait(latch);
assertNull(l.error);
cm.unregister(l);
@@ -417,7 +418,7 @@ public class ConfigMapListenerTest {
"[S1]",
"k1 = v1b"
);
- cm.save();
+ cm.commit();
wait(latch);
assertNull(l.error);
cm.unregister(l);
@@ -455,7 +456,7 @@ public class ConfigMapListenerTest {
"[S1]",
"k1 = v1b"
);
- cm.save();
+ cm.commit();
wait(latch);
assertNull(l.error);
cm.unregister(l);
@@ -497,7 +498,7 @@ public class ConfigMapListenerTest {
ConfigMap cm = s.getMap("Foo.cfg");
cm.register(l);
cm.setEntry("S1", "k1", "v1c", null, null, null);
- cm.save();
+ cm.commit();
wait(latch);
assertNull(l.error);
cm.unregister(l);
@@ -543,7 +544,7 @@ public class ConfigMapListenerTest {
cm.register(l);
cm.setEntry("S1", "k1", "v1c", null, null, null);
try {
- cm.save();
+ cm.commit();
fail("Exception expected.");
} catch (ConfigException e) {
assertEquals("Unable to store contents of
config to store.", e.getMessage());
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 f68b778..9fc752d 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
@@ -20,6 +20,7 @@ import static org.apache.juneau.TestUtils.*;
import static org.apache.juneau.internal.StringUtils.*;
import org.apache.juneau.*;
+import org.apache.juneau.config.internal.*;
import org.apache.juneau.config.store.*;
import org.junit.*;
@@ -503,7 +504,7 @@ public class ConfigMapTest {
assertTextEquals("[S1]|k1 = v1b|k2 = v2a|k3 = v3b|", cm);
- cm.save();
+ cm.commit();
assertTextEquals("[S1]|k1 = v1b|k2 = v2a|k3 = v3b|",
s.read("Foo.cfg"));
// Round trip.
@@ -536,7 +537,7 @@ public class ConfigMapTest {
assertTextEquals("|#S1||[S1]||#k1||k1 = v1b||#k2||k2 = v2a|k3 =
v3b||#k4||k4 = v4b|", cm);
- cm.save();
+ cm.commit();
assertTextEquals("|#S1||[S1]||#k1||k1 = v1b||#k2||k2 = v2a|k3 =
v3b||#k4||k4 = v4b|", s.read("Foo.cfg"));
// Round trip.
@@ -556,7 +557,7 @@ public class ConfigMapTest {
assertEquals("v1\nv2\nv3", cm.getEntry("", "k").getValue());
assertEquals("v1\nv2\nv3", cm.getEntry("S1", "k1").getValue());
- cm.save();
+ cm.commit();
assertTextEquals("k = v1| v2| v3|[S1]|k1 = v1|
v2| v3|", cm);
// Round trip.
@@ -576,7 +577,7 @@ public class ConfigMapTest {
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();
+ cm.commit();
assertTextEquals("k = v1 | v2 | v3|[S1]|k1 = v1
| v2 | v3|", cm);
// Round trip.
@@ -668,12 +669,12 @@ public class ConfigMapTest {
for (char c : validChars.toCharArray()) {
String test = ""+c;
cm.setSection(test, Arrays.asList("test"));
- cm.save();
+ cm.commit();
assertEquals("test", cm.getPreLines(test).get(0));
test = "foo"+c+"bar";
cm.setSection(test, Arrays.asList("test"));
- cm.save();
+ cm.commit();
assertEquals("test", cm.getPreLines(test).get(0));
}
}
@@ -953,7 +954,7 @@ public class ConfigMapTest {
cm.setEntry("S1", "k1", null, null, "", null);
assertTextEquals("[S1]|k1 = v1|", cm);
- cm.save();
+ cm.commit();
assertTextEquals("[S1]|k1 = v1|", cm);
cm.setEntry("S1", "k1", null, null, null, 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 82082ec..64e6db7 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
@@ -85,7 +85,7 @@ public class ConfigTest {
assertEquals("6", c.get("S/b2"));
assertEquals("7", c.get("T/c1"));
- c.save();
+ c.commit();
assertEquals("2", c.get("a1"));
assertEquals("3", c.get("a2"));
@@ -127,7 +127,7 @@ public class ConfigTest {
assertEquals("6", c.get("S/b2"));
assertEquals("7", c.get("T/c1"));
- c.save();
+ c.commit();
assertEquals("2", c.get("a1"));
assertEquals("3", c.get("a2"));
@@ -187,7 +187,7 @@ public class ConfigTest {
c.set("T/c1", b, UonSerializer.DEFAULT, ENCODED, "comment",
Arrays.asList("#c1","#c2"));
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());
- c.save();
+ c.commit();
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());
c = cb.build();
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());
@@ -214,7 +214,7 @@ public class ConfigTest {
c.remove("T/c1");
assertTextEquals("[S]|", c.toString());
- c.save();
+ c.commit();
assertTextEquals("[S]|", c.toString());
c = cb.build();
assertTextEquals("[S]|", c.toString());
@@ -1216,7 +1216,7 @@ public class ConfigTest {
cf.set("section1/key3", new int[]{4,5,6});
cf.set("section1/key4", new URL("http://bar"));
- cf.save();
+ cf.commit();
assertEquals(1, cf.getInt("key1"));
assertEquals(true, cf.getBoolean("key2"));
@@ -1239,7 +1239,7 @@ public class ConfigTest {
);
assertEquals(TimeUnit.MINUTES, cf.getObject("key1",
TimeUnit.class));
- cf.save();
+ cf.commit();
assertEquals(TimeUnit.MINUTES, cf.getObject("key1",
TimeUnit.class));
}
@@ -1257,14 +1257,14 @@ public class ConfigTest {
assertEquals("mypassword", cf.getString("s1/foo"));
- cf.save();
+ cf.commit();
String expected = "[s1]||foo* = {AwwJVhwUQFZEMg==}|";
assertTextEquals(expected, cf);
assertEquals("mypassword", cf.getString("s1/foo"));
- cf.write(new StringReader("[s1]\nfoo* = mypassword2\n"), true);
+ cf.load(new StringReader("[s1]\nfoo* = mypassword2\n"), true);
assertEquals("mypassword2", cf.getString("s1/foo"));
@@ -1287,7 +1287,7 @@ public class ConfigTest {
);
cf.encodeEntries();
- cf.save();
+ cf.commit();
String expected = "[s1]||foo* = {AwwJVhwUQFZEMg==}|";
assertTextEquals(expected,
ConfigMemoryStore.DEFAULT.read("Test.cfg"));
}
@@ -1448,7 +1448,7 @@ public class ConfigTest {
cf.set("B/b1", 3);
cf.set("B/b3", 3);
assertObjectEquals("[]", changes);
- cf.save();
+ cf.commit();
assertObjectEquals("['a1=3','a3=3','B/b1=3','B/b3=3']",
changes);
// Rollback.
@@ -1459,7 +1459,7 @@ public class ConfigTest {
cf.set("B/b3", 3);
assertObjectEquals("[]", changes);
cf.rollback();
- cf.save();
+ cf.commit();
assertObjectEquals("[]", changes);
// Overwrite
@@ -1470,21 +1470,21 @@ public class ConfigTest {
cf.set("B/b2", "2");
cf.set("C/c1", "2");
cf.set("C/c2", "2");
- cf.save();
+ cf.commit();
assertObjectEquals("['a1=2','a2=2','B/b1=2','B/b2=2','C/c1=2','C/c2=2']",
changes);
// Encoded
changes.clear();
cf.set("a4", "4", null, ConfigMod.ENCODED, null, null);
cf.set("B/b4", "4", null, ConfigMod.ENCODED, null, null);
- cf.save();
+ cf.commit();
assertObjectEquals("['a4={Wg==}','B/b4={Wg==}']", changes);
// Encoded overwrite
changes.clear();
cf.set("a4", "5");
cf.set("B/b4", "5");
- cf.save();
+ cf.commit();
assertObjectEquals("['a4={Ww==}','B/b4={Ww==}']", changes);
// Remove entries
@@ -1494,32 +1494,32 @@ public class ConfigTest {
cf.remove("B/b4");
cf.remove("B/bx");
cf.remove("X/bx");
- cf.save();
+ cf.commit();
assertObjectEquals("['REMOVE_ENTRY(a4)','REMOVE_ENTRY(B/b4)']",
changes);
// Add section
// Shouldn't trigger listener.
changes.clear();
cf.setSection("D", Arrays.asList("#comment"));
- cf.save();
+ cf.commit();
assertObjectEquals("[]", changes);
// Add section with contents
changes.clear();
cf.setSection("E", null, new AMap<String,Object>().append("e1",
"1").append("e2", "2"));
- cf.save();
+ cf.commit();
assertObjectEquals("['E/e1=1','E/e2=2']", changes);
// Remove section
changes.clear();
cf.removeSection("E");
- cf.save();
+ cf.commit();
assertObjectEquals("['REMOVE_ENTRY(E/e1)','REMOVE_ENTRY(E/e2)']", changes);
// Remove non-existent section
changes.clear();
cf.removeSection("E");
- cf.save();
+ cf.commit();
assertObjectEquals("[]", changes);
}
@@ -1705,7 +1705,7 @@ public class ConfigTest {
cf.set("A/a", "a,#b,=c");
assertTextEquals("a = a,\\u0023b,=c|[A]|a = a,\\u0023b,=c|",
cf);
- cf.save();
+ cf.commit();
assertTextEquals("a = a,\\u0023b,=c|[A]|a = a,\\u0023b,=c|",
cf);
assertEquals("a,#b,=c", cf.getString("a"));
diff --git
a/juneau-core/juneau-svl/src/main/java/org/apache/juneau/svl/VarResolver.java
b/juneau-core/juneau-svl/src/main/java/org/apache/juneau/svl/VarResolver.java
index dfabaa6..6bc5d27 100644
---
a/juneau-core/juneau-svl/src/main/java/org/apache/juneau/svl/VarResolver.java
+++
b/juneau-core/juneau-svl/src/main/java/org/apache/juneau/svl/VarResolver.java
@@ -68,7 +68,6 @@ public class VarResolver {
* <li><code>$IF{booleanValue,thenValue[,elseValue]}</code> -
{@link IfVar}
*
<li><code>$SW{test,matchPattern,thenValue[,matchPattern,thenValue][,elseValue]}</code>
- {@link SwitchVar}
* <li><code>$CO{arg1[,arg2...]}</code> - {@link CoalesceVar}
- * <li><code>$CR{arg1[,arg2...]}</code> - {@link
CoalesceAndRecurseVar}
* </ul>
*
* @see SystemPropertiesVar
diff --git
a/juneau-core/juneau-svl/src/main/java/org/apache/juneau/svl/VarResolverBuilder.java
b/juneau-core/juneau-svl/src/main/java/org/apache/juneau/svl/VarResolverBuilder.java
index 3f2ccf5..617c5ab 100644
---
a/juneau-core/juneau-svl/src/main/java/org/apache/juneau/svl/VarResolverBuilder.java
+++
b/juneau-core/juneau-svl/src/main/java/org/apache/juneau/svl/VarResolverBuilder.java
@@ -68,13 +68,12 @@ public class VarResolverBuilder {
* <li>{@link SwitchVar}
* <li>{@link IfVar}
* <li>{@link CoalesceVar}
- * <li>{@link CoalesceAndRecurseVar}
* </ul>
*
* @return This object (for method chaining).
*/
public VarResolverBuilder defaultVars() {
- return vars(SystemPropertiesVar.class, EnvVariablesVar.class,
SwitchVar.class, IfVar.class, CoalesceAndRecurseVar.class, CoalesceVar.class);
+ return vars(SystemPropertiesVar.class, EnvVariablesVar.class,
SwitchVar.class, IfVar.class, CoalesceVar.class);
}
/**
diff --git
a/juneau-core/juneau-svl/src/main/java/org/apache/juneau/svl/vars/CoalesceAndRecurseVar.java
b/juneau-core/juneau-svl/src/main/java/org/apache/juneau/svl/vars/CoalesceAndRecurseVar.java
deleted file mode 100644
index 98bc245..0000000
---
a/juneau-core/juneau-svl/src/main/java/org/apache/juneau/svl/vars/CoalesceAndRecurseVar.java
+++ /dev/null
@@ -1,49 +0,0 @@
-//
***************************************************************************************************************************
-// * Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file *
-// * distributed with this work for additional information regarding copyright
ownership. The ASF licenses this file *
-// * to you under the Apache License, Version 2.0 (the "License"); you may not
use this file except in compliance *
-// * with the License. You may obtain a copy of the License at
*
-// *
*
-// * http://www.apache.org/licenses/LICENSE-2.0
*
-// *
*
-// * Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an *
-// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
express or implied. See the License for the *
-// * specific language governing permissions and limitations under the
License. *
-//
***************************************************************************************************************************
-package org.apache.juneau.svl.vars;
-
-import org.apache.juneau.svl.*;
-
-/**
- * A basic variable resolver that returns the first non-null value.
- *
- * <p>
- * The format for this var is <js>"$CR{arg1[,arg2...]}"</js>.
- *
- * <p>
- * The difference between {@link CoalesceVar} and {@link
CoalesceAndRecurseVar} is that the first will not resolve
- * inner variables nor recursively resolve variables, and the second will.
- * <br>Use {@link CoalesceVar} when resolving user-input.
- *
- * <h5 class='section'>See Also:</h5>
- * <ul>
- * <li class='link'><a class="doclink"
href="../../../../../overview-summary.html#juneau-svl.SvlVariables">Overview
> juneau-svl > SVL Variables</a>
- * </ul>
- */
-public class CoalesceAndRecurseVar extends MultipartResolvingVar {
-
- /** The name of this variable. */
- public static final String NAME = "CR";
-
- /**
- * Constructor.
- */
- public CoalesceAndRecurseVar() {
- super(NAME);
- }
-
- @Override
- public String resolve(VarResolverSession session, String arg) throws
Exception {
- return arg;
- }
-}
diff --git
a/juneau-core/juneau-svl/src/main/java/org/apache/juneau/svl/vars/CoalesceVar.java
b/juneau-core/juneau-svl/src/main/java/org/apache/juneau/svl/vars/CoalesceVar.java
index 4e7af41..fa02ad9 100644
---
a/juneau-core/juneau-svl/src/main/java/org/apache/juneau/svl/vars/CoalesceVar.java
+++
b/juneau-core/juneau-svl/src/main/java/org/apache/juneau/svl/vars/CoalesceVar.java
@@ -20,10 +20,6 @@ import org.apache.juneau.svl.*;
* <p>
* The format for this var is <js>"$CO{arg1[,arg2...]}"</js>.
*
- * <p>
- * The difference between {@link CoalesceVar} and {@link
CoalesceAndRecurseVar} is that the first will not resolve
- * inner variables nor recursively resolve variables, and the second will.
- * <br>Use {@link CoalesceVar} when resolving user-input.
*
* <h5 class='section'>See Also:</h5>
* <ul>
@@ -46,14 +42,4 @@ public class CoalesceVar extends MultipartResolvingVar {
public String resolve(VarResolverSession session, String arg) throws
Exception {
return arg;
}
-
- @Override /* Var */
- protected boolean allowNested() {
- return false;
- }
-
- @Override /* Var */
- protected boolean allowRecurse() {
- return false;
- }
}
diff --git a/juneau-doc/src/main/javadoc/overview.html
b/juneau-doc/src/main/javadoc/overview.html
index 482e95d..348fbbb 100644
--- a/juneau-doc/src/main/javadoc/overview.html
+++ b/juneau-doc/src/main/javadoc/overview.html
@@ -157,12 +157,16 @@
<li><p><a class='doclink'
href='#juneau-config.BinaryData'>Binary Data</a></p>
</ol>
<li><p><a class='doclink'
href='#juneau-config.Variables'>Variables</a></p>
+ <ol>
+ <li><p><a class='doclink'
href='#juneau-config.LogicVariables'>Logic Variables</a></p>
+ </ol>
<li><p><a class='doclink'
href='#juneau-config.EncodedEntries'>Encoded Entries</a></p>
<li><p><a class='doclink'
href='#juneau-config.SectionMaps'>Section Maps</a></p>
<li><p><a class='doclink'
href='#juneau-config.SectionBeans'>Section Beans</a></p>
<li><p><a class='doclink'
href='#juneau-config.SectionInterfaces'>Section Interfaces</a></p>
<li><p><a class='doclink'
href='#juneau-config.SettingValues'>Setting Values</a></p>
<ol>
+ <li><p><a class='doclink'
href='#juneau-config.FileSystemChanges'>File System Changes</a></p>
<li><p><a class='doclink'
href='#juneau-config.CustomEntrySerialization'>Custom Entry
Serialization</a></p>
<li><p><a class='doclink'
href='#juneau-config.BulkSettingValues'>Setting Values in Bulk</a></p>
</ol>
@@ -172,6 +176,7 @@
<ol>
<li><p><a class='doclink'
href='#juneau-config.ConfigMemoryStore'>ConfigMemoryStore</a></p>
<li><p><a class='doclink'
href='#juneau-config.ConfigFileStore'>ConfigFileStore</a></p>
+ <li><p><a class='doclink'
href='#juneau-config.CustomConfigStores"'>Custom ConfigStores</a></p>
</ol>
<li><p><a class='doclink'
href='#juneau-config.ReadOnlyConfigs'>Read-only Configs</a></p>
<li><p><a class='doclink'
href='#juneau-config.ClosingConfigs'>Closing Configs</a></p>
@@ -4381,10 +4386,14 @@
<ul>
<li><code>$S{key}</code>,<code>$S{key,default}</code> -
System properties.
<li><code>$E{key}</code>,<code>$E{key,default}</code> -
Environment variables.
+ </ul>
+ <p>
+ The following logic variables are also provided:
+ </p>
+ <ul>
<li><code>$IF{booleanValue,thenValue[,elseValue]}</code> - If-else patterns.
-
<li><code>$SW{test,matchPattern,thenValue[,matchPattern,thenValue][,elseValue]}</code>
- Switch patterns.
+
<li><code>$SW{test,matchPattern:thenValue[,matchPattern:thenValue...][,elseValue]}</code>
- Switch patterns.
<li><code>$CO{arg1[,arg2...]}</code> - Coalesce
variable.
- <li><code>$CR{arg1[,arg2...]}</code> -
Coalesce-and-recurse variable.
</ul>
<h5 class='figure'>Example:</h5>
<p class='bcode'>
@@ -4478,16 +4487,12 @@
<td class='code'>$CO{arg1[,arg2...]}</td>
</tr>
<tr class='dark'>
- <td>{@link
org.apache.juneau.svl.vars.CoalesceAndRecurseVar}</td>
- <td class='code'>$CR{arg1[,arg2...]}</td>
- </tr>
- <tr class='dark'>
<td>{@link
org.apache.juneau.svl.vars.IfVar}</td>
- <td
class='code'>$IF{booleanArg,thenValue[,elseValue]}</td>
+ <td class='code'>$IF{booleanArg ?
thenValue}<br>$IF{booleanArg ? thenValue : elseValue}</td>
</tr>
<tr class='dark dd'>
<td>{@link
org.apache.juneau.svl.vars.SwitchVar}</td>
- <td
class='code'>$SW{stringArg(,pattern,thenValue)+[,elseValue]}</td>
+ <td class='code'>$SW{stringArg ? pattern:
value, pattern: value, ...}</td>
</tr>
<tr class='light dd'>
<td rowspan="1"
style='text-align:center;font-weight:bold;padding:20px;'
class='code'>juneau-config</td>
@@ -4698,12 +4703,21 @@
<ck>key4</ck> = <cv>http://bar</cv>
</p>
<p>
- This code shows how the file can be accessed:
+ Config files are access through the {@link
org.apache.juneau.config.Config} class which
+ are created through the {@link
org.apache.juneau.config.ConfigBuilder} class.
+ <br><code>create()</code> methods are provided on the
<code>Config</code> class for creating builders:
</p>
<p class='bcode'>
- <jc>// Load our config file</jc>
+ <jc>// Create a Config object</jc>
Config c =
Config.<jsm>create</jsm>().name(<js>"MyConfig.cfg"</js>).build();
+ <jc>// Shortcut</jc>
+ Config c = Config.<jsm>create</jsm>(<js>"MyConfig.cfg"</js>).build();
+ </p>
+ <p>
+ Once instantiated, reading values from the config are
simple:
+ </p>
+ <p class='bcode'>
<jc>// Read values from section #1</jc>
<jk>int</jk> key1 = c.getInt(<js>"Section1/key1"</js>);
<jk>boolean</jk> key2 = c.getBoolean(<js>"Section1/key2"</js>);
@@ -4724,22 +4738,25 @@
<li>Binary data
</ul>
<li>
- A listener API that allows you to, for example,
reinitialize your REST resource if the config file
- changes, or listen for changes to particular
sections or values.
+ Transactional modifications with
commit/rollback capabilities.
+ <li>
+ A listener API.
<li>
- Filesystem watcher integration allows configs
to reflect changes on the file system in real-time.
+ Filesystem watcher integration allowing changes
on the file system to be reflected in real-time.
<li>
Config files can be modified through the Config
class (e.g. add/remove/modify sections and keys, add/remove comments and
whitespace, etc...).
<br>When using these APIs, you <b>DO NOT</b>
lose formatting in your existing configuration file.
All existing whitespace and comments are
preserved for you!
<li>
- Support for encoding of values for added
security.
+ Support for value encoding for added security.
<li>
- Config sections can be used to directly
populate beans.
+ Support for SVL variables.
<li>
- Config sections can be accessed and manipulated
through Java interface proxies.
+ Directly populate beans from config sections.
<li>
- An extensible storage API allows you to write
your own config storage location for files such as databases or the cloud.
+ Accessing config sections through Java
interface proxies.
+ <li>
+ An extensible storage API allows you to write
your own config storage (e.g. storage in databases or the cloud).
</ul>
<!--
========================================================================================================
-->
@@ -5240,15 +5257,12 @@
</p>
<p>
By default, <code>Configs</code> use the {@link
org.apache.juneau.svl.VarResolver#DEFAULT} variable resolver
- which provides support for the following variables and
constructs (in addition to the <code>$C</code> variable):
+ which provides support for the following variables and
constructs:
</p>
<ul class='spaced-list'>
+ <li><code>$C{key}</code>,<code>$C{key,default}</code> -
{@link org.apache.juneau.config.vars.ConfigVar}
<li><code>$S{key}</code>,<code>$S{key,default}</code> -
{@link org.apache.juneau.svl.vars.SystemPropertiesVar}
<li><code>$E{key}</code>,<code>$E{key,default}</code> -
{@link org.apache.juneau.svl.vars.EnvVariablesVar}
-
<li><code>$IF{booleanValue,thenValue[,elseValue]}</code> - {@link
org.apache.juneau.svl.vars.IfVar}
-
<li><code>$SW{test,matchPattern,thenValue[,matchPattern,thenValue][,elseValue]}</code>
- {@link org.apache.juneau.svl.vars.SwitchVar}
- <li><code>$CO{arg1[,arg2...]}</code> - {@link
org.apache.juneau.svl.vars.CoalesceVar}
- <li><code>$CR{arg1[,arg2...]}</code> - {@link
org.apache.juneau.svl.vars.CoalesceAndRecurseVar}
</ul>
<p>
The variable resolver can be overridden via the
following:
@@ -5264,6 +5278,72 @@
<ul class='doctree'>
<li class='jf'>{@link
org.apache.juneau.config.Config#resolving(VarResolverSession)}
</ul>
+
+ <!--
========================================================================================================
-->
+ <a id="juneau-config.LogicVariables"></a>
+ <h4 class='topic' onclick='toggle(this)'>6.3.1 - Logic
Variables</h4>
+ <div class='topic'>
+ <p>
+ The default variable resolver also provides the
following logic variables for performing simple logical operations:
+ </p>
+ <ul class='spaced-list'>
+
<li><code>$IF{booleanValue,thenValue[,elseValue]}</code> - {@link
org.apache.juneau.svl.vars.IfVar}
+
<li><code>$SW{test,matchPattern:thenValue[,matchPattern:thenValue...]}</code> -
{@link org.apache.juneau.svl.vars.SwitchVar}
+ <li><code>$CO{arg1[,arg2...]}</code> - {@link
org.apache.juneau.svl.vars.CoalesceVar}
+ </ul>
+ <p>
+ The <code>$IF</code> variable can be used for
simple if/else logic:
+ </p>
+ <p class='bcode'>
+ <cc># Value set to 'foo' if myBooleanProperty is true</cc>
+ <ck>key1</ck> =
+ <cv>$IF{
+ $S{myBooleanProperty},
+ foo
+ }</cv>
+
+ <cc># Value set to 'foo' if myBooleanProperty is true, 'bar' if
false.</cc>
+ <ck>key2</ck> =
+ <cv>$IF{
+ $S{myBooleanProperty},
+ foo,
+ bar
+ }</cv>
+
+ <cc># Value set to key1 value if myBooleanProperty is true, key2 value
if false.</cc>
+ <ck>key3</ck> =
+ <cv>$IF{
+ $S{myBooleanProperty},
+ $C{key1},
+ $C{key2}
+ }</cv>
+ </p>
+ <p>
+ The <code>$SW</code> variable can be used for
switch blocks based on pattern matching:
+ </p>
+ <p class='bcode'>
+ <cc># Shell command depends on the OS</cc>
+ <ck>shellCommand</ck> =
+ <cv>$SW{
+ $S{os.name},
+ *win*: bat,
+ linux: bash,
+ *: sh
+ }</cv>
+ </p>
+ <p>
+ The <code>$CO</code> variable can be used for
coalescing of values (finding the first non-null/empty match):
+ </p>
+ <p class='bcode'>
+ <cc># Debug flag can be enabled by system property or environment
variable.</cc>
+ <ck>debug</ck> =
+ <cv>$CO{
+ $S{debug},
+ $E{DEBUG},
+ false
+ }</cv>
+ </p>
+ </div>
</div>
<!--
========================================================================================================
-->
@@ -5304,7 +5384,7 @@
<br>The curly brackets around the value identify
whether the value has been encoded or not.
</p>
<p>
- Unencoded values are encoded when the file is saved
using the {@link org.apache.juneau.config.Config#save()} method.
+ Unencoded values are encoded when the file is saved
using the {@link org.apache.juneau.config.Config#commit()} method.
<br>They can also be encoded by calling {@link
org.apache.juneau.config.Config#encodeEntries()}.
</p>
</div>
@@ -5424,8 +5504,8 @@
<jc>// Write a value.</jc>
ci.setBean(<jk>new</jk> MyBean());
- <jc>// Save your changes.</jc>
- c.save();
+ <jc>// Commit your changes to the store.</jc>
+ c.commit();
</p>
</div>
@@ -5461,52 +5541,544 @@
.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();
+ .commit();
+ </p>
+ <p>
+ The method {@link
org.apache.juneau.config.Config#set(String,Object,Serializer,ConfigMod[],String,List)}
can be used
+ for adding comments and pre-lines to entries, and
specifying encoded values.
+ </p>
+ <p class='bcode'>
+ <jc>// Set an encoded value with some comments.</jc>
+ c.set(<js>"key1"</js>, 1, <jk>null</jk>, ConfigMod.<jsf>ENCODED</jsf>,
<js>"Same-line comment"</js>,
+ Arrays.asList(
+ <js>"# Comment 1"</js>, <js>""</js>, <js>"# Comment
2"</js>
+ )
+ )
+ </p>
+ <p class='bcode'>
+ <cc># Comment 1</cc>
+
+ <cc># Comment 2</cc>
+ <ck>key1</ck> = <cv>1</cv> <cc># Same-line comment</cc>
+ </p>
+ <p>
+ The last 4 arguments in {@link
org.apache.juneau.config.Config#set(String,Object,Serializer,ConfigMod[],String,List)}
+ are optional in that if you pass <jk>null</jk>, the
current value will not be overwritten.
+ <br>To unset the same-line comment, you should pass in
a blank string.
+ <br>To remove pre-lines, you should pass in an empty
list.
+ </p>
+ <p>
+ Sections can be added with optional pre-lines using the
<code>setSection</code> methods:
+ </p>
+ <p class='bcode'>
+ <jc>// Set an encoded value with some comments.</jc>
+ c.setSection(<js>"NewSection"</js>,
+ Arrays.asList(
+ <js>"# Section comment 1"</js>, <js>""</js>, <js>"#
Section comment 2"</js>
+ )
+ );
+ </p>
+ <p class='bcode'>
+ <cc># Section comment 1</cc>
+
+ <cc># Section comment 2</cc>
+ <cs>[NewSection]</cs>
+ </p>
+ <p>
+ Changes made to the configuration are transactional in
nature.
+ <br>They are kept in memory until you call the {@link
org.apache.juneau.config.Config#commit()} method.
+ <br>Until then, you still see the modified values when
you call any of the getters, but the modified values
+ exist only in memory.
+ </p>
+ <p>
+ Changes can be rolled back using the {@link
org.apache.juneau.config.Config#rollback()} method.
</p>
<!--
========================================================================================================
-->
+ <a id="juneau-config.FileSystemChanges"></a>
+ <h4 class='topic' onclick='toggle(this)'>6.8.1 - File System
Changes</h4>
+ <div class='topic'>
+ <p>
+ In general, changes made to configuration files
will be updated immediately in the <code>Config</code>
+ object (although this is configurable and
described in detail later).
+ </p>
+ <p>
+ The <code>Config</code> object maintains an
in-memory record of all changes that have been applied to it
+ through getters and setters.
+ <br>When the underlying file changes, the new
contents are loaded and the in-memory changes are then
+ applied to the new configuration.
+ <br>This provides the benefits of real-time
updates of configurations while not losing any changes made in the JVM.
+ </p>
+ <p>
+ If the <code>commit()</code> method is called
on the <code>Config</code> objects after the file system
+ contents have been modified, we will then
reload the configuration from the file system, apply the
+ changes, and then try to save to the file
system again (up to 10 times).
+ </p>
+ </div>
+
+ <!--
========================================================================================================
-->
<a id="juneau-config.CustomEntrySerialization"></a>
- <h4 class='topic' onclick='toggle(this)'>6.8.1 - Custom Entry
Serialization</h4>
+ <h4 class='topic' onclick='toggle(this)'>6.8.2 - Custom Entry
Serialization</h4>
<div class='topic'>
+ <p>
+ Setter methods that take in a
<code>Serializer</code> can be used to provide custom serialization of entries
+ instead of using the predefined serializer.
+ </p>
+ <p class='bcode'>
+ <jc>// Set an XML value instead of a.</jc>
+ c.set(<js>"key1"</js>, myAddress,
XmlSerializer.<jsf>DEFAULT_SQ_READABLE</jsf>);
+ </p>
+ <p class='bcode'>
+ <ck>key1</ck> =
+ <cv><address>
+ <street>123 Main Street</street>
+ <city>Anywhere</city>
+ <state>NY</state>
+ <zip>12345</zip>
+ </address></cv>
+ </p>
+ <p>
+ The value can then be retrieved using the
equivalent parser:
+ </p>
+ <p class='bcode'>
+ Address a = c.getObject(<js>"key1"</js>, XmlParser.<jsf>DEFAULT</jsf>,
Address.<jk>class</jk>);
+ </p>
</div>
<!--
========================================================================================================
-->
<a id="juneau-config.BulkSettingValues"></a>
- <h4 class='topic' onclick='toggle(this)'>6.8.2 - Setting Values
in Bulk</h4>
+ <h4 class='topic' onclick='toggle(this)'>6.8.3 - Setting Values
in Bulk</h4>
<div class='topic'>
+ <p>
+ The following methods can be used to bulk-load
configuration values:
+ </p>
+ <ul class='doctree'>
+ <li class='jc'>{@link
org.apache.juneau.config.Config}
+ <ul>
+ <li class='jm'>{@link
org.apache.juneau.config.Config#setSection(String,List,Map)
setSection(String,List,Map)}
+ <li class='jm'>{@link
org.apache.juneau.config.Config#load(Map) load(Map)}
+ </ul>
+ </ul>
+ <p>
+ Changes can then be committed using the {@link
org.apache.juneau.config.Config#commit()} method.
+ </p>
</div>
-
</div>
<!--
========================================================================================================
-->
<a id="juneau-config.Listeners"></a>
<h3 class='topic' onclick='toggle(this)'>6.9 - Listeners</h3>
<div class='topic'>
+ <p>
+ Configuration change events can be listened for using
the following methods:
+ </p>
+ <ul class='doctree'>
+ <li class='jc'>{@link org.apache.juneau.config.Config}
+ <ul>
+ <li class='jm'>{@link
org.apache.juneau.config.Config#addListener(ConfigEventListener)
addListener(ConfigEventListener)}
+ <li class='jm'>{@link
org.apache.juneau.config.Config#removeListener(ConfigEventListener)
removeListener(ConfigEventListener)}
+ </ul>
+ </ul>
+ <p>
+ The event listener interface consists of the following
method:
+ </p>
+ <ul class='doctree'>
+ <li class='jic'>{@link
org.apache.juneau.config.event.ConfigEventListener}
+ <ul>
+ <li class='jm'>{@link
org.apache.juneau.config.event.ConfigEventListener#onConfigChange(List)
onConfigChange(List<ConfigEvent>)}
+ </ul>
+ </ul>
+ <ul class='doctree'>
+ <li class='jc'>{@link
org.apache.juneau.config.event.ConfigEvent}
+ <ul>
+ <li class='jm'>{@link
org.apache.juneau.config.event.ConfigEvent#getType() getType()}
+ <li class='jm'>{@link
org.apache.juneau.config.event.ConfigEvent#getSection() getSection()}
+ <li class='jm'>{@link
org.apache.juneau.config.event.ConfigEvent#getKey() getKey()}
+ <li class='jm'>{@link
org.apache.juneau.config.event.ConfigEvent#getValue() getValue()}
+ <li class='jm'>{@link
org.apache.juneau.config.event.ConfigEvent#getModifiers() getModifiers()}
+ <li class='jm'>{@link
org.apache.juneau.config.event.ConfigEvent#getComment() getComment()}
+ <li class='jm'>{@link
org.apache.juneau.config.event.ConfigEvent#getPreLines() getPreLines}
+ </ul>
+ </ul>
+ <p>
+ This method is triggered:
+ </p>
+ <ul>
+ <li>After {@link
org.apache.juneau.config.Config#commit()} is called.
+ <li>When the file changes on the file system.
+ </ul>
+ <p>
+ In both cases, the listener is triggered after the
changes have been committed.
+ </p>
+ <p class='bcode'>
+ <jk>final</jk> Config c =
Config.<jsm>create</jsm>(<js>"MyConfig.cfg"</js>).build();
+
+ <jc>// Add a listener for changes to MySection/key1</jc>
+ c.addListener(
+ <jk>new</jk> ConfigEventListener() {
+ <ja>@Override</ja>
+ <jk>public void</jk>
onConfigChange(List<ConfigEvent> events) {
+ <jk>for</jk> (ConfigEvent event : events) {
+ <jk>if</jk> (event.getType() ==
<jsf>SET_ENTRY</jsf>) {
+ <jk>if</jk>
(event.getSection().equals(<js>"MySection"</js>) &&
event.getKey().equals(<js>"key1"</js>)) {
+
+ <jc>// Get the new
value from the event.</jc>
+ String newVal =
event.getValue();
+
+ <jc>// Or get the new
value from the config (since the change has already been committed).</jc>
+ newVal =
c.getString(<js>"MySection/key1"</js>);
+ }
+ }
+ }
+ }
+ }
+ )
+ </p>
</div>
<!--
========================================================================================================
-->
<a id="juneau-config.Serializing"></a>
<h3 class='topic' onclick='toggle(this)'>6.10 - Serializing</h3>
<div class='topic'>
+ <p>
+ The following methods are used for serializing
<code>Config</code> objects back into INI files:
+ </p>
+ <ul class='doctree'>
+ <li class='jc'>{@link org.apache.juneau.config.Config}
+ <ul>
+ <li class='jm'>{@link
org.apache.juneau.config.Config#writeTo(Writer)}
+ <li class='jm'>{@link
org.apache.juneau.config.Config#toString()}
+ </ul>
+ </ul>
+ <p>
+ Both methods are thread safe.
+ </p>
</div>
<!--
========================================================================================================
-->
<a id="juneau-config.ConfigStores"></a>
<h3 class='topic' onclick='toggle(this)'>6.11 - Config Stores</h3>
<div class='topic'>
+ <p>
+ Configuration files are stored in entities called
Stores.
+ </p>
+ <p>
+ The API for implementing a store is simple:
+ </p>
+ <ul class='doctree'>
+ <li class='jac'>{@link
org.apache.juneau.config.store.ConfigStore}
+ <ul>
+ <li class='jm'>{@link
org.apache.juneau.config.store.ConfigStore#read(String) read(String)} - Read a
config file.
+ <li class='jm'>{@link
org.apache.juneau.config.store.ConfigStore#write(String,String,String)
write(String,String,String)} - Write a config file.
+ <li class='jm'>{@link
org.apache.juneau.config.store.ConfigStore#update(String,String)
update(String,String)} - Update the contents of a config file.
+ </ul>
+ </ul>
+ <p>
+ Read is self-explanatory:
+ <br><code>String read(String name)</code>
+ <br>Simple return the string contents of the specified
configuration name:
+ </p>
+ <p>
+ Write is slightly trickier:
+ <br><code>String write(String name, String oldContents,
String newContents)</code>
+ <br>With this method, you pass in the old and new
contents.
+ <br>There are two possible outcomes to this call:
+ </p>
+ <ul>
+ <li>The old contents match the current stored contents,
the new contents will get stored, and the method returns <jk>null</jk>.
+ <li>The old contents DO NOT match the current stored
contents (i.e. it was modified in some way), the new contents are NOT
+ stored, and the method returns the current stored
contents.
+ </ul>
+ <p>
+ The update method is called whenever the stored file
gets modified:
+ <br><code><jk>void</jk> update(String name, String
newContents)</code>
+ </p>
+ <p>
+ The <code>ConfigStore</code> class also has the
following listener methods:
+ </p>
+ <ul class='doctree'>
+ <li class='jac'>{@link
org.apache.juneau.config.store.ConfigStore}
+ <ul>
+ <li class='jm'>{@link
org.apache.juneau.config.store.ConfigStore#register(String,ConfigStoreListener)
register(String,ConfigStoreListener)} - Register a listener on the specified
config name.
+ <li class='jm'>{@link
org.apache.juneau.config.store.ConfigStore#unregister(String,ConfigStoreListener)
unregister(String,ConfigStoreListener)} - Unregister a listener on the
specified config name.
+ </ul>
+ </ul>
+ <p>
+ Note that this is a different listener than {@link
org.apache.juneau.config.event.ConfigEventListener}.
+ <br>In this case, we're just listening for changed
files:
+ </p>
+ <ul class='doctree'>
+ <li class='jic'>{@link
org.apache.juneau.config.store.ConfigStoreListener}
+ <ul>
+ <li class='jm'>{@link
org.apache.juneau.config.store.ConfigStoreListener#onChange(String)} - Called
when file changes. New contents passed in.
+ </ul>
+ </ul>
+ <p>
+ This listener is used by the <code>Config</code> class
to listen for changes on the file system so that it can be
+ updated in real-time.
+ </p>
+ <p>
+ Two configuration stores are provided by default:
+ </p>
+ <ul>
+ <li class='jc'>{@link
org.apache.juneau.config.store.ConfigFileStore} - File-system storage.
+ <li class='jc'>{@link
org.apache.juneau.config.store.ConfigMemoryStore} - In-memory storage.
+ </ul>
+ <p>
+ The store is defined on the <code>Config</code> object
via the following:
+ </p>
+ <ul>
+ <li class='jf'>{@link
org.apache.juneau.config.Config#CONFIG_store}
+ <li class='jm'>{@link
org.apache.juneau.config.ConfigBuilder#store(ConfigStore)}
+ </ul>
+
+ <h5 class='figure'>Example:</h5>
+ <p class='bcode'>
+ <jc>// Create a config with in-memory storage.</jc>
+ Config c =
Config.<jsm>create</jsm>(<js>"MyConfig.cfg"</js>).store(ConfigMemoryStore.<jsf>DEFAULT</jsf>).build();
+ <p>
+ The default store used is {@link
org.apache.juneau.config.store.ConfigFileStore#DEFAULT} which defines
+ the execution directory as the file system directory to
store and retrieve files.
+ </p>
+
<!--
========================================================================================================
-->
<a id="juneau-config.ConfigMemoryStore"></a>
<h4 class='topic' onclick='toggle(this)'>6.11.1 -
ConfigMemoryStore</h4>
<div class='topic'>
+ <p>
+ The {@link
org.apache.juneau.config.store.ConfigMemoryStore} class is simply an in-memory
storage
+ location for configuration files.
+ <br>There is no hard persistence and is used
primarily for testing purposes.
+ </p>
+ <p>
+ However, the implementation provides a good
idea on how stores work, especially the write method:
+ </p>
+ <p>
+ <jk>public class</jk> ConfigMemoryStore <jk>extends</jk> ConfigStore {
+
+ <jc>// Some methods ommitted.</jc>
+
+ <jk>private final</jk> ConcurrentHashMap<String,String>
<jf>cache</jf> = <jk>new</jk> ConcurrentHashMap<>();
+
+ <ja>@Override</ja> <jc>/* ConfigStore */</jc>
+ <jk>public synchronized</jk> String read(String name) {
+ <jk>return</jk>
<jsm>emptyIfNull</jsm>(<jf>cache</jf>.get(name));
+ }
+
+ <ja>@Override</ja> <jc>/* ConfigStore */</jc>
+ <jk>public synchronized</jk> String write(String name, String
expectedContents, String newContents) {
+
+ <jc>// This is a no-op.</jc>
+ <jk>if</jk> (isEquals(expectedContents, newContents))
+ <jk>return null</jk>;
+
+ String currentContents = read(name);
+
+ <jk>if</jk> (expectedContents != <jk>null</jk>
&& ! <jsm>isEquals</jsm>(currentContents, expectedContents))
+ <jk>return</jk> currentContents;
+
+ update(name, newContents);
+
+ <jc>// Success!</jc>
+ <jk>return null</jk>;
+ }
+
+
+ <ja>@Override</ja> <jc>/* ConfigStore */</jc>
+ <jk>public synchronized</jk> ConfigMemoryStore update(String
name, String newContents) {
+ <jf>cache</jf>.put(name, newContents);
+ <jk>super</jk>.update(name, newContents); <jc>//
Trigger any listeners.</jc>
+ <jk>return this</jk>;
+ }
+ }
+ </p>
+
</div>
<!--
========================================================================================================
-->
<a id="juneau-config.ConfigFileStore"></a>
<h4 class='topic' onclick='toggle(this)'>6.11.2 -
ConfigFileStore</h4>
<div class='topic'>
+ <p>
+ The {@link
org.apache.juneau.config.store.ConfigFileStore} is the typical store used for
configuration files.
+ It provides the following configurable settings:
+ </p>
+ <ul class='doctree'>
+ <li class='jic'>{@link
org.apache.juneau.config.store.ConfigFileStore}
+ <ul>
+ <li class='jm'>{@link
org.apache.juneau.config.store.ConfigFileStore#FILESTORE_charset}
+ <li class='jm'>{@link
org.apache.juneau.config.store.ConfigFileStore#FILESTORE_directory}
+ <li class='jm'>{@link
org.apache.juneau.config.store.ConfigFileStore#FILESTORE_updateOnWrite}
+ <li class='jm'>{@link
org.apache.juneau.config.store.ConfigFileStore#FILESTORE_useWatcher}
+ <li class='jm'>{@link
org.apache.juneau.config.store.ConfigFileStore#FILESTORE_watcherSensitivity}
+ </ul>
+ </ul>
+
+ <h5 class='figure'>Example:</h5>
+ <p class='bcode'>
+ <jc>// Create a config store with a watcher thread and high
sensitivity.</jc>
+ ConfigFileStore fs =
ConfigFileStore.<jsm>create</jsm>().directory(<js>"configs"</js>).useWatcher().watcherSensitivity(<jsf>HIGH</jsf>).build();
+
+ <jc>// Create a config using the store defined above.</jc>
+ Config c =
Config.<jsm>create</jsm>(<js>"MyConfig.cfg"</js>).store(fs).build();
+ </p>
+
</div>
+ <!--
========================================================================================================
-->
+ <a id="juneau-config.CustomConfigStores"></a>
+ <h4 class='topic' onclick='toggle(this)'>6.11.3 - Custom
ConfigStores</h4>
+ <div class='topic'>
+ <p>
+ The <code>ConfigStore</code> API has been
written to allow easy development of custom configuration storage classes.
+ </p>
+ <p>
+ The example belows shows a starting point for
an implementation based on a relational database.
+ <br>Completing it is left as an exercise:
+ </p>
+ <h5 class='figure'>Store Class</h5>
+ <p class='bcode'>
+ <jk>public class</jk> ConfigSqlStore <jk>extends</jk> ConfigStore {
+
+ <jc>// Configurable properties</jc>
+ <jk>static final</jk> String
+ <jsf>CONFIGSQLSTORE_jdbcUrl</jsf> =
<js>"ConfigSqlStore.jdbcUrl.s"</js>,
+ <jsf>CONFIGSQLSTORE_tableName</jsf> =
<js>"ConfigSqlStore.tableName.s"</js>,
+ <jsf>CONFIGSQLSTORE_nameColumn</jsf> =
<js>"ConfigSqlStore.nameColumn.s"</js>;
+ <jsf>CONFIGSQLSTORE_valueColumn</jsf> =
<js>"ConfigSqlStore.valueColumn.s"</js>;
+
+ <jc>// Instance fields</jc>
+ <jk>private final</jk> String <jf>jdbcUrl</jf>;
+ <jk>private final</jk> String <jf>tableName</jf>,
<jf>nameColumn</jf>, <jf>valueColumn</jf>;
+ <jk>private final</jk> Thread <jf>watcherThread</jf>;
+ <jk>private final</jk> ConcurrentHashMap<String,String>
<jf>cache</jf> = <jk>new</jk> ConcurrentHashMap<>();
+
+
+ <jc>// Constructor called from builder.</jc>
+ <jk>protected</jk> ConfigSqlStore(PropertyStore ps) {
+ <jk>super</jk>(ps);
+
+ <jk>this</jk>.<jf>jdbcUrl</jf> =
getStringProperty(<jsf>CONFIGSQLSTORE_jdbcUrl</jsf>,
<js>"jdbc:derby:mydb"</js>);
+ <jk>this</jk>.<jf>tableName</jf> =
getStringProperty(<jsf>CONFIGSQLSTORE_tableName</jsf>);
+ <jk>this</jk>.<jf>nameColumn</jf> =
getStringProperty(<jsf>CONFIGSQLSTORE_nameColumn</jsf>);
+ <jk>this</jk>.<jf>valueColumn</jf> =
getStringProperty(<jsf>CONFIGSQLSTORE_valueColumn</jsf>);
+
+ <jk>this</jk>.watcherThread = <jk>new</jk> Thread() {
+ <ja>@Override</ja> <jc>/* Thread */</jc>
+ <jk>public void</jk> run() {
+
ConfigSqlStore.<jk>this</jk>.checkForUpdates();
+ }
+ };
+ watcherThread.start();
+ }
+
+ <jk>private synchronized void</jk> checkForUpdates() {
+
+ <jc>// Loop through all our entries and find the latest
values.</jc>
+ <jk>for</jk> (Map.Entry<String,String> e :
cache.entrySet()) {
+ String name = e.getKey();
+ String cacheContents = e.getValue();
+ String newContents = getDatabaseValue(name);
+
+ <jc>// Change detected!</jc>
+ <jk>if</jk> (!
cacheContents.equals(newContents))
+ update(name, newContents);
+ }
+
+ }
+
+ <jc>// Reads the value from the database.</jc>
+ <jk>protected</jk> String getDatabaseValue(String name) {
+ <jc>// Implement me!</jc>
+ }
+
+ <ja>@Override</ja> <jc>/* ConfigStore */</jc>
+ <jk>public synchronized</jk> String read(String name) {
+ String contents = <jf>cache</jf>.get(name);
+ <jk>if</jk> (contents == <jk>null</jk>) {
+ contents = readDatabaseValue();
+ update(name, contents);
+ }
+ <jk>return</jk> contents;
+ }
+
+ <ja>@Override</ja> <jc>/* ConfigStore */</jc>
+ <jk>public synchronized</jk> String write(String name, String
expectedContents, String newContents) {
+
+ <jc>// This is a no-op.</jc>
+ <jk>if</jk> (isEquals(expectedContents, newContents))
+ <jk>return null</jk>;
+
+ String currentContents = read(name);
+
+ <jk>if</jk> (expectedContents != <jk>null</jk>
&& ! <jsm>isEquals</jsm>(currentContents, expectedContents))
+ <jk>return</jk> currentContents;
+
+ update(name, newContents);
+
+ <jc>// Success!</jc>
+ <jk>return null</jk>;
+ }
+
+
+ <ja>@Override</ja> <jc>/* ConfigStore */</jc>
+ <jk>public synchronized</jk> ConfigSqlStore update(String name,
String newContents) {
+ <jf>cache</jf>.put(name, newContents);
+ <jk>super</jk>.update(name, newContents); <jc>//
Trigger any listeners.</jc>
+ <jk>return this</jk>;
+ }
+
+ <ja>@Override</ja> <jc>/* Closeable */</jc>
+ <jk>public synchronized void</jk> close() {
+ <jk>if</jk> (watcher != <jk>null</jk>)
+ watcher.interrupt();
+ }
+ }
+ </p>
+ <p>
+ The purpose of the builder class is to simply
set values in the {@link org.apache.juneau.PropertyStore}
+ that's passed to the <code>ConfigStore</code>:
+ </p>
+ <h5 class='figure'>Builder Class</h5>
+ <p class='bcode'>
+ <jk>public class</jk> ConfigSqlStoreBuilder <jk>extends</jk>
ConfigStoreBuilder {
+
+ <jk>public</jk> ConfigSqlStoreBuilder() {
+ <jk>super</jk>();
+ }
+
+ <jk>publicv ConfigSqlStoreBuilder(PropertyStore ps) {
+ <jk>super</jk>(ps);
+ }
+
+ <jk>public</jk> ConfigSqlStoreBuilder jdbcUrl(String value) {
+ <jk>super</jk>.set(<jsf>CONFIGSQLSTORE_jdbcUrl</jsf>,
value);
+ <jk>return this</jk>;
+ }
+
+ <jk>public</jk> ConfigSqlStoreBuilder tableName(String value) {
+ <jk>super</jk>.set(<jsf>CONFIGSQLSTORE_tableName</jsf>,
value);
+ <jk>return this</jk>;
+ }
+
+ <jk>public</jk> ConfigSqlStoreBuilder nameColumn(String value) {
+
<jk>super</jk>.set(<jsf>CONFIGSQLSTORE_nameColumn</jsf>, value);
+ <jk>return this</jk>;
+ }
+
+ <jk>public</jk> ConfigSqlStoreBuilder valueColumn(String value)
{
+
<jk>super</jk>.set(<jsf>CONFIGSQLSTORE_valueColumn</jsf>, value);
+ <jk>return this</jk>;
+ }
+
+ <ja>@Override</ja> <jc>/* ContextBuilder */</jc>
+ <jk>public</jk> ConfigFileStore build() {
+ <jk>return new</jk> ConfigFileStore(getPropertyStore());
+ }
+ }
+ </div>
+
</div>
<!--
========================================================================================================
-->
@@ -5523,7 +6095,7 @@
<h6 class='figure'>Example:</h6>
<p class='bcode'>
<jc>// Create a read-only config</jc>
- Config c =
Config.<jsm>create</jsm>().name(<js>"MyConfig.cfg"</js>).readOnly().build();
+ Config c =
Config.<jsm>create</jsm>(<js>"MyConfig.cfg"</js>).readOnly().build();
</p>
<p>
This causes all methods that make modifications to
throw {@link java.lang.UnsupportedOperationException}.
@@ -5531,7 +6103,7 @@
</div>
<!--
========================================================================================================
-->
- <a id="#juneau-config.ClosingConfigs"></a>
+ <a id="juneau-config.ClosingConfigs"></a>
<h3 class='topic' onclick='toggle(this)'>6.13 - Closing Configs</h3>
<div class='topic'>
<p>
@@ -5540,7 +6112,7 @@
</p>
<p class='bcode'>
<jc>// Create a transient config.</jc>
- Config c =
Config.<jsm>create</jsm>().name(<js>"MyConfig.cfg"</js>).build();
+ Config c = Config.<jsm>create</jsm>(<js>"MyConfig.cfg"</js>).build();
<jc>// Do stuff with it.</jc>
@@ -8164,12 +8736,6 @@
<td
style='text-align:center;font-weight:bold'>yes</td>
</tr>
<tr class='dark'>
- <td>{@link
org.apache.juneau.svl.vars.CoalesceAndRecurseVar}</td>
- <td class='code'>$CR{arg1[,arg2...]}</td>
- <td
style='text-align:center;font-weight:bold'>yes</td>
- <td
style='text-align:center;font-weight:bold'>yes</td>
- </tr>
- <tr class='dark'>
<td>{@link
org.apache.juneau.svl.vars.IfVar}</td>
<td
class='code'>$IF{booleanArg,thenValue[,elseValue]}</td>
<td
style='text-align:center;font-weight:bold'>yes</td>
@@ -15820,6 +16386,7 @@
<h5 class='toc'>What's new in each release</h5>
<ul class='toc'>
+ <li><p><a class='doclink' href='#7.1.1'>7.1.1 (TBD)</a></p>
<li><p><a class='doclink' href='#7.1.0'>7.1.0 (TBD)</a></p>
<li><p><a class='doclink' href='#7.0.1'>7.0.1 (Dec 24,
2017)</a></p>
<li><p><a class='doclink' href='#7.0.0'>7.0.0 (Oct 25,
2017)</a></p>
@@ -15893,10 +16460,28 @@
</ul>
<!--
===========================================================================================================
-->
+ <a id="7.1.1"></a>
+ <h3 class='topic' onclick='toggle(this)'>7.1.1 (TBD)</h3>
+ <div class='topic'>
+ <p>
+ TBD
+ </p>
+
+ <h5 class='topic'>juneau-config</h5>
+ <ul class='spaced-list'>
+ <li>
+ <code>Config.save()</code> method renamed to
{@link org.apache.juneau.config.Config#commit()}.
+ <li>
+ <code>Config.write(Reader,boolean)</code>
method renamed to {@link org.apache.juneau.config.Config#load(Reader,boolean)}.
+ </ul>
+ </div>
+
+ <!--
===========================================================================================================
-->
<a id="7.1.0"></a>
<h3 class='topic' onclick='toggle(this)'>7.1.0 (TBD)</h3>
<div class='topic'>
<p>
+ Version 7.1.0 is a major update with major
implementation refactoring across all aspects of the product.
</p>
<h5 class='topic'>juneau-marshall</h5>
@@ -15978,7 +16563,6 @@
New SVL variables:
<ul>
<li>{@link
org.apache.juneau.svl.vars.CoalesceVar}
- <li>{@link
org.apache.juneau.svl.vars.CoalesceAndRecurseVar}
</ul>
<li>
Improvements to the HTTP-Part APIs.
@@ -18446,8 +19030,8 @@
<li><code><del>ConfigFile.containsNonEmptyValue(String)</del></code>
<li><code><del>ConfigFile.isEncoded(String)</del></code>
<li><code><del>ConfigFile.addListener(ConfigFileListener)</del></code> - Listen
for modification events on the config file.
-
<li><code><del>ConfigFile.merge(ConfigFile)} - Merge the contents of another
config file into this config file.
-
<li><code><del>ConfigFile.getResolving()},
<del><code>ConfigFile.getResolving(StringVarResolver)</code></del> - Return an
instance of the config file that resolves string variables.
+
<li><code><del>ConfigFile.merge(ConfigFile)</del></code> - Merge the contents
of another config file into this config file.
+
<li><code><del>ConfigFile.getResolving()</del></code>,
<del><code>ConfigFile.getResolving(StringVarResolver)</code></del> - Return an
instance of the config file that resolves string variables.
Much more
efficient than the previous design since the same underlying config file object
is shared.
<li><code><del>ConfigFile.toWritable()</del></code> - Wraps the config file in
a {@link org.apache.juneau.Writable} interface so that it can be serialized by
the REST interface as a plain-text INI file instead of as a serialized POJO.
<li><code><del>ConfigFile.getInt(String)</del></code> - Now supports
<js>"M"</js> and <js>"K"</js> to identify millions and thousands.
diff --git
a/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/RestMicroservice.java
b/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/RestMicroservice.java
index 3f704f4..75ce57f 100755
---
a/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/RestMicroservice.java
+++
b/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/RestMicroservice.java
@@ -403,7 +403,7 @@ public class RestMicroservice extends Microservice {
}
/**
- * Called when {@link Config#save()} is called on the config file.
+ * Called when {@link Config#commit()} is called on the config file.
*
* <p>
* The default behavior is configured by the following value in the
config file:
diff --git
a/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/resources/ConfigResource.java
b/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/resources/ConfigResource.java
index 9de2e66..1027513 100755
---
a/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/resources/ConfigResource.java
+++
b/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/resources/ConfigResource.java
@@ -153,7 +153,7 @@ public class ConfigResource extends Resource {
)
)
public ObjectMap setConfigContents(@Body Reader contents) throws
Exception {
- return getServletConfig().getConfig().write(contents,
true).asMap();
+ return getServletConfig().getConfig().load(contents,
true).asMap();
}
/**
diff --git
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContextBuilder.java
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContextBuilder.java
index c06afeb..fd4dbd1 100644
---
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContextBuilder.java
+++
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContextBuilder.java
@@ -140,10 +140,7 @@ public class RestContextBuilder extends BeanContextBuilder
implements ServletCon
try {
-// ConfigBuilder cfb = Config.create();
-
htmlDocBuilder = new HtmlDocBuilder(properties);
-// this.config = cfb.build();
varResolverBuilder = new VarResolverBuilder()
.vars(
SystemPropertiesVar.class,
@@ -151,8 +148,7 @@ public class RestContextBuilder extends BeanContextBuilder
implements ServletCon
ConfigVar.class,
IfVar.class,
SwitchVar.class,
- CoalesceVar.class,
- CoalesceAndRecurseVar.class
+ CoalesceVar.class
);
VarResolver vr = varResolverBuilder.build();
diff --git
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/ResourceSwagger.java
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/ResourceSwagger.java
index b96fc32..31b5624 100644
---
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/ResourceSwagger.java
+++
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/ResourceSwagger.java
@@ -60,7 +60,6 @@ public @interface ResourceSwagger {
* Value can contain any of the following variables:
* {@link ConfigVar $C}
* {@link CoalesceVar $CO}
- * {@link CoalesceAndRecurseVar $CR}
* {@link EnvVariablesVar $E}
* {@link FileVar $F}
* {@link ServletInitParamVar $I},
@@ -117,7 +116,6 @@ public @interface ResourceSwagger {
* Value can contain any of the following variables:
* {@link ConfigVar $C}
* {@link CoalesceVar $CO}
- * {@link CoalesceAndRecurseVar $CR}
* {@link EnvVariablesVar $E}
* {@link FileVar $F}
* {@link ServletInitParamVar $I},
@@ -174,7 +172,6 @@ public @interface ResourceSwagger {
* Value can contain any of the following variables:
* {@link ConfigVar $C}
* {@link CoalesceVar $CO}
- * {@link CoalesceAndRecurseVar $CR}
* {@link EnvVariablesVar $E}
* {@link FileVar $F}
* {@link ServletInitParamVar $I},
@@ -237,7 +234,6 @@ public @interface ResourceSwagger {
* Value can contain any of the following variables:
* {@link ConfigVar $C}
* {@link CoalesceVar $CO}
- * {@link CoalesceAndRecurseVar $CR}
* {@link EnvVariablesVar $E}
* {@link FileVar $F}
* {@link ServletInitParamVar $I},
@@ -275,7 +271,6 @@ public @interface ResourceSwagger {
* Value can contain any of the following variables:
* {@link ConfigVar $C}
* {@link CoalesceVar $CO}
- * {@link CoalesceAndRecurseVar $CR}
* {@link EnvVariablesVar $E}
* {@link FileVar $F}
* {@link ServletInitParamVar $I},
@@ -313,7 +308,6 @@ public @interface ResourceSwagger {
* Value can contain any of the following variables:
* {@link ConfigVar $C}
* {@link CoalesceVar $CO}
- * {@link CoalesceAndRecurseVar $CR}
* {@link EnvVariablesVar $E}
* {@link FileVar $F}
* {@link ServletInitParamVar $I},
--
To stop receiving notification emails like this one, please contact
[email protected].