CORDA-3638: Allow CordaFuture to complete even if an Error is thrown. (#5994)

* Allow CordaFuture to complete even if an Error is thrown.

* Allow CordaFuture.flatMap() to notify for failures due to Error.
This commit is contained in:
Chris Rankin 2020-03-03 15:01:12 +00:00 committed by GitHub
parent da3adb40b4
commit fec2ef2fd3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -78,6 +78,7 @@ fun <ELEMENT> CordaFuture<out ELEMENT>.mapError(transform: (Throwable) -> Throwa
* But if this future or the transform fails, the returned future's outcome is the same throwable.
* In the case where this future fails, the transform is not invoked.
*/
@Suppress("TooGenericExceptionCaught")
fun <V, W> CordaFuture<out V>.flatMap(transform: (V) -> CordaFuture<out W>): CordaFuture<W> = CordaFutureImpl<W>().also { result ->
thenMatch(success@ {
result.captureLater(try {
@ -85,6 +86,9 @@ fun <V, W> CordaFuture<out V>.flatMap(transform: (V) -> CordaFuture<out W>): Cor
} catch (e: Exception) {
result.setException(e)
return@success
} catch (t: Throwable) {
result.setException(t)
throw t
})
}, {
result.setException(it)
@ -136,11 +140,15 @@ interface ValueOrException<in V> {
fun captureLater(f: CordaFuture<out V>) = f.then { capture { f.getOrThrow() } }
/** Run the given block (in the foreground) and set this future to its outcome. */
@Suppress("TooGenericExceptionCaught")
fun capture(block: () -> V): Boolean {
return set(try {
block()
} catch (e: Exception) {
return setException(e)
} catch (t: Throwable) {
setException(t)
throw t
})
}
}
@ -160,12 +168,16 @@ internal class CordaFutureImpl<V>(private val impl: CompletableFuture<V> = Compl
override fun setException(t: Throwable) = impl.completeExceptionally(t)
override fun <W> then(callback: (CordaFuture<V>) -> W) = thenImpl(defaultLog, callback)
/** For testing only. */
@Suppress("TooGenericExceptionCaught")
internal fun <W> thenImpl(log: Logger, callback: (CordaFuture<V>) -> W) {
impl.whenComplete { _, _ ->
try {
callback(this)
} catch (e: Exception) {
log.error(listenerFailedMessage, e)
} catch (t: Throwable) {
log.error(listenerFailedMessage, t)
throw t
}
}
}