Skip to content

Commit

Permalink
Upgrade to ktor 2.1.0 (#50)
Browse files Browse the repository at this point in the history
* Upgrade to ktor 2.1.0

* Updates after QA
  • Loading branch information
MikAoJk authored Aug 24, 2022
1 parent c496e8d commit f2c25cb
Show file tree
Hide file tree
Showing 8 changed files with 81 additions and 75 deletions.
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
FROM gcr.io/distroless/java17@sha256:51312565c020a77583a9c699eb4d92b99d9629f4109a333d49a7c4f7ed5f9f82

WORKDIR /app
COPY build/libs/pdfgen-1.5.0-all.jar app.jar
COPY build/libs/pdfgen-1.5.1-all.jar app.jar
COPY fonts fonts
COPY templates templates
COPY resources resources
Expand Down
7 changes: 6 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ In your own repository, create a Dockerfile with the following contents

```dockerfile
# Dockerfile
FROM ghcr.io/navikt/pdfgen:1.4.6
FROM ghcr.io/navikt/pdfgen:1.5.1

COPY templates /app/templates # handlebars templates
COPY fonts /app/fonts # fonts to be embedded
Expand Down Expand Up @@ -58,6 +58,11 @@ making this ideal for developing new templates for your application.

The template and data directory structure both follow the `<application>/<template>` structure.

### Upgrading the gradle wrapper
Find the newest version of gradle here: https://gradle.org/releases/ Then run this command:

```./gradlew wrapper --gradle-version $gradleVersjon```

## 👥 Contact

This project is currently maintained by the organisation [@navikt](https://github.com/navikt).
Expand Down
21 changes: 13 additions & 8 deletions build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

group = "no.nav.pdfgen"
version = "1.5.0"
version = "1.5.1"

val handlebarsVersion = "4.3.0"
val jacksonVersion = "2.13.2"
val jacksonVersion = "2.13.3"
val jaxbVersion = "3.0.2"
val jaxbApiVersion = "2.3.1"
val jsoupVersion = "1.14.3"
val kluentVersion = "1.68"
val ktorVersion = "1.6.8"
val ktorVersion = "2.1.0"
val logbackVersion = "1.2.11"
val logstashEncoderVersion = "7.0.1"
val logstashEncoderVersion = "7.2"
val openHtmlToPdfVersion = "1.0.10"
val prometheusVersion = "0.15.0"
val spekVersion = "2.0.17"
val prometheusVersion = "0.16.0"
val spekVersion = "2.0.18"
val verapdfVersion = "1.20.1"

plugins {
kotlin("jvm") version "1.6.10"
kotlin("jvm") version "1.7.10"
id("org.jmailen.kotlinter") version "3.9.0"
id("com.github.johnrengelman.shadow") version "6.0.0"
id("com.github.ben-manes.versions") version "0.42.0"
Expand Down Expand Up @@ -68,7 +68,12 @@ dependencies {
implementation("org.glassfish.jaxb:jaxb-runtime:$jaxbVersion")

implementation("io.ktor:ktor-server-netty:$ktorVersion")
implementation("io.ktor:ktor-jackson:$ktorVersion")
implementation("io.ktor:ktor-server-core:$ktorVersion")
implementation("io.ktor:ktor-serialization-jackson:$ktorVersion")
implementation("io.ktor:ktor-server-content-negotiation:$ktorVersion")
implementation("io.ktor:ktor-server-status-pages:$ktorVersion")


implementation("io.prometheus:simpleclient_common:$prometheusVersion")
implementation("io.prometheus:simpleclient_hotspot:$prometheusVersion")

Expand Down
62 changes: 26 additions & 36 deletions src/main/kotlin/no/nav/pdfgen/Bootstrap.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,28 +6,26 @@ package no.nav.pdfgen
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.module.kotlin.registerKotlinModule
import com.github.jknack.handlebars.Template
import com.openhtmltopdf.util.XRLog
import com.openhtmltopdf.slf4j.Slf4jLogger
import io.ktor.application.call
import io.ktor.application.feature
import io.ktor.application.install
import io.ktor.features.ContentNegotiation
import io.ktor.features.StatusPages
import com.openhtmltopdf.util.XRLog
import io.ktor.http.ContentType
import io.ktor.http.HttpStatusCode
import io.ktor.http.content.TextContent
import io.ktor.http.withCharset
import io.ktor.jackson.jackson
import io.ktor.request.path
import io.ktor.response.respond
import io.ktor.response.respondText
import io.ktor.response.respondTextWriter
import io.ktor.routing.*
import io.ktor.serialization.jackson.jackson
import io.ktor.server.application.call
import io.ktor.server.application.install
import io.ktor.server.engine.ApplicationEngine
import io.ktor.server.engine.embeddedServer
import io.ktor.server.netty.Netty
import io.ktor.utils.io.*
import io.ktor.utils.io.jvm.javaio.*
import io.ktor.server.plugins.contentnegotiation.ContentNegotiation
import io.ktor.server.plugins.statuspages.StatusPages
import io.ktor.server.request.path
import io.ktor.server.response.respond
import io.ktor.server.response.respondText
import io.ktor.server.response.respondTextWriter
import io.ktor.server.routing.get
import io.ktor.server.routing.routing
import io.prometheus.client.CollectorRegistry
import io.prometheus.client.exporter.common.TextFormat
import kotlinx.coroutines.CoroutineScope
Expand All @@ -38,9 +36,6 @@ import no.nav.pdfgen.template.loadTemplates
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.verapdf.pdfa.VeraGreenfieldFoundryProvider
import java.util.*
import java.util.logging.Level


val objectMapper: ObjectMapper = ObjectMapper()
.registerKotlinModule()
Expand All @@ -59,7 +54,7 @@ fun initializeApplication(port: Int): ApplicationEngine {
val templates = loadTemplates(env)
val collectorRegistry: CollectorRegistry = CollectorRegistry.defaultRegistry

XRLog.setLoggerImpl(Slf4jLogger());
XRLog.setLoggerImpl(Slf4jLogger())

return embeddedServer(
Netty, port,
Expand All @@ -72,29 +67,32 @@ fun initializeApplication(port: Int): ApplicationEngine {
}

install(StatusPages) {
status(HttpStatusCode.NotFound) {
status(HttpStatusCode.NotFound) { call, _ ->
call.respond(
TextContent(
messageFor404(templates, feature(Routing), call.request.path()),
messageFor404(templates, call.request.path()),
ContentType.Text.Plain.withCharset(Charsets.UTF_8),
it
HttpStatusCode.NotFound
)
)
}
}
routing {
get("/is_ready") {
get("/internal/is_ready") {
call.respondText("I'm ready")
}
get("/is_alive") {
get("/internal/is_alive") {
call.respondText("I'm alive")
}
get("/prometheus") {
get("/internal/prometheus") {
val names = call.request.queryParameters.getAll("name[]")?.toSet() ?: setOf()
call.respondTextWriter(ContentType.parse(TextFormat.CONTENT_TYPE_004)) {
CoroutineScope(Dispatchers.IO).launch {
runCatching {
TextFormat.write004(this@respondTextWriter, collectorRegistry.filteredMetricFamilySamples(names))
TextFormat.write004(
this@respondTextWriter,
collectorRegistry.filteredMetricFamilySamples(names)
)
}
}
}
Expand All @@ -104,15 +102,7 @@ fun initializeApplication(port: Int): ApplicationEngine {
}
}

private fun messageFor404(templates: Map<Pair<String, String>, Template>, routing: Routing, path: String) =
"Unkown path '$path'. Known paths:" + templates.map { (app, _) ->
val (applicationName, template) = app
apiRoutes(routing)
.map { it.replace("{applicationName}", applicationName) }.joinToString("\n") { it.replace("{template}", template) }
private fun messageFor404(templates: Map<Pair<String, String>, Template>, path: String) =
"Unkown path '$path'. Known templates:\n" + templates.map { (app, _) ->
"/api/v1/genpdf/%s/%s".format(app.first, app.second)
}.joinToString("\n")

private fun apiRoutes(routing: Routing) = allRoutes(routing).filter {
it.selector is HttpMethodRouteSelector && it.toString().startsWith("/api")
}.map { it.toString() }

private fun allRoutes(route: Route): List<Route> = listOf(route) + route.children.flatMap(::allRoutes)
15 changes: 11 additions & 4 deletions src/main/kotlin/no/nav/pdfgen/api/GeneratePdfApi.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,18 @@ import com.github.jknack.handlebars.Context
import com.github.jknack.handlebars.JsonNodeValueResolver
import com.github.jknack.handlebars.Template
import com.github.jknack.handlebars.context.MapValueResolver
import io.ktor.application.*
import io.ktor.http.*
import io.ktor.request.*
import io.ktor.response.*
import io.ktor.routing.*
import io.ktor.server.application.call
import io.ktor.server.request.contentType
import io.ktor.server.request.receive
import io.ktor.server.request.receiveText
import io.ktor.server.response.respond
import io.ktor.server.response.respondBytes
import io.ktor.server.response.respondText
import io.ktor.server.routing.Routing
import io.ktor.server.routing.get
import io.ktor.server.routing.post
import io.ktor.server.routing.route
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import net.logstash.logback.argument.StructuredArguments
Expand Down
7 changes: 2 additions & 5 deletions src/main/kotlin/no/nav/pdfgen/template/Helpers.kt
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,13 @@ import no.nav.pdfgen.domain.syfosoknader.PeriodeMapper
import java.time.LocalDate
import java.time.format.DateTimeFormatter
import java.time.temporal.ChronoUnit
import java.text.DecimalFormat
import java.text.DecimalFormatSymbols
import java.util.*

val dateFormat: DateTimeFormatter = DateTimeFormatter.ofPattern("dd.MM.yyyy")
val dateFormatLong: DateTimeFormatter = DateTimeFormatter.ofPattern("d. MMMM yyyy")
.withLocale(Locale("no", "NO"))
val datetimeFormat: DateTimeFormatter = DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm")


fun formatDate(formatter: DateTimeFormatter, context: CharSequence): String = try {
formatter.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME.parseBest(context))
} catch (e: Exception) {
Expand Down Expand Up @@ -151,7 +148,7 @@ fun registerNavHelpers(handlebars: Handlebars, env: Environment) {
registerHelper(
"capitalize",
Helper<String> { context, _ ->
context?.lowercase()?.replaceFirstChar{ it.uppercase() } ?: ""
context?.lowercase()?.replaceFirstChar { it.uppercase() } ?: ""
}
)

Expand Down Expand Up @@ -308,4 +305,4 @@ fun registerNavHelpers(handlebars: Handlebars, env: Environment) {
}

private fun String.capitalizeWords(wordSplitter: String) =
this.split(wordSplitter).joinToString(wordSplitter) { it.trim().replaceFirstChar{ it.uppercase() } }
this.split(wordSplitter).joinToString(wordSplitter) { it.trim().replaceFirstChar { it.uppercase() } }
41 changes: 22 additions & 19 deletions src/test/kotlin/no/nav/pdfgen/PdfGenITSpek.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,13 @@ package no.nav.pdfgen
import io.ktor.client.HttpClient
import io.ktor.client.engine.cio.CIO
import io.ktor.client.request.post
import io.ktor.client.request.preparePost
import io.ktor.client.request.setBody
import io.ktor.client.statement.*
import io.ktor.http.ContentType
import io.ktor.http.content.ByteArrayContent
import io.ktor.http.content.TextContent
import io.ktor.http.isSuccess
import io.ktor.util.KtorExperimentalAPI
import kotlinx.coroutines.*
import no.nav.pdfgen.template.loadTemplates
import org.amshove.kluent.*
Expand All @@ -24,7 +25,6 @@ import java.nio.file.Paths
import java.util.concurrent.Executors
import kotlin.io.use

@KtorExperimentalAPI
object PdfGenITSpek : Spek({
val applicationPort = getRandomPort()
val application = initializeApplication(applicationPort)
Expand All @@ -49,7 +49,7 @@ object PdfGenITSpek : Spek({

val response = runBlocking<HttpResponse> {
client.post("http://localhost:$applicationPort/api/v1/genpdf/$applicationName/$templateName") {
body = TextContent(json, contentType = ContentType.Application.Json)
setBody(TextContent(json, contentType = ContentType.Application.Json))
}
}
response.status.isSuccess() shouldBeEqualTo true
Expand All @@ -74,7 +74,7 @@ object PdfGenITSpek : Spek({

val response = runBlocking<HttpResponse> {
client.post("http://localhost:$applicationPort/api/v1/genpdf/$applicationName/$templateName") {
body = TextContent(json, contentType = ContentType.Application.Json)
setBody(TextContent(json, contentType = ContentType.Application.Json))
}
}

Expand All @@ -90,7 +90,7 @@ object PdfGenITSpek : Spek({
it("Should render a document using default HTML") {
val response = runBlocking<HttpResponse> {
client.post("http://localhost:$applicationPort/api/v1/genpdf/html/integration-test") {
body = testTemplateIncludedFonts
setBody(testTemplateIncludedFonts)
}
}
response.status.isSuccess() shouldBeEqualTo true
Expand Down Expand Up @@ -125,8 +125,8 @@ object PdfGenITSpek : Spek({
it("Should render a document using input image, $outputFile") {
runBlocking {
runBlocking<HttpStatement> {
client.post("http://localhost:$applicationPort/api/v1/genpdf/image/integration-test") {
body = payload
client.preparePost("http://localhost:$applicationPort/api/v1/genpdf/image/integration-test") {
setBody(payload)
}
}.execute { response ->
response.status.isSuccess().shouldBeTrue()
Expand All @@ -147,11 +147,11 @@ object PdfGenITSpek : Spek({
it("Should respond with helpful information") {
runBlocking {
runBlocking<HttpStatement> {
client.config { expectSuccess = false }.post("http://localhost:$applicationPort/whodis")
client.config { expectSuccess = false }.preparePost("http://localhost:$applicationPort/whodis")
}.execute { response ->
response.status.value shouldBeEqualTo 404
val text = runBlocking { response.readText() }
text shouldContain "Known paths:/api/v1/genpdf"
val text = runBlocking { response.bodyAsText() }
text shouldContain "Known templates:\n/api/v1/genpdf"
}
}
}
Expand All @@ -171,9 +171,10 @@ object PdfGenITSpek : Spek({
IOUtils.toByteArray(it).toString(Charsets.UTF_8)
}!!

val response = client.post<HttpResponse>("http://localhost:$applicationPort/api/v1/genpdf/$applicationName/$templateName") {
body = TextContent(json, contentType = ContentType.Application.Json)
}
val response =
client.preparePost("http://localhost:$applicationPort/api/v1/genpdf/$applicationName/$templateName") {
setBody(TextContent(json, contentType = ContentType.Application.Json))
}.execute()
response.readBytes() shouldNotBeEqualTo null
response.status.isSuccess() shouldBeEqualTo true
}
Expand All @@ -189,9 +190,10 @@ object PdfGenITSpek : Spek({
IOUtils.toByteArray(it).toString(Charsets.UTF_8)
} ?: "{}"

val response = client.post<HttpResponse>("http://localhost:$applicationPort/api/v1/genpdf/$applicationName/$templateName") {
body = TextContent(json, contentType = ContentType.Application.Json)
}
val response =
client.preparePost("http://localhost:$applicationPort/api/v1/genpdf/$applicationName/$templateName") {
setBody(TextContent(json, contentType = ContentType.Application.Json))
}.execute()
response.readBytes() shouldNotBeEqualTo null
response.status.isSuccess() shouldBeEqualTo true
}
Expand All @@ -208,9 +210,10 @@ object PdfGenITSpek : Spek({
IOUtils.toByteArray(it).toString(Charsets.UTF_8)
} ?: "{}"

val response = client.post<HttpResponse>("http://localhost:$applicationPort/api/v1/genpdf/$applicationName/$templateName") {
body = TextContent(json, contentType = ContentType.Application.Json)
}
val response =
client.preparePost("http://localhost:$applicationPort/api/v1/genpdf/$applicationName/$templateName") {
setBody(TextContent(json, contentType = ContentType.Application.Json))
}.execute()
response.readBytes() shouldNotBeEqualTo null
response.status.isSuccess() shouldBeEqualTo true
}
Expand Down
1 change: 0 additions & 1 deletion src/test/kotlin/no/nav/pdfgen/RenderingSpek.kt
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import org.verapdf.pdfa.flavours.PDFAFlavour
import org.verapdf.pdfa.results.TestAssertion
import java.io.ByteArrayInputStream

@KtorExperimentalAPI
object RenderingSpek : Spek({
val env = Environment()
val templates = loadTemplates(env)
Expand Down

0 comments on commit f2c25cb

Please sign in to comment.