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 c34f187  Config API refactoring.
c34f187 is described below

commit c34f1870a57be83f430ea00e04110b5f43bb51b8
Author: JamesBognar <[email protected]>
AuthorDate: Fri Feb 16 14:41:24 2018 -0500

    Config API refactoring.
---
 .../org/apache/juneau/config/store/FileStore.java  | 218 ++++++++++++++-------
 .../juneau/config/store/FileStoreBuilder.java      |  42 ++++
 .../apache/juneau/config/store/MemoryStore.java    |  22 ++-
 .../java/org/apache/juneau/config/store/Store.java |   2 +-
 .../{MemoryStore.java => WatcherSensitivity.java}  |  73 ++-----
 .../apache/juneau/config/store/FileStoreTest.java  | 134 +++++++++++++
 .../juneau/config/store/MemoryStoreTest.java}      | 103 +++++-----
 7 files changed, 409 insertions(+), 185 deletions(-)

diff --git 
a/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/store/FileStore.java
 
b/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/store/FileStore.java
index d8ee346..75f50ec 100644
--- 
a/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/store/FileStore.java
+++ 
b/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/store/FileStore.java
@@ -13,6 +13,8 @@
 package org.apache.juneau.config.store;
 
 import static java.nio.file.StandardWatchEventKinds.*;
+import static java.nio.file.StandardOpenOption.*;
+import static org.apache.juneau.internal.StringUtils.*;
 
 import java.io.*;
 import java.nio.*;
