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

io.lsdconsulting.interceptors.http.common.DefaultHttpInteractionHandler.kt Maven / Gradle / Ivy

Go to download

Provides various interceptors to capture events for the lsd-core library to generate sequence diagrams

There is a newer version: 8.0.73
Show newest version
package io.lsdconsulting.interceptors.http.common

import com.lsd.core.IdGenerator
import com.lsd.core.LsdContext
import com.lsd.core.builders.ActivateLifelineBuilder
import com.lsd.core.builders.DeactivateLifelineBuilder
import com.lsd.core.builders.MessageBuilder.Companion.messageBuilder
import com.lsd.core.domain.MessageType
import io.lsdconsulting.interceptors.common.HeaderKeys
import io.lsdconsulting.interceptors.common.HeaderKeys.TARGET_NAME
import io.lsdconsulting.interceptors.http.naming.DestinationNameMappings
import io.lsdconsulting.interceptors.http.naming.SourceNameMappings
import j2html.TagCreator
import lsd.format.prettyPrint
import org.apache.commons.lang3.StringUtils
import java.time.Duration
import java.util.stream.Collectors

data class DefaultHttpInteractionHandler(
    private val lsdContext: LsdContext,
    private val sourceNameMappings: SourceNameMappings,
    private val destinationNameMappings: DestinationNameMappings
) : HttpInteractionHandler {
    private val idGenerator: IdGenerator = lsdContext.idGenerator

    override fun handleRequest(method: String, requestHeaders: Map, path: String, body: String) {
        val targetName = deriveTargetName(requestHeaders, path)
        lsdContext.capture(
            messageBuilder()
                .id(idGenerator.next())
                .from(deriveSourceName(requestHeaders, path))
                .to(targetName)
                .label("$method $path")
                .data(renderHtmlFor(path, requestHeaders, null, prettyPrint(body), null))
                .type(MessageType.SYNCHRONOUS)
                .build(),
            ActivateLifelineBuilder.activation().of(targetName).colour("skyblue").build()
        )
    }

    override fun handleResponse(
        statusMessage: String,
        requestHeaders: Map,
        responseHeaders: Map,
        path: String,
        body: String,
        duration: Duration
    ) {
        var colour = ""
        if (statusMessage.startsWith("4") || statusMessage.startsWith("5")) colour = "red"
        val targetName = deriveTargetName(requestHeaders, path)
        lsdContext.capture(
            messageBuilder()
                .id(idGenerator.next())
                .from(targetName)
                .to(deriveSourceName(requestHeaders, path))
                .label(statusMessage + " (" + duration.toMillis() + "ms)")
                .data(renderHtmlFor(path, requestHeaders, responseHeaders, prettyPrint(body), duration))
                .type(MessageType.SYNCHRONOUS_RESPONSE)
                .colour(colour)
                .duration(duration)
                .build(),
            DeactivateLifelineBuilder.deactivation().of(targetName).build()
        )
    }

    private fun renderHtmlFor(
        path: String,
        requestHeaders: Map,
        responseHeaders: Map?,
        prettyBody: String,
        duration: Duration?
    ): String {
        return TagCreator.div(
            TagCreator.section(
                TagCreator.h3("Full Path"),
                TagCreator.span(path)
            ),
            if (isMissingHeaders(requestHeaders)) TagCreator.p() else TagCreator.section(
                TagCreator.h3("Request Headers"),
                TagCreator.p(prettyPrintHeaders(requestHeaders))
            ),
            if (isMissingHeaders(responseHeaders)) TagCreator.p() else TagCreator.section(
                TagCreator.h3("Response Headers"),
                TagCreator.p(prettyPrintHeaders(responseHeaders))
            ),
            if (StringUtils.isEmpty(prettyBody)) TagCreator.p() else TagCreator.section(
                TagCreator.h3("Body"),
                TagCreator.p(prettyBody),
                if (null == duration) TagCreator.p() else TagCreator.section(
                    TagCreator.h3("Duration"),
                    TagCreator.p(duration.toMillis().toString() + "ms")
                )
            )
        ).render()
    }

    private fun prettyPrintHeaders(headers: Map?): String {
        return headers!!.entries.stream().map { (key, value): Map.Entry -> "$key: $value" }
            .collect(Collectors.joining(System.lineSeparator()))
    }

    private fun deriveTargetName(headers: Map, path: String): String {
        return if (headers.containsKey(TARGET_NAME.key())) headers[TARGET_NAME.key()]!! else destinationNameMappings.mapForPath(
            path
        )
    }

    private fun deriveSourceName(headers: Map, path: String): String {
        return if (headers.containsKey(HeaderKeys.SOURCE_NAME.key())) headers[HeaderKeys.SOURCE_NAME.key()]!! else sourceNameMappings.mapForPath(
            path
        )
    }

    companion object {
        private fun isMissingHeaders(requestHeaders: Map?): Boolean {
            return requestHeaders.isNullOrEmpty()
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy