From 09ff8fa3462da0bd16fe771cca589bb4370cc74d Mon Sep 17 00:00:00 2001 From: Ian Clarke Date: Sun, 1 Jul 2018 21:26:14 -0500 Subject: [PATCH] a few small changes, bump build --- build.gradle | 2 +- .../kotlin/io/kweb/shoebox/OrderedViewSet.kt | 22 +++++++++++-------- src/main/kotlin/io/kweb/shoebox/Shoebox.kt | 22 ++++++++++++++++--- src/main/kotlin/io/kweb/shoebox/View.kt | 18 ++++++++++++--- .../io/kweb/shoebox/stores/DirectoryStore.kt | 10 ++++++++- .../io/kweb/shoebox/OrderedViewSetSpec.kt | 10 ++++----- 6 files changed, 61 insertions(+), 23 deletions(-) diff --git a/build.gradle b/build.gradle index 595673b..dc20a9a 100644 --- a/build.gradle +++ b/build.gradle @@ -1,5 +1,5 @@ group 'io.kweb' -version '0.2.16' +version '0.2.17' buildscript { ext.kotlin_version = '1.2.50' diff --git a/src/main/kotlin/io/kweb/shoebox/OrderedViewSet.kt b/src/main/kotlin/io/kweb/shoebox/OrderedViewSet.kt index 0db0139..2ea41ca 100644 --- a/src/main/kotlin/io/kweb/shoebox/OrderedViewSet.kt +++ b/src/main/kotlin/io/kweb/shoebox/OrderedViewSet.kt @@ -6,6 +6,7 @@ import java.util.concurrent.ConcurrentHashMap /** * Created by ian on 3/14/17. */ + class OrderedViewSet(val view : View, val viewKey : String, val comparator: Comparator) { private val orderedList : MutableList> @@ -22,13 +23,17 @@ class OrderedViewSet(val view : View, val viewKey : String, val comp additionHandle = view.onAdd(viewKey) { keyValue -> val binarySearchResult = orderedList.betterBinarySearch(keyValue, kvComparator) val insertionPoint: Int = when (binarySearchResult) { - is Exact -> { - throw RuntimeException("Listener called for key/value already in list keyValue: $keyValue orderedList[${binarySearchResult.index}] = ${orderedList[binarySearchResult.index]}") - } + is Exact -> binarySearchResult.index is Between -> binarySearchResult.highIndex } ol.add(insertionPoint, keyValue) - insertListeners.values.forEach { it(insertionPoint, keyValue) } + insertListeners.values.forEach { + try { + it(insertionPoint, keyValue) + } catch (e: Exception) { + e.printStackTrace(System.err) + } + } } removalHandle = view.onRemove(viewKey) { keyValue -> @@ -53,18 +58,17 @@ class OrderedViewSet(val view : View, val viewKey : String, val comp val newKeyValue = KeyValue(kv.key, newValue) val insertPoint = orderedList.betterBinarySearch(newKeyValue, kvComparator) val insertionIndex: Int = when (insertPoint) { - is Exact -> throw RuntimeException("Object modified to same value as an existing object ($newValue)") + is Exact -> insertPoint.index is Between -> insertPoint.highIndex } insertListeners.values.forEach { it(insertionIndex, newKeyValue) } val oldKeyValue = KeyValue(kv.key, oldValue) val removePoint = orderedList.betterBinarySearch(oldKeyValue, kvComparator) - val removalIndex = when (removePoint) { - is Exact -> removePoint.index - is Between -> throw RuntimeException("Object modified from an unknown value ($oldValue)") + when (removePoint) { + is Exact -> removeListeners.values.forEach { it(removePoint.index, oldKeyValue) } } - removeListeners.values.forEach { it(removalIndex, oldKeyValue) } + } }) } diff --git a/src/main/kotlin/io/kweb/shoebox/Shoebox.kt b/src/main/kotlin/io/kweb/shoebox/Shoebox.kt index c8877a6..0e77c4a 100644 --- a/src/main/kotlin/io/kweb/shoebox/Shoebox.kt +++ b/src/main/kotlin/io/kweb/shoebox/Shoebox.kt @@ -52,7 +52,11 @@ class Shoebox(val store: Store, private val kc: KClass) { * @return The value associated with the key, or null if no value is associated */ operator fun get(key: String): T? { - return store.get(key) + try { + return store.get(key) + } catch (e: Exception) { + throw RuntimeException("Exception in call to get(\"$key\")", e) + } } /** @@ -77,10 +81,22 @@ class Shoebox(val store: Store, private val kc: KClass) { operator fun set(key: String, value: T) { val previousValue = store.set(key, value) if (previousValue == null) { - newListeners.values.forEach { l -> l(KeyValue(key, value), LOCAL) } + newListeners.values.forEach { l -> + try { + l(KeyValue(key, value), LOCAL) + } catch (e: Exception) { + e.printStackTrace(System.err) + } + } } else if (value != previousValue) { changeListeners.values.forEach { cl -> cl(previousValue, KeyValue(key, value), LOCAL) } - keySpecificChangeListeners[key]?.values?.forEach { l -> l(previousValue, value, LOCAL) } + keySpecificChangeListeners[key]?.values?.forEach { l -> + try { + l(previousValue, value, LOCAL) + } catch (e: Exception) { + e.printStackTrace(System.err) + } + } } } diff --git a/src/main/kotlin/io/kweb/shoebox/View.kt b/src/main/kotlin/io/kweb/shoebox/View.kt index dbc43d8..ffd1b85 100644 --- a/src/main/kotlin/io/kweb/shoebox/View.kt +++ b/src/main/kotlin/io/kweb/shoebox/View.kt @@ -35,10 +35,22 @@ class View(val references: Shoebox, val nextViewKey = viewBy(nextKeyValue.value) if (previousViewKey != nextViewKey) { - removeListeners[previousViewKey]?.values?.forEach { it(KeyValue(nextKeyValue.key, previousValue)) } + removeListeners[previousViewKey]?.values?.forEach { + try { + it(KeyValue(nextKeyValue.key, previousValue)) + } catch (e: Exception) { + e.printStackTrace(System.err) + } + } removeValue(previousViewKey, nextKeyValue.key) - addListeners[nextViewKey]?.values?.forEach { it(nextKeyValue) } + addListeners[nextViewKey]?.values?.forEach { + try { + it(nextKeyValue) + } catch (e: Exception) { + e.printStackTrace(System.err) + } + } addValue(nextViewKey, nextKeyValue.key) } } @@ -91,7 +103,7 @@ class View(val references: Shoebox, fun onAdd(viewKey : String, listener : (KeyValue) -> Unit) : Long { val handle = listenerHandleSource.incrementAndGet() - addListeners.computeIfAbsent(viewKey, {ConcurrentHashMap()}).put(handle, listener) + addListeners.computeIfAbsent(viewKey) { ConcurrentHashMap() }.put(handle, listener) return handle } diff --git a/src/main/kotlin/io/kweb/shoebox/stores/DirectoryStore.kt b/src/main/kotlin/io/kweb/shoebox/stores/DirectoryStore.kt index 3517492..73e20b8 100644 --- a/src/main/kotlin/io/kweb/shoebox/stores/DirectoryStore.kt +++ b/src/main/kotlin/io/kweb/shoebox/stores/DirectoryStore.kt @@ -39,7 +39,7 @@ class DirectoryStore(val directory : Path, private val kc : KClass) Files.createDirectories(directory) if (Files.exists(lockFilePath)) { if (System.currentTimeMillis() - Files.getLastModifiedTime(lockFilePath).toMillis() < LOCK_STALE_TIME) { - throw RuntimeException("$directory locked by $lockFilePath") + throw RuntimeException("$directory locked by $lockFilePath, created ${System.currentTimeMillis() - Files.getLastModifiedTime(lockFilePath).toMillis()}ms ago.") } else { Files.setLastModifiedTime(lockFilePath, FileTime.fromMillis(System.currentTimeMillis())) } @@ -61,6 +61,7 @@ class DirectoryStore(val directory : Path, private val kc : KClass) override val entries: Iterable> get() = Files.newDirectoryStream(directory) .mapNotNull {it.fileName.toString()} .filter {it != LOCK_FILENAME } + .filter {it.isNotBlank()} .map { KeyValue(it, this[it]!!) } @@ -72,6 +73,7 @@ class DirectoryStore(val directory : Path, private val kc : KClass) * @return The value associated with the key, or null if no value is associated */ override operator fun get(key: String): T? { + require(key.isNotBlank()) {"key(\"$key\") must not be blank"} return load(key) } @@ -81,6 +83,7 @@ class DirectoryStore(val directory : Path, private val kc : KClass) * @param key The key associated with the value to be removed, similar to [MutableMap.remove] */ override fun remove(key: String) : T? { + require(key.isNotBlank()) {"key(\"$key\") must not be blank"} val cachedValue: T? = cache.getIfPresent(key) if (cachedValue != null) { cache.invalidate(key) @@ -106,6 +109,7 @@ class DirectoryStore(val directory : Path, private val kc : KClass) * @param value The new value */ override operator fun set(key: String, value: T) : T? { + require(key.isNotBlank()) {"key(\"$key\") must not be blank"} val previousValue = get(key) cache.put(key, value) if (value != previousValue) { @@ -119,8 +123,12 @@ class DirectoryStore(val directory : Path, private val kc : KClass) } private fun load(key: String): T? { + require(key.isNotBlank()) {"key(\"$key\") must not be blank"} val filePath = directory.resolve(key) if (Files.exists(filePath)) { + if (Files.isDirectory(filePath)) { + throw IllegalStateException("File $filePath is a directory, not a file") + } val o = filePath.newBufferedReader().use { gson.fromJson(it, kc.javaObjectType) } diff --git a/src/test/kotlin/io/kweb/shoebox/OrderedViewSetSpec.kt b/src/test/kotlin/io/kweb/shoebox/OrderedViewSetSpec.kt index 071b086..69547f6 100644 --- a/src/test/kotlin/io/kweb/shoebox/OrderedViewSetSpec.kt +++ b/src/test/kotlin/io/kweb/shoebox/OrderedViewSetSpec.kt @@ -1,12 +1,10 @@ package io.kweb.shoebox -import io.kweb.shoebox.data.Gender -import io.kweb.shoebox.data.User -import io.kweb.shoebox.stores.MemoryStore -import io.kotlintest.matchers.shouldBe -import io.kotlintest.matchers.shouldEqual +import io.kotlintest.matchers.* import io.kotlintest.specs.FreeSpec import io.kweb.shoebox.data.Gender.* +import io.kweb.shoebox.data.User +import io.kweb.shoebox.stores.MemoryStore /** * Created by ian on 3/14/17. @@ -126,7 +124,7 @@ class OrderedViewSetSpec : FreeSpec() { val maleViewSet = OrderedViewSet(viewByGender, "MALE", compareBy(User::name)) - maleViewSet.onInsert { p, kv -> + maleViewSet.onInsert { _, kv -> }