Skip to content

Commit ee66189

Browse files
authored
fix: Read resources from classpath (#2)
* fix: Read resources from classpath * Legg til dokumentasjon * Legg til api for å opprette PDF direkte fra json og template
1 parent 256628a commit ee66189

File tree

8 files changed

+80
-35
lines changed

8 files changed

+80
-35
lines changed

README.md

+32
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,38 @@ Most commonly, pdfgen-core is used with templates, fonts, additional resources,
1717
Check GitHub releases to find the latest `release` version
1818
Check [Github releases](https://github.com/navikt/pdfgen-core/releases) to find the latest `release` version
1919

20+
In your own repository create subfolders in `templates` and `data`
21+
```bash
22+
mkdir {templates,data}/directory_name # directory_name can be anything, but it'll be a necessary part of the API later
23+
````
24+
* `templates/directory_name/` should then be populated with your .hbs-templates. the names of these templates will also decide parts of the API paths
25+
* `data/directory_name/` should be populated with json files with names corresponding to a target .hbs-template, this can be used to test your PDFs during development of templates.
26+
27+
Additionally create subfolder `resources` containing additional resources which can be referred in your .hbs-templates
28+
29+
30+
### Example usage
31+
#### Generating HTML from predefined JSON data in data-folder
32+
```kotlin
33+
34+
val html: String = createHtmlFromTemplateData(template, directoryName)
35+
```
36+
37+
#### Generating PDF from predefined JSON data in data-folder
38+
```kotlin
39+
val html: String = createHtmlFromTemplateData(template, directoryName)
40+
val pdfBytes: ByteArray = createPDFA(html)
41+
```
42+
43+
#### Generating from JSON input data
44+
```kotlin
45+
val html: String = createHtmlFromTemplateData(template, directoryName, jsonNode)
46+
val pdfBytes: ByteArray = createPDFA(html)
47+
48+
// Or directly
49+
val pdfBytes: ByteArray = createPDFA(template, directoryName, jsonNode)
50+
```
51+
2052
## Developing pdfgen-core
2153

2254
### Build and run tests

build.gradle.kts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
group = "no.nav.pdfgen"
2-
version = properties["version"]?.takeIf { it is String && it.isNotEmpty() } ?: "local-build"
2+
version = properties["version"]?.takeIf { it is String && it.isNotEmpty() && it != "unspecified" } ?: "local-build"
33
println(version)
44

55
val handlebarsVersion = "4.3.1"

src/main/kotlin/no/nav/pdfgen/core/Environment.kt

+30-17
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,23 @@ package no.nav.pdfgen.core
22

33
import com.fasterxml.jackson.databind.ObjectMapper
44
import com.fasterxml.jackson.module.kotlin.readValue
5+
import io.github.oshai.kotlinlogging.KotlinLogging
6+
import no.nav.pdfgen.core.util.FontMetadata
7+
import org.apache.pdfbox.io.IOUtils
8+
import java.io.File
59
import java.nio.file.Files
610
import java.nio.file.Path
711
import java.nio.file.Paths
8-
import java.util.*
12+
import java.util.Base64
913
import kotlin.io.path.exists
1014
import kotlin.io.path.extension
11-
import no.nav.pdfgen.core.util.FontMetadata
12-
import org.apache.pdfbox.io.IOUtils
13-
15+
import kotlin.io.path.pathString
16+
import kotlin.io.path.readBytes
17+
private val log = KotlinLogging.logger {}
1418
val objectMapper: ObjectMapper = ObjectMapper().findAndRegisterModules()
15-
val templateRoot: Path = getFromEnvOrDefault("TEMPLATES_PATH", "templates/")
16-
val imagesRoot: Path = getFromEnvOrDefault("RESOURCES_PATH", "resources/")
17-
val fontsRoot: Path = getFromEnvOrDefault("FONTS_PATH", "fonts/")
19+
val templateRoot: PDFGenResource = PDFGenResource("TEMPLATES_PATH", "templates/")
20+
val imagesRoot: PDFGenResource = PDFGenResource("RESOURCES_PATH", "resources/")
21+
val fontsRoot: PDFGenResource = PDFGenResource("FONTS_PATH", "fonts/")
1822

1923
class PDFgen {
2024
companion object {
@@ -34,7 +38,7 @@ data class Environment(
3438
val colorProfile: ByteArray =
3539
IOUtils.toByteArray(Environment::class.java.getResourceAsStream("/sRGB2014.icc")),
3640
val fonts: List<FontMetadata> =
37-
objectMapper.readValue(Files.newInputStream(fontsRoot.resolve("config.json"))),
41+
objectMapper.readValue(fontsRoot.readAllBytes("config.json")),
3842
val disablePdfGet: Boolean = System.getenv("DISABLE_PDF_GET")?.let { it == "true" } ?: false,
3943
val enableHtmlEndpoint: Boolean =
4044
System.getenv("ENABLE_HTML_ENDPOINT")?.let { it == "true" } ?: false,
@@ -53,17 +57,26 @@ data class Environment(
5357
}
5458
}
5559

56-
private fun getFromEnvOrDefault(envVariableName: String, defaultPath: String): Path {
57-
return System.getenv(envVariableName)?.let { Paths.get(it) }
58-
?: run {
59-
val fromDefaultPath = Paths.get(defaultPath)
60-
return if (fromDefaultPath.exists()) fromDefaultPath
61-
else Paths.get(ClassLoader.getSystemResource(defaultPath).file.toString())
62-
}
60+
data class PDFGenResource(val envVariableName: String, val defaultPath: String){
61+
62+
private val _path: Path = System.getenv(envVariableName)?.let { Paths.get(it) }
63+
?: Paths.get(defaultPath)
64+
fun readAllBytes(filename: String? = null): ByteArray {
65+
val filePath = filename?.let { _path.resolve(it) } ?: _path
66+
return if (filePath.exists()) filePath.readBytes() else Environment::class.java.classLoader.getResourceAsStream(filePath.pathString)!!.readAllBytes()
67+
}
68+
69+
fun toFile(filename: String? = null): File = getPath(filename).toFile()
70+
71+
fun getPath(filename: String? = null): Path {
72+
val filePath = filename?.let { _path.resolve(it) } ?: _path
73+
log.debug { "Reading file from path $filePath. File exists on path = ${filePath.exists()}" }
74+
return if (filePath.exists()) filePath else Path.of(Environment::class.java.classLoader.getResource(filePath.pathString)!!.toURI())
75+
}
6376
}
6477

6578
private fun loadImages() =
66-
Files.list(imagesRoot)
79+
Files.list(imagesRoot.getPath())
6780
.filter {
6881
val validExtensions = setOf("jpg", "jpeg", "png", "bmp", "svg")
6982
!Files.isHidden(it) && it.fileName.extension in validExtensions
@@ -84,7 +97,7 @@ private fun loadImages() =
8497
.toMap()
8598

8699
private fun loadResources() =
87-
Files.list(imagesRoot)
100+
Files.list(imagesRoot.getPath())
88101
.filter {
89102
val validExtensions = setOf("svg")
90103
!Files.isHidden(it) && it.fileName.extension in validExtensions

src/main/kotlin/no/nav/pdfgen/core/MetricRegistry.kt

+3-7
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,13 @@ import io.prometheus.client.Summary
44

55
val HANDLEBARS_RENDERING_SUMMARY: Summary =
66
Summary.Builder()
7-
.name("handlebars_rendering")
7+
.name("pdfgen_core_handlebars_rendering")
88
.help("Time it takes for handlebars to render the template")
99
.register()
1010
val OPENHTMLTOPDF_RENDERING_SUMMARY: Summary =
1111
Summary.Builder()
12-
.name("openhtmltopdf_rendering_summary")
12+
.name("pdfgen_core_openhtmltopdf_rendering_summary")
1313
.help("Time it takes to render a PDF")
1414
.labelNames("application_name", "template_type")
1515
.register()
16-
val JSOUP_PARSE_SUMMARY: Summary =
17-
Summary.Builder()
18-
.name("jsoup_parse")
19-
.help("Time it takes jsoup to parse the template")
20-
.register()
16+

src/main/kotlin/no/nav/pdfgen/core/pdf/CreateHtml.kt

+7-7
Original file line numberDiff line numberDiff line change
@@ -14,21 +14,21 @@ import no.nav.pdfgen.core.template.loadTemplates
1414

1515
private val log = KotlinLogging.logger {}
1616

17-
fun createHtml(template: String, applicationName: String, jsonPayload: JsonNode): String? {
17+
fun createHtml(template: String, directoryName: String, jsonPayload: JsonNode): String? {
1818
log.debug { "${"JSON: {}"} ${objectMapper.writeValueAsString(jsonPayload)}" }
19-
return render(applicationName, template, jsonPayload)
19+
return render(directoryName, template, jsonPayload)
2020
}
2121

22-
fun createHtmlFromTemplateData(template: String, applicationName: String): String? {
23-
val jsonNode = hotTemplateData(applicationName, template)
22+
fun createHtmlFromTemplateData(template: String, directoryName: String): String? {
23+
val jsonNode = hotTemplateData(directoryName, template)
2424
log.debug { "${"JSON: {}"} ${objectMapper.writeValueAsString(jsonNode)}" }
25-
return render(applicationName, template, jsonNode)
25+
return render(directoryName, template, jsonNode)
2626
}
2727

28-
private fun render(applicationName: String, template: String, jsonNode: JsonNode): String? {
28+
private fun render(directoryName: String, template: String, jsonNode: JsonNode): String? {
2929
return HANDLEBARS_RENDERING_SUMMARY.startTimer()
3030
.use {
31-
loadTemplates()[applicationName to template]?.apply(
31+
loadTemplates()[directoryName to template]?.apply(
3232
Context.newBuilder(jsonNode)
3333
.resolver(
3434
JsonNodeValueResolver.INSTANCE,

src/main/kotlin/no/nav/pdfgen/core/pdf/Create.kt src/main/kotlin/no/nav/pdfgen/core/pdf/CreatePdf.kt

+5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package no.nav.pdfgen.core.pdf
22

3+
import com.fasterxml.jackson.databind.JsonNode
34
import com.openhtmltopdf.pdfboxout.PdfRendererBuilder
45
import com.openhtmltopdf.svgsupport.BatikSVGDrawer
56
import io.github.oshai.kotlinlogging.KotlinLogging
@@ -32,6 +33,10 @@ import org.verapdf.pdfa.results.TestAssertion
3233

3334
private val log = KotlinLogging.logger {}
3435

36+
fun createPDFA(template: String, directoryName: String, jsonPayload: JsonNode? = null): ByteArray? {
37+
val html = jsonPayload?.let { createHtml(template, directoryName, it) } ?: createHtmlFromTemplateData(template, directoryName)
38+
return html?.let { createPDFA(it) }
39+
}
3540
fun createPDFA(html: String): ByteArray {
3641
val pdf =
3742
ByteArrayOutputStream()

src/main/kotlin/no/nav/pdfgen/core/template/Templates.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ fun setupHandlebars() =
1717
}
1818

1919
fun loadTemplates(): TemplateMap =
20-
Files.list(templateRoot)
20+
Files.list(templateRoot.getPath())
2121
.filter { !Files.isHidden(it) && Files.isDirectory(it) }
2222
.map {
2323
it.fileName.toString() to Files.list(it).filter { b -> b.fileName.extension == "hbs" }
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package no.nav.pdfgen.core.util
22

33
import com.openhtmltopdf.outputdevice.helper.BaseRendererBuilder
4-
import java.nio.file.Files
54
import no.nav.pdfgen.core.fontsRoot
65

76
data class FontMetadata(
@@ -11,5 +10,5 @@ data class FontMetadata(
1110
val style: BaseRendererBuilder.FontStyle,
1211
val subset: Boolean,
1312
) {
14-
val bytes: ByteArray = Files.readAllBytes(fontsRoot.resolve(path))
13+
val bytes: ByteArray = fontsRoot.readAllBytes(path)
1514
}

0 commit comments

Comments
 (0)