diff --git a/app/src/main/java/com/bartlomiejpluta/ttsserver/core/web/exception/UriTemplateException.kt b/app/src/main/java/com/bartlomiejpluta/ttsserver/core/web/exception/UriTemplateException.kt new file mode 100644 index 0000000..8b8aa60 --- /dev/null +++ b/app/src/main/java/com/bartlomiejpluta/ttsserver/core/web/exception/UriTemplateException.kt @@ -0,0 +1,3 @@ +package com.bartlomiejpluta.ttsserver.core.web.exception + +class UriTemplateException(message: String, val position: Int) : Exception(message) \ No newline at end of file diff --git a/app/src/main/java/com/bartlomiejpluta/ttsserver/core/web/uri/UriTemplate.kt b/app/src/main/java/com/bartlomiejpluta/ttsserver/core/web/uri/UriTemplate.kt new file mode 100644 index 0000000..074d907 --- /dev/null +++ b/app/src/main/java/com/bartlomiejpluta/ttsserver/core/web/uri/UriTemplate.kt @@ -0,0 +1,72 @@ +package com.bartlomiejpluta.ttsserver.core.web.uri + +import com.bartlomiejpluta.ttsserver.core.web.exception.UriTemplateException +import java.util.regex.Pattern + +class UriTemplate private constructor(uri: String) { + private val variables = mutableListOf() + private var pattern: Pattern + + init { + val patternBuilder = StringBuilder() + var variableBuilder: StringBuilder? = null + var isVariable = false + + uri.forEachIndexed { index, char -> + when { + char == '{' -> { + if (isVariable) { + error("Templates cannot be nested", index + 1) + } + isVariable = true + variableBuilder = StringBuilder() + patternBuilder.append("(\\w+)") + } + + char == '}' -> { + isVariable = false + variables.add(variableBuilder.toString()) + } + + isVariable -> char.takeIf { it.isLetter() } ?: error( + "Only letters are allowed as template", + index + 1 + ).let { variableBuilder?.append(it) } + + else -> patternBuilder.append(char) + } + } + + if (isVariable) { + error("Unclosed template found", patternBuilder.length) + } + + pattern = Pattern.compile("^${patternBuilder.toString()}\$") + } + + private fun error(message: String, position: Int): Unit = + throw UriTemplateException(message, position) + + + fun match(url: String): MatchingResult { + val matcher = pattern.matcher(url) + + if (matcher.find()) { + val matchedVariables = IntRange(0, matcher.groupCount() - 1) + .map { variables[it] to matcher.group(it + 1)!! } + .toMap() + + return MatchingResult(true, matchedVariables) + } + + return MatchingResult(false) + } + + data class MatchingResult(val matched: Boolean, val variables: Map = emptyMap()) + + companion object { + fun parse(uriTemplate: String): UriTemplate { + return UriTemplate(uriTemplate) + } + } +} \ No newline at end of file