@@ -107,6 +109,32 @@ public class FileStore extends Store {
        public static final String FILESTORE_useWatcher = PREFIX + 
"useWatcher.s";
        
        /**
+        * Configuration property:  Watcher sensitivity.
+        * 
+        * <h5 class='section'>Property:</h5>
+        * <ul>
+        *      <li><b>Name:</b>  <js>"FileStore.watcherSensitivity.s"</js>
+        *      <li><b>Data type:</b>  {@link WatcherSensitivity}
+        *      <li><b>Default:</b>  {@link WatcherSensitivity#MEDIUM}
+        *      <li><b>Methods:</b> 
+        *              <ul>
+        *                      <li class='jm'>{@link 
FileStoreBuilder#watcherSensitivity(WatcherSensitivity)}
+        *                      <li class='jm'>{@link 
FileStoreBuilder#watcherSensitivity(String)}
+        *              </ul>
+        * </ul>
+        * 
+        * <h5 class='section'>Description:</h5>
+        * <p>
+        * Determines how frequently the file system is polled for updates.
+        * 
+        * <h5 class='section'>Notes:</h5>
+        * <ul class='spaced-list'>
+        *      <li>This relies on internal Sun packages and may not work on 
all JVMs.
+        * </ul>
+        */
+       public static final String FILESTORE_watcherSensitivity = PREFIX + 
"watcherSensitivity.s";
+       
+       /**
         * Configuration property:  Config file extension.
         * 
         * <h5 class='section'>Property:</h5>
@@ -126,6 +154,19 @@ public class FileStore extends Store {
         */
        public static final String FILESTORE_ext = PREFIX + "ext.s";
 
+       
+       
//-------------------------------------------------------------------------------------------------------------------
+       // Predefined instances
+       
//-------------------------------------------------------------------------------------------------------------------
+
+       /** Default file store, all default values.*/
+       public static final FileStore DEFAULT = FileStore.create().build();
+
+
+       
//-------------------------------------------------------------------------------------------------------------------
+       // Instance
+       
//-------------------------------------------------------------------------------------------------------------------
+       
        /**
         * Create a new builder for this object.
         * 
@@ -155,52 +196,137 @@ public class FileStore extends Store {
                super(ps);
                try {
                        dir = new File(getStringProperty(FILESTORE_directory, 
".")).getCanonicalFile();
+                       dir.mkdirs();
                        ext = getStringProperty(FILESTORE_ext, "cfg");
                        charset = getProperty(FILESTORE_charset, Charset.class, 
Charset.defaultCharset());
-                       watcher = getBooleanProperty(FILESTORE_useWatcher, 
false) ? new WatcherThread(dir) : null;
+                       WatcherSensitivity ws = 
getProperty(FILESTORE_watcherSensitivity, WatcherSensitivity.class, 
WatcherSensitivity.MEDIUM);
+                       watcher = getBooleanProperty(FILESTORE_useWatcher, 
false) ? new WatcherThread(dir, ws) : null;
                        if (watcher != null)
                                watcher.start();
-               } catch (IOException e) {
+               } catch (Exception e) {
                        throw new RuntimeException(e);
                }
        }
        
+       @Override /* Store */
+       public synchronized String read(String name) throws Exception {
+               String s = cache.get(name);
+               if (s != null)
+                       return s;
+               
+               dir.mkdirs();
+               Path p = dir.toPath().resolve(name + '.' + ext);
+               if (! Files.exists(p)) 
+                       return null;
+               try (FileChannel fc = FileChannel.open(p, READ, WRITE, CREATE)) 
{
+                       try (FileLock lock = fc.lock()) {
+                               ByteBuffer buf = ByteBuffer.allocate(1024);
+                               StringBuilder sb = new StringBuilder();
+                               while (fc.read(buf) != -1) {
+                                       
sb.append(charset.decode((ByteBuffer)(buf.flip())));
+                                       buf.clear();
+                               }
+                               s = sb.toString();
+                               cache.put(name, s);
+                       }
+               }
+               
+               return cache.get(name);
+       }
+
+       @Override /* Store */
+       public synchronized boolean write(String name, String oldContents, 
String newContents) throws Exception {
+               dir.mkdirs();
+               Path p = dir.toPath().resolve(name + '.' + ext);
+               boolean exists = Files.exists(p);
+               if (oldContents != null && ! exists)
+                       return false;
+               try (FileChannel fc = FileChannel.open(p, READ, WRITE, CREATE)) 
{
+                       try (FileLock lock = fc.lock()) {
+                               String currentContents = null;
+                               if (exists) {
+                                       ByteBuffer buf = 
ByteBuffer.allocate(1024);
+                                       StringBuilder sb = new StringBuilder();
+                                       while (fc.read(buf) != -1) {
+                                               
sb.append(charset.decode((ByteBuffer)(buf.flip())));
+                                               buf.clear();
+                                       }
+                                       currentContents = sb.toString();
+                               }
+                               if (! isEquals(oldContents, currentContents)) {
+                                       if (currentContents == null)
+                                               cache.remove(name);
+                                       else
+                                               cache.put(name, 
currentContents);
+                                       return false;
+                               }
+                               fc.position(0);
+                               fc.write(charset.encode(newContents));
+                               cache.put(name, newContents);
+                       }
+               }
+               return true;
+       }
+               
+       @Override /* Store */
+       public synchronized FileStore update(String name, String newContents) {
+               cache.put(name, newContents);
+               super.update(name, newContents);
+               return this;
+       }
+
        @Override /* Closeable */
        public synchronized void close() {
                if (watcher != null)
                        watcher.interrupt();
        }
        
+       
        
//---------------------------------------------------------------------------------------------
        // WatcherThread
        
//---------------------------------------------------------------------------------------------
 
        final class WatcherThread extends Thread {
                private final WatchService watchService;
-
-               WatcherThread(File dir) throws IOException {
+               
+               WatcherThread(File dir, WatcherSensitivity s) throws Exception {
                        watchService = 
FileSystems.getDefault().newWatchService();
-                       dir.toPath().register(watchService, ENTRY_CREATE, 
ENTRY_DELETE, ENTRY_MODIFY);
+                       WatchEvent.Kind<?>[] kinds = new 
WatchEvent.Kind[]{ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY};
+                       WatchEvent.Modifier modifier = lookupModifier(s);
+                       dir.toPath().register(watchService, kinds, modifier);
+               }
+               
+               @SuppressWarnings("restriction")
+               private WatchEvent.Modifier lookupModifier(WatcherSensitivity 
s) {
+                       try {
+                               switch(s) {
+                                       case LOW: return 
com.sun.nio.file.SensitivityWatchEventModifier.LOW;
+                                       case MEDIUM: return 
com.sun.nio.file.SensitivityWatchEventModifier.MEDIUM;
+                                       case HIGH: return 
com.sun.nio.file.SensitivityWatchEventModifier.HIGH;
+                               }
+                       } catch (Exception e) {
+                               /* Ignore */
+                       }
+                       return null;
+                       
                }
                
                @SuppressWarnings("unchecked")
                @Override /* Thread */
                public void run() {
                    try {
-                               while (true) {
-                                   WatchKey key = watchService.take();
-                                   
-                                   for (WatchEvent<?> event: key.pollEvents()) 
{
+                               WatchKey key;
+                               while ((key = watchService.take()) != null) {
+                                   for (WatchEvent<?> event : 
key.pollEvents()) {
                                        WatchEvent.Kind<?> kind = event.kind();
-
                                        if (kind != OVERFLOW) 
                                                        
FileStore.this.onFileEvent(((WatchEvent<Path>)event));
-                                   }  
-                                   
+                                   }
                                    if (! key.reset())
                                                break;
                                }
                        } catch (Exception e) {
+                               e.printStackTrace();
                                throw new RuntimeException(e);
                        }
                };
@@ -217,65 +343,25 @@ public class FileStore extends Store {
                }
        }
        
-       synchronized void onFileEvent(WatchEvent<Path> e) throws IOException {
-               File f = e.context().toFile();
-               String fn = f.getName();
+       /**
+        * Gets called when the watcher service on this store is triggered with 
a file system change.
+        * 
+        * @param e The file system event.
+        * @throws Exception
+        */
+       protected synchronized void onFileEvent(WatchEvent<Path> e) throws 
Exception {
+               String fn = e.context().getFileName().toString();
                String bn = FileUtils.getBaseName(fn);
                String ext = FileUtils.getExtension(fn);
-               if (ext.equals(ext)) {
-                       String newContents = IOUtils.read(f);
+               
+               if (isEquals(this.ext, ext)) {
                        String oldContents = cache.get(bn);
-                       if (! StringUtils.isEquals(oldContents, newContents)) {
-                               onChange(bn, newContents);
-                               cache.put(bn, newContents);
+                       cache.remove(bn);
+                       String newContents = read(bn);
+                       if (! isEquals(oldContents, newContents)) {
+                               update(bn, newContents);
                        }
                }
        }
                
-       @Override
-       public synchronized String read(String name) throws Exception {
-               String s = cache.get(name);
-               if (s != null)
-                       return s;
-               
-               File f = new File(dir, name + '.' + ext);
-               if (f.exists()) {
-                       try (FileInputStream fis = new FileInputStream(f)) {
-                               try (FileLock lock = fis.getChannel().lock()) {
-                                       try (Reader r = new 
InputStreamReader(fis, charset)) {
-                                               String contents = 
IOUtils.read(r);
-                                               cache.put(name, contents);
-                                       }
-                               }
-                       }
-               }
-               
-               return cache.get(name);
-       }
-
-       @Override
-       public synchronized boolean write(String name, String oldContents, 
String newContents) throws Exception {
-               File f = new File(dir, name + '.' + ext);
-               try (FileChannel fc = FileChannel.open(f.toPath(), 
StandardOpenOption.READ, StandardOpenOption.WRITE)) {
-                       try (FileLock lock = fc.lock()) {
-                               ByteBuffer buf = ByteBuffer.allocate(1024);
-                               StringBuilder sb = new StringBuilder();
-                               while (fc.read(buf) != -1) {
-                                       sb.append(charset.decode(buf));
-                                       
sb.append(charset.decode((ByteBuffer)(buf.flip())));
-                                       buf.clear();
-                               }
-                               String s = sb.toString();
-                               if (! StringUtils.isEquals(oldContents, 
sb.toString())) {
-                                       cache.put(name, s);
-                                       return false;
-                               }
-                               fc.position(0);
-                               fc.write(charset.encode(newContents));
-                               cache.put(name, newContents);
-                               return true;
-                       }
-                       
-               }
-       }
 }
diff --git 
a/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/store/FileStoreBuilder.java
 
b/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/store/FileStoreBuilder.java
index f949085..0ae98c0 100644
--- 
a/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/store/FileStoreBuilder.java
+++ 
b/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/store/FileStoreBuilder.java
@@ -169,6 +169,48 @@ public class FileStoreBuilder extends StoreBuilder {
        }
        
        /**
+        * Configuration property:  Watcher sensitivity.
+        * 
+        * <p>
+        * Determines how frequently the file system is polled for updates.
+        * 
+        * <h5 class='section'>See Also:</h5>
+        * <ul>
+        *      <li class='jf'>{@link FileStore#FILESTORE_watcherSensitivity}
+        * </ul>
+        * 
+        * @param value 
+        *      The new value for this property.
+        *      <br>The default is {@link WatcherSensitivity#MEDIUM}
+        * @return This object (for method chaining).
+        */
+       public FileStoreBuilder watcherSensitivity(WatcherSensitivity value) {
+               super.set(FILESTORE_watcherSensitivity, value);
+               return this;
+       }
+
+       /**
+        * Configuration property:  Watcher sensitivity.
+        * 
+        * <p>
+        * Determines how frequently the file system is polled for updates.
+        * 
+        * <h5 class='section'>See Also:</h5>
+        * <ul>
+        *      <li class='jf'>{@link FileStore#FILESTORE_watcherSensitivity}
+        * </ul>
+        * 
+        * @param value 
+        *      The new value for this property.
+        *      <br>The default is {@link WatcherSensitivity#MEDIUM}
+        * @return This object (for method chaining).
+        */
+       public FileStoreBuilder watcherSensitivity(String value) {
+               super.set(FILESTORE_watcherSensitivity, value);
+               return this;
+       }
+
+       /**
         * Configuration property:  Config file extension.
         * 
         * <p>
diff --git 
a/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/store/MemoryStore.java
 
b/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/store/MemoryStore.java
index f24e642..8dde322 100644
--- 
a/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/store/MemoryStore.java
+++ 
b/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/store/MemoryStore.java
@@ -27,6 +27,18 @@ import org.apache.juneau.*;
  */
 public class MemoryStore extends Store {
 
+       
//-------------------------------------------------------------------------------------------------------------------
+       // Predefined instances
+       
//-------------------------------------------------------------------------------------------------------------------
+
+       /** Default memory store, all default values.*/
+       public static final MemoryStore DEFAULT = MemoryStore.create().build();
+
+
+       
//-------------------------------------------------------------------------------------------------------------------
+       // Instance
+       
//-------------------------------------------------------------------------------------------------------------------
+       
        /**
         * Create a new builder for this object.
         * 
@@ -66,12 +78,20 @@ public class MemoryStore extends Store {
                
                if (! isEquals(s, newContents)) {
                        cache.put(name, newContents);
-                       onChange(name, newContents);
+                       update(name, newContents);
                }
                
                return true;
        }
 
+       
+       @Override /* Store */
+       public synchronized MemoryStore update(String name, String newContents) 
{
+               cache.put(name, newContents);
+               super.update(name, newContents);
+               return this;
+       }
+
        /**
         * No-op.
         */
diff --git 
a/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/store/Store.java
 
b/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/store/Store.java
index 7e16c21..6b8488c 100644
--- 
a/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/store/Store.java
+++ 
b/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/store/Store.java
@@ -93,7 +93,7 @@ public abstract class Store extends Context implements 
Closeable {
         * @param contents The new contents.
         * @return This object (for method chaining).
         */
-       protected Store onChange(String name, String contents) {
+       public Store update(String name, String contents) {
                for (StoreListener l : listeners)
                        l.onChange(name, contents);
                return this;
diff --git 
a/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/store/MemoryStore.java
 
b/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/store/WatcherSensitivity.java
similarity index 52%
copy from 
juneau-core/juneau-config/src/main/java/org/apache/juneau/config/store/MemoryStore.java
copy to 
juneau-core/juneau-config/src/main/java/org/apache/juneau/config/store/WatcherSensitivity.java
index f24e642..ad789a5 100644
--- 
a/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/store/MemoryStore.java
+++ 
b/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/store/WatcherSensitivity.java
@@ -12,71 +12,22 @@
 // 
***************************************************************************************************************************
 package org.apache.juneau.config.store;
 
-import static org.apache.juneau.internal.StringUtils.*;
-
-import java.io.*;
-import java.util.concurrent.*;
-
-import org.apache.juneau.*;
-
 /**
- * Filesystem-based storage location for configuration files.
+ * Determines how often the file system is polled by the watcher in {@link 
FileStore}.
  * 
- * <p>
- * Points to a file system directory containing configuration files.
+ * <h5 class='section'>Notes:</h5>
+ * <ul class='spaced-list'>
+ *     <li>This relies on internal Sun packages and may not work on all JVMs.
+ * </ul>
  */
-public class MemoryStore extends Store {
-
-       /**
-        * Create a new builder for this object.
-        * 
-        * @return A new builder for this object.
-        */
-       public static MemoryStoreBuilder create() {
-               return new MemoryStoreBuilder();
-       }
+public enum WatcherSensitivity {
        
-       @Override /* Context */
-       public MemoryStoreBuilder builder() {
-               return new MemoryStoreBuilder(getPropertyStore());
-       }
-
-       private final ConcurrentHashMap<String,String> cache = new 
ConcurrentHashMap<>();
+       /** 30 seconds */
+       LOW, 
        
-       /**
-        * Constructor.
-        * 
-        * @param ps The settings for this content store.
-        */
-       protected MemoryStore(PropertyStore ps) {
-               super(ps);
-       }
+       /** 10 seconds */
+       MEDIUM, 
        
-       @Override /* Store */
-       public synchronized String read(String name) throws Exception {
-               return cache.get(name);
-       }
-
-       @Override /* Store */
-       public synchronized boolean write(String name, String oldContents, 
String newContents) throws Exception {
-               String s = cache.get(name);
-               
-               if (! isEquals(s, oldContents)) 
-                       return false;
-               
-               if (! isEquals(s, newContents)) {
-                       cache.put(name, newContents);
-                       onChange(name, newContents);
-               }
-               
-               return true;
-       }
-
-       /**
-        * No-op.
-        */
-       @Override /* Closeable */
-       public void close() throws IOException {
-               // No-op
-       }
+       /** 2 seconds */
+       HIGH;
 }
diff --git 
a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/config/store/FileStoreTest.java
 
b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/config/store/FileStoreTest.java
new file mode 100644
index 0000000..97b76e9
--- /dev/null
+++ 
b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/config/store/FileStoreTest.java
@@ -0,0 +1,134 @@
+// 
***************************************************************************************************************************
+// * 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.config.store;
+
+import static org.junit.Assert.*;
+
+import java.io.*;
+import java.util.concurrent.*;
+
+import org.apache.juneau.internal.*;
+import org.junit.*;
+
+public class FileStoreTest {
+       
+       private static final File DIR = new File("./config");
+       
+       @After
+       public void cleanUp() {
+               FileUtils.delete(DIR);
+       }
+       
+       @Test
+       public void testNoFile() throws Exception {
+               FileStore fs = FileStore.create().directory(DIR).build();
+               assertEquals(null, fs.read("X"));
+               assertFileNotExists("X.cfg");
+       }
+
+       @Test
+       public void testDifferentExtension() throws Exception {
+               FileStore fs = 
FileStore.create().directory(DIR).ext("ini").build();
+               assertEquals(null, fs.read("X"));
+               assertFileNotExists("X.ini");
+       }
+
+       @Test
+       public void testSimpleCreate() throws Exception {
+               FileStore fs = FileStore.create().directory(DIR).build();
+               assertTrue(fs.write("X", null, "foo"));
+               assertEquals("foo", fs.read("X"));
+               assertFileExists("X.cfg");
+       }
+
+       @Test
+       public void testFailOnMismatch() throws Exception {
+               FileStore fs = FileStore.create().directory(DIR).build();
+               assertFalse(fs.write("X", "xxx", "foo"));
+               assertEquals(null, fs.read("X"));
+               assertFileNotExists("X.cfg");
+               assertTrue(fs.write("X", null, "foo"));
+               assertEquals("foo", fs.read("X"));
+               assertFalse(fs.write("X", "xxx", "foo"));
+               assertEquals("foo", fs.read("X"));
+               assertTrue(fs.write("X", "foo", "bar"));
+               assertEquals("bar", fs.read("X"));
+       }
+       
+       @Test
+       public void testCharset() throws Exception {
+               FileStore fs = 
FileStore.create().directory(DIR).charset("UTF-8").build();
+               assertTrue(fs.write("X", null, "foo"));
+               assertEquals("foo", fs.read("X"));
+       }               
+       
+       @Test
+       public void testWatcher() throws Exception {
+               FileStore fs = 
FileStore.create().directory(DIR).useWatcher().watcherSensitivity(WatcherSensitivity.HIGH).build();
+
+               final CountDownLatch latch = new CountDownLatch(2);
+               final boolean[] error = {false};
+               fs.register(new StoreListener() {
+                       @Override
+                       public void onChange(String name, String contents) {
+                               if ("X".equals(name) && "xxx".equals(contents))
+                                       latch.countDown();
+                               else if ("Y".equals(name) && 
"yyy".equals(contents))
+                                       latch.countDown();
+                               else
+                                       error[0] = true;
+                       }
+               });
+               IOUtils.write(new File(DIR, "Z.ini"), new StringReader("zzz"));
+               IOUtils.write(new File(DIR, "X.cfg"), new StringReader("xxx"));
+               IOUtils.write(new File(DIR, "Y.cfg"), new StringReader("yyy"));
+               if (! latch.await(10, TimeUnit.SECONDS))
+                       throw new Exception("CountDownLatch never reached 
zero.");
+               assertFalse(error[0]);
+       }
+       
+       @Test
+       public void testUpdate() throws Exception {
+               FileStore fs = FileStore.create().directory(DIR).build();
+
+               final CountDownLatch latch = new CountDownLatch(2);
+               final boolean[] error = {false};
+               fs.register(new StoreListener() {
+                       @Override
+                       public void onChange(String name, String contents) {
+                               if ("X".equals(name) && "xxx".equals(contents))
+                                       latch.countDown();
+                               else if ("Y".equals(name) && 
"yyy".equals(contents))
+                                       latch.countDown();
+                               else
+                                       error[0] = true;
+                       }
+               });
+               
+               fs.update("X", "xxx");
+               fs.update("Y", "yyy");
+               if (! latch.await(10, TimeUnit.SECONDS))
+                       throw new Exception("CountDownLatch never reached 
zero.");
+               assertFalse(error[0]);
+       }       
+       
+       
+       private void assertFileExists(String name) {
+               assertTrue(new File(DIR, name).exists());
+       }
+       
+       private void assertFileNotExists(String name) {
+               assertTrue(! new File(DIR, name).exists());
+       }
+       
+}
diff --git 
a/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/store/MemoryStore.java
 
b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/config/store/MemoryStoreTest.java
similarity index 51%
copy from 
juneau-core/juneau-config/src/main/java/org/apache/juneau/config/store/MemoryStore.java
copy to 
juneau-core/juneau-core-test/src/test/java/org/apache/juneau/config/store/MemoryStoreTest.java
index f24e642..ac38dff 100644
--- 
a/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/store/MemoryStore.java
+++ 
b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/config/store/MemoryStoreTest.java
@@ -12,71 +12,62 @@
 // 
***************************************************************************************************************************
 package org.apache.juneau.config.store;
 
-import static org.apache.juneau.internal.StringUtils.*;
+import static org.junit.Assert.*;
 
-import java.io.*;
 import java.util.concurrent.*;
 
-import org.apache.juneau.*;
+import org.junit.*;
 
-/**
- * Filesystem-based storage location for configuration files.
- * 
- * <p>
- * Points to a file system directory containing configuration files.
- */
-public class MemoryStore extends Store {
-
-       /**
-        * Create a new builder for this object.
-        * 
-        * @return A new builder for this object.
-        */
-       public static MemoryStoreBuilder create() {
-               return new MemoryStoreBuilder();
-       }
+public class MemoryStoreTest {
        
-       @Override /* Context */
-       public MemoryStoreBuilder builder() {
-               return new MemoryStoreBuilder(getPropertyStore());
+       @Test
+       public void testNoFile() throws Exception {
+               MemoryStore fs = MemoryStore.create().build();
+               assertEquals(null, fs.read("X"));
        }
 
-       private final ConcurrentHashMap<String,String> cache = new 
ConcurrentHashMap<>();
-       
-       /**
-        * Constructor.
-        * 
-        * @param ps The settings for this content store.
-        */
-       protected MemoryStore(PropertyStore ps) {
-               super(ps);
-       }
-       
-       @Override /* Store */
-       public synchronized String read(String name) throws Exception {
-               return cache.get(name);
+       @Test
+       public void testSimpleCreate() throws Exception {
+               MemoryStore fs = MemoryStore.create().build();
+               assertTrue(fs.write("X", null, "foo"));
+               assertEquals("foo", fs.read("X"));
        }
 
-       @Override /* Store */
-       public synchronized boolean write(String name, String oldContents, 
String newContents) throws Exception {
-               String s = cache.get(name);
-               
-               if (! isEquals(s, oldContents)) 
-                       return false;
-               
-               if (! isEquals(s, newContents)) {
-                       cache.put(name, newContents);
-                       onChange(name, newContents);
-               }
-               
-               return true;
+       @Test
+       public void testFailOnMismatch() throws Exception {
+               MemoryStore fs = MemoryStore.create().build();
+               assertFalse(fs.write("X", "xxx", "foo"));
+               assertEquals(null, fs.read("X"));
+               assertTrue(fs.write("X", null, "foo"));
+               assertEquals("foo", fs.read("X"));
+               assertFalse(fs.write("X", "xxx", "foo"));
+               assertEquals("foo", fs.read("X"));
+               assertTrue(fs.write("X", "foo", "bar"));
+               assertEquals("bar", fs.read("X"));
        }
+       
+       @Test
+       public void testUpdate() throws Exception {
+               MemoryStore fs = MemoryStore.create().build();
 
-       /**
-        * No-op.
-        */
-       @Override /* Closeable */
-       public void close() throws IOException {
-               // No-op
-       }
+               final CountDownLatch latch = new CountDownLatch(2);
+               final boolean[] error = {false};
+               fs.register(new StoreListener() {
+                       @Override
+                       public void onChange(String name, String contents) {
+                               if ("X".equals(name) && "xxx".equals(contents))
+                                       latch.countDown();
+                               else if ("Y".equals(name) && 
"yyy".equals(contents))
+                                       latch.countDown();
+                               else
+                                       error[0] = true;
+                       }
+               });
+               
+               fs.update("X", "xxx");
+               fs.update("Y", "yyy");
+               if (! latch.await(10, TimeUnit.SECONDS))
+                       throw new Exception("CountDownLatch never reached 
zero.");
+               assertFalse(error[0]);
+       }       
 }

-- 
To stop receiving notification emails like this one, please contact
[email protected].

Reply via email to