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

io.github.xstefanox.underkow.dsl.RoutingBuilder.kt Maven / Gradle / Ivy

There is a newer version: 2.4.1
Show newest version
package io.github.xstefanox.underkow.dsl

import io.github.xstefanox.underkow.FunctionHandlerAdapter
import io.github.xstefanox.underkow.HttpHandlerAdapter
import io.github.xstefanox.underkow.SuspendingHttpHandler
import io.github.xstefanox.underkow.chain.HandlerChain
import io.github.xstefanox.underkow.dispatcher.ExchangeDispatcher
import io.github.xstefanox.underkow.exception.SuspendingExceptionHandler
import io.undertow.server.HttpHandler
import io.undertow.server.HttpServerExchange
import io.undertow.server.RoutingHandler
import io.undertow.util.HttpString
import io.undertow.util.Methods.DELETE
import io.undertow.util.Methods.GET
import io.undertow.util.Methods.HEAD
import io.undertow.util.Methods.PATCH
import io.undertow.util.Methods.POST
import io.undertow.util.Methods.PUT
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import kotlin.reflect.KClass

/**
 * A builder used to define the routes supported under a configured path prefix.
 *
 * @param prefix the path prefix applied to each route configured by this builder.
 * @param filters the filters applied to each call handled by the routes defined by this builder.
 */
