All Downloads are FREE. Search and download functionalities are using the official Maven repository.

.kovenant.kovenant-core.3.3.0.source-code.context-api.kt Maven / Gradle / Ivy

/*
 * Copyright (c) 2015 Mark Platvoet
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * THE SOFTWARE.
 */
@file:JvmName("KovenantContextApi")

package nl.komponents.kovenant


object Kovenant {
    private val concrete = ConcreteKovenant()

    var context: Context
        get() = concrete.context
        set(value) {
            concrete.context = value
        }


    fun context(body: MutableContext.() -> Unit): Context = concrete.context(body)

    fun createContext(body: MutableContext.() -> Unit): Context = concrete.createContext(body)

    fun  deferred(context: Context = Kovenant.context): Deferred = concrete.deferred(context)

    fun  deferred(context: Context = Kovenant.context, onCancelled: (E) -> Unit): Deferred = concrete.deferred(context, onCancelled)

    fun stop(force: Boolean = false, timeOutMs: Long = 0, block: Boolean = true): List<() -> Unit> {
        return context.stop(force, timeOutMs, block)
    }

    fun  cancel(promise: Promise<*, E>, error: E): Boolean = promise is CancelablePromise && promise.cancel(error)

}

interface Context {
    val multipleCompletion: (curVal: Any?, newVal: Any?) -> Unit

    val callbackContext: DispatcherContext
    val workerContext: DispatcherContext

    fun stop(force: Boolean = false, timeOutMs: Long = 0, block: Boolean = true): List<() -> Unit> {
        val callbackTasks = callbackContext.dispatcher.stop(force, timeOutMs, block)
        val workerTasks = workerContext.dispatcher.stop(force, timeOutMs, block)
        return callbackTasks + workerTasks
    }
}

interface MutableContext : Context {
    override val callbackContext: MutableDispatcherContext
    override val workerContext: MutableDispatcherContext

    override var multipleCompletion: (curVal: Any?, newVal: Any?) -> Unit

    fun callbackContext(body: MutableDispatcherContext.() -> Unit) {
        callbackContext.body()
    }

    fun workerContext(body: MutableDispatcherContext.() -> Unit) {
        workerContext.body()
    }


}

interface ReconfigurableContext : MutableContext {
    fun copy(): ReconfigurableContext
}

interface DispatcherContext {
    companion object {
        fun create(dispatcher: Dispatcher,
                   errorHandler: (Exception) -> Unit): DispatcherContext
                = StaticDispatcherContext(dispatcher, errorHandler)
    }

    val dispatcher: Dispatcher
    val errorHandler: (Exception) -> Unit

    fun offer(fn: () -> Unit): Unit {
        try {
            dispatcher.offer(fn)
        } catch (e: Exception) {
            errorHandler(e)
        }
    }
}

/* Use a DirectDispatcherContext to avoid scheduling. */
object DirectDispatcherContext : DispatcherContext {
    val errorFn: (Exception) -> Unit = { e -> e.printStackTrace() }

    override val dispatcher: Dispatcher = DirectDispatcher.instance
    override val errorHandler: (Exception) -> Unit get() = errorFn
}

interface MutableDispatcherContext : DispatcherContext {
    override var dispatcher: Dispatcher
    override var errorHandler: (Exception) -> Unit

    fun dispatcher(body: DispatcherBuilder.() -> Unit) {
        dispatcher = buildDispatcher(body)
    }
}

private class StaticDispatcherContext(override val dispatcher: Dispatcher,
                                      override val errorHandler: (Exception) -> Unit) : DispatcherContext


/**
 * Puts Kovenant into test mode for the purpose of Unit Testing.
 *
 * - Sets all dispatchers into synchronous mode. So everything happens in order.
 * - attaches the provided failures callback to all error handlers
 * - maps the multiple completion handler to the provided failure handler
 *
 * @param failures callback for all Kovenant errors, defaults to throwing the exception
 */
fun Kovenant.testMode(failures: (Throwable) -> Unit = { throw it }) {
    context {
        callbackContext.dispatcher = DirectDispatcher.instance
        callbackContext.errorHandler = failures

        workerContext.dispatcher = DirectDispatcher.instance
        workerContext.errorHandler = failures

        multipleCompletion = {
            first, second ->
            failures(KovenantException("multiple completion: first = $first, second = $second"))
        }
    }
}


/**
 * Returns a `Promise` operating on the provided `Context`
 *
 * This function might return the same instance of the `Promise` or a new one depending whether the
 * `Context` of the `Promise` and the provided `Promise` match.
 *
 *
 * @param context The `Context` on which the returned promise should operate
 * @return the same `Promise` if the `Context` matches, a new promise otherwise with the provided context
 */
fun  Promise.withContext(context: Context): Promise {
    // Already same context, just return self
    if (this.context == context) return this

    // avoid using deferred and callbacks if this promise
    // is already resolved
    if (isDone()) when {
        isSuccess() -> return Promise.ofSuccess(get(), context)
        isFailure() -> return Promise.ofFail(getError(), context)
    }

    //okay, the hard way
    val deferred = deferred(context)
    success { deferred resolve it }
    fail { deferred reject it }
    return deferred.promise
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy