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

remote.Server.kt Maven / Gradle / Ivy

package ch.softappeal.yass.remote

import ch.softappeal.yass.Interceptor
import ch.softappeal.yass.OnlyNeededForJava
import ch.softappeal.yass.compositeInterceptor
import ch.softappeal.yass.invoke

typealias ReplyWriter = (reply: Reply) -> Unit

abstract class AbstractService internal constructor(val contractId: ContractId, internal val implementation: C) {
    internal abstract fun invoke(invocation: AbstractInvocation, replyWriter: ReplyWriter)
}

class ServerInvocation internal constructor(
    val service: AbstractService<*>, request: Request
) : AbstractInvocation(service.contractId.methodMapper.map(request.methodId), request.arguments) {
    fun invoke(replyWriter: ReplyWriter) =
        service.invoke(this, replyWriter)
}

class Server @SafeVarargs constructor(vararg services: AbstractService<*>) {
    private val id2service = mutableMapOf>()

    init {
        for (service in services) {
            check(id2service.put(service.contractId.id, service) == null) { "service id ${service.contractId.id} already added" }
        }
    }

    fun invocation(asyncSupported: Boolean, request: Request): ServerInvocation {
        val service = checkNotNull(id2service[request.serviceId]) {
            "no service id ${request.serviceId} found (method id ${request.methodId})"
        }
        check(asyncSupported || (service !is AsyncService<*>)) {
            "asynchronous services not supported (service id ${service.contractId.id})"
        }
        return ServerInvocation(service, request)
    }
}

val EmptyServer = Server()

class Service @SafeVarargs constructor(
    contractId: ContractId, implementation: C, vararg interceptors: Interceptor
) : AbstractService(contractId, implementation) {
    private val interceptor = compositeInterceptor(*interceptors)
    override fun invoke(invocation: AbstractInvocation, replyWriter: ReplyWriter) {
        replyWriter(try {
            ValueReply(invoke(interceptor, invocation.methodMapping.method, implementation, invocation.arguments))
        } catch (e: Exception) {
            if (invocation.methodMapping.oneWay) throw e
            ExceptionReply(e)
        })
    }
}

@OnlyNeededForJava
@SafeVarargs
fun  service(contractId: ContractId, implementation: C, vararg interceptors: Interceptor) =
    Service(contractId, implementation, *interceptors)

abstract class Completer {
    abstract fun complete(result: Any?)
    fun complete() = complete(null)
    abstract fun completeExceptionally(exception: Exception)
}

private val completer_ = ThreadLocal()

val completer: Completer
    get() = checkNotNull(completer_.get()) { "no active asynchronous request/reply service invocation" }

class AsyncService(
    contractId: ContractId, implementation: C, private val interceptor: AsyncInterceptor = DirectAsyncInterceptor
) : AbstractService(contractId, implementation) {
    override fun invoke(invocation: AbstractInvocation, replyWriter: ReplyWriter) {
        val oldCompleter = completer_.get()
        completer_.set(if (invocation.methodMapping.oneWay) null else object : Completer() {
            override fun complete(result: Any?) {
                interceptor.exit(invocation, result)
                replyWriter(ValueReply(result))
            }

            override fun completeExceptionally(exception: Exception) {
                interceptor.exception(invocation, exception)
                replyWriter(ExceptionReply(exception))
            }
        })
        try {
            interceptor.entry(invocation)
            invoke(invocation.methodMapping.method, implementation, invocation.arguments)
        } finally {
            completer_.set(oldCompleter)
        }
    }
}

@OnlyNeededForJava
@JvmOverloads
fun  asyncService(contractId: ContractId, implementation: C, interceptor: AsyncInterceptor = DirectAsyncInterceptor) =
    AsyncService(contractId, implementation, interceptor)




© 2015 - 2025 Weber Informatics LLC | Privacy Policy