@UndertowDsl
class RoutingBuilder(
    prefix: String = DEFAULT_PREFIX,
    private val filters: Collection = emptyList(),
    private val dispatcher: ExchangeDispatcher
) {

    private val logger: Logger = LoggerFactory.getLogger(RoutingBuilder::class.java)

    private val prefix: String = prefix.trim()

    private val templates = mutableMapOf>()

    private val paths = mutableListOf()

    private val exceptions = mutableMapOf, SuspendingHttpHandler>()

    init {
        require(this.prefix.isEmpty() || this.prefix.isNotBlank()) {
            BLANK_PREFIX_REQUIREMENT_MESSAGE
        }
    }

    /**
     * Add a new HEAD route to the list of routes configured by this builder.
     *
     * @param template the route template uri.
     * @param handler the handler that will receive the requests, defined as a lambda function.
     */
    fun head(template: String = DEFAULT_PREFIX, handler: suspend (HttpServerExchange) -> Unit) = addHandler(HEAD, template, handler)

    /**
     * Add a new HEAD route to the list of routes configured by this builder.
     *
     * @param template the route template uri.
     * @param handler the handler that will receive the requests.
     */
    fun head(template: String = DEFAULT_PREFIX, handler: SuspendingHttpHandler) = addHandler(HEAD, template, handler)

    /**
     * Add a new HEAD route to the list of routes configured by this builder.
     *
     * @param template the route template uri.
     * @param handler the handler that will receive the requests; it will be wrapped into a [SuspendingHttpHandler].
     */
    fun head(template: String = DEFAULT_PREFIX, handler: HttpHandler) = addHandler(HEAD, template, handler)

    /**
     * Add a new GET route to the list of routes configured by this builder.
     *
     * @param template the route template uri.
     * @param handler the handler that will receive the requests, defined as a lambda function.
     */
    fun get(template: String = DEFAULT_PREFIX, handler: suspend (HttpServerExchange) -> Unit) = addHandler(GET, template, handler)

    /**
     * Add a new GET route to the list of routes configured by this builder.
     *
     * @param template the route template uri.
     * @param handler the handler that will receive the requests.
     */
    fun get(template: String = DEFAULT_PREFIX, handler: SuspendingHttpHandler) = addHandler(GET, template, handler)

    /**
     * Add a new GET route to the list of routes configured by this builder.
     *
     * @param template the route template uri.
     * @param handler the handler that will receive the requests; it will be wrapped into a [SuspendingHttpHandler].
     */
    fun get(template: String = DEFAULT_PREFIX, handler: HttpHandler) = addHandler(GET, template, handler)

    /**
     * Add a new POST route to the list of routes configured by this builder.
     *
     * @param template the route template uri.
     * @param handler the handler that will receive the requests, defined as a lambda function.
     */
    fun post(template: String = DEFAULT_PREFIX, handler: suspend (HttpServerExchange) -> Unit) = addHandler(POST, template, handler)

    /**
     * Add a new POST route to the list of routes configured by this builder.
     *
     * @param template the route template uri.
     * @param handler the handler that will receive the requests.
     */
    fun post(template: String = DEFAULT_PREFIX, handler: SuspendingHttpHandler) = addHandler(POST, template, handler)

    /**
     * Add a new POST route to the list of routes configured by this builder.
     *
     * @param template the route template uri.
     * @param handler the handler that will receive the requests; it will be wrapped into a [SuspendingHttpHandler].
     */
    fun post(template: String = DEFAULT_PREFIX, handler: HttpHandler) = addHandler(POST, template, handler)

    /**
     * Add a new PUT route to the list of routes configured by this builder.
     *
     * @param template the route template uri.
     * @param handler the handler that will receive the requests, defined as a lambda function.
     */
    fun put(template: String = DEFAULT_PREFIX, handler: suspend (HttpServerExchange) -> Unit) = addHandler(PUT, template, handler)

    /**
     * Add a new PUT route to the list of routes configured by this builder.
     *
     * @param template the route template uri.
     * @param handler the handler that will receive the requests.
     */
    fun put(template: String = DEFAULT_PREFIX, handler: SuspendingHttpHandler) = addHandler(PUT, template, handler)

    /**
     * Add a new PUT route to the list of routes configured by this builder.
     *
     * @param template the route template uri.
     * @param handler the handler that will receive the requests; it will be wrapped into a [SuspendingHttpHandler].
     */
    fun put(template: String = DEFAULT_PREFIX, handler: HttpHandler) = addHandler(PUT, template, handler)

    /**
     * Add a new PATCH route to the list of routes configured by this builder.
     *
     * @param template the route template uri.
     * @param handler the handler that will receive the requests, defined as a lambda function.
     */
    fun patch(template: String = DEFAULT_PREFIX, handler: suspend (HttpServerExchange) -> Unit) = addHandler(PATCH, template, handler)

    /**
     * Add a new PATCH route to the list of routes configured by this builder.
     *
     * @param template the route template uri.
     * @param handler the handler that will receive the requests.
     */
    fun patch(template: String = DEFAULT_PREFIX, handler: SuspendingHttpHandler) = addHandler(PATCH, template, handler)

    /**
     * Add a new PATCH route to the list of routes configured by this builder.
     *
     * @param template the route template uri.
     * @param handler the handler that will receive the requests; it will be wrapped into a [SuspendingHttpHandler].
     */
    fun patch(template: String = DEFAULT_PREFIX, handler: HttpHandler) = addHandler(PATCH, template, handler)

    /**
     * Add a new DELETE route to the list of routes configured by this builder.
     *
     * @param template the route template uri.
     * @param handler the handler that will receive the requests, defined as a lambda function.
     */
    fun delete(template: String = DEFAULT_PREFIX, handler: suspend (HttpServerExchange) -> Unit) = addHandler(DELETE, template, handler)

    /**
     * Add a new DELETE route to the list of routes configured by this builder.
     *
     * @param template the route template uri.
     * @param handler the handler that will receive the requests.
     */
    fun delete(template: String = DEFAULT_PREFIX, handler: SuspendingHttpHandler) = addHandler(DELETE, template, handler)

    /**
     * Add a new DELETE route to the list of routes configured by this builder.
     *
     * @param template the route template uri.
     * @param handler the handler that will receive the requests; it will be wrapped into a [SuspendingHttpHandler].
     */
    fun delete(template: String = DEFAULT_PREFIX, handler: HttpHandler) = addHandler(DELETE, template, handler)

    /**
     * Begin the definition of a set of routes nested in the given path prefix. Every call to this method overwrites a
     * previously defined nested routing, if present.
     *
     * @param prefix the path prefix that will be applied to each route defined by the nested builder; it cannot be an
     *               empty or blank string.
     * @param filters the collection of filters that will be applied to every request received by the routes defined by
     *                the nested builder.
     * @param init the lambda function used to configure the nested builder.
     */
    fun path(prefix: String, vararg filters: SuspendingHttpHandler, init: RoutingBuilder.() -> Unit) {

        require(prefix.isNotBlank()) {
            BLANK_PREFIX_REQUIREMENT_MESSAGE
        }

        val routingBuilder = RoutingBuilder(
            this.prefix + prefix.trim(),
            this.filters + filters.toList(),
            dispatcher)

        paths += RouteInitializer(routingBuilder, init)
    }

    /**
     * Configure the builder to handle the exceptions of the given class using the given handler.
     *
     * @param exception the class of the exceptions to handle.
     * @param handler the handler used to handle the catched exceptions.
     */
    fun on(exception: KClass, handler: SuspendingHttpHandler) {
        exceptions[exception] = handler
    }

    /**
     * Configure the builder to handle the exceptions of the given class using the given handler.
     *
     * @param T the class of the exceptions to handle.
     * @param handler the handler used to handle the catched exceptions.
     */
    inline fun  on(handler: SuspendingHttpHandler) {
        on(T::class, handler)
    }

    /**
     * Configure the builder to handle the exceptions of the given class using the given handler.
     *
     * @param T the class of the exceptions to handle.
     * @param handler the handler used to handle the catched exceptions; it will be wrapped into a
     *                [SuspendingHttpHandler].
     */
    inline fun  on(handler: HttpHandler) {
        on(T::class, HttpHandlerAdapter(handler))
    }

    /**
     * Configure the builder to handle the exceptions of the given class using the given handler.
     *
     * @param T the class of the exceptions to handle.
     * @param handler the handler used to handle the catched exceptions; it will be wrapped into a
     *                [SuspendingHttpHandler].
     */
    inline fun  on(noinline handler: suspend (HttpServerExchange) -> Unit) {
        on(T::class, FunctionHandlerAdapter(handler))
    }

    /**
     * Build a new [RoutingHandler] from this builder.
     *
     * @return a [RoutingHandler] configured with the DSL defined by this builder.
     */
    fun build(): RoutingHandler {

        val routingHandler = RoutingHandler()

        templates.forEach { template, map ->
            map.forEach { method, handler ->
                logger.debug("found route $method $template")
                routingHandler.add(method, template, HandlerChain(filters + handler, SuspendingExceptionHandler(exceptions, UNHANDLED_EXCEPTION_HANDLER), dispatcher))
            }
        }

        paths.forEach { group ->
            routingHandler.addAll(group.build())
        }

        return routingHandler
    }

    private fun addHandler(method: HttpString, template: String = DEFAULT_PREFIX, handler: SuspendingHttpHandler) {

        require(template.isEmpty() || template.isNotBlank()) {
            BLANK_PREFIX_REQUIREMENT_MESSAGE
        }

        val pathHandlers = templates.computeIfAbsent(prefix + template) {
            mutableMapOf()
        }

        pathHandlers[method] = handler
    }

    private fun addHandler(method: HttpString, template: String = DEFAULT_PREFIX, handler: HttpHandler) {
        addHandler(method, template, HttpHandlerAdapter(handler))
    }

    private fun addHandler(method: HttpString, template: String = DEFAULT_PREFIX, handler: suspend (HttpServerExchange) -> Unit) {
        addHandler(method, template, FunctionHandlerAdapter(handler))
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy