juneau-commits mailing list archives

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

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


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

commit c34f1870a57be83f430ea00e04110b5f43bb51b8
Author: JamesBognar <jamesbognar@apache.org>
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
jamesbognar@apache.org.

Mime
View raw message