Skip to content

Commit

Permalink
Merge branch 'main' of github.com:itcr-uni-luebeck/termite
Browse files Browse the repository at this point in the history
Resolve conflicts after merge
  • Loading branch information
pbehrend committed Jun 12, 2024
2 parents 4194218 + ad63c46 commit a7425c7
Show file tree
Hide file tree
Showing 16 changed files with 273 additions and 340 deletions.
8 changes: 4 additions & 4 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
# Build jar using Gradle
FROM gradle:7.2.0-jdk17-alpine AS gradle_build
COPY . /home/abide_validation/termite
WORKDIR /home/abide_validation/termite
COPY . /termite
WORKDIR /termite
# Create jar
RUN gradle clean build bootJar --no-daemon
RUN gradle clean build bootJar

# Copy jar to new image for running terminology service
FROM openjdk:17
COPY --from=gradle_build /home/abide_validation/termite/build/libs/termite.jar /app/termite.jar
COPY --from=gradle_build /termite/build/libs/termite.jar /app/termite.jar
COPY /config/application.properties /app/config/application.properties
COPY /config/log4j2.xml /app/config/log4j2.xml
COPY upload.sh /app/upload.sh
Expand Down
12 changes: 10 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ plugins {
id "org.jetbrains.kotlin.plugin.spring" version "2.0.0"
}

group 'org.example'
group 'de.itcr'
version '1.0-SNAPSHOT'

repositories {
Expand All @@ -25,9 +25,17 @@ compileJava {
targetCompatibility = "17"
}

sourceSets {
main {
java {
srcDir "src"
}
}
}

dependencies {
//Kotlin
implementation "org.jetbrains.kotlin:kotlin-stdlib"
implementation "org.jetbrains.kotlin:kotlin-stdlib:2.0.0"
implementation "org.jetbrains.kotlin:kotlin-reflect:2.0.0"

//Spring Boot
Expand Down
6 changes: 3 additions & 3 deletions docker/docker-compose.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
services:
termite:
# image: ghcr.io/itcr-uni-luebeck/termite:latest
image: termite
image: ghcr.io/itcr-uni-luebeck/termite:latest
ports:
- 9083:9083
environment:
Expand All @@ -20,13 +19,14 @@ services:
expose:
- 5432
environment:
- PGUSER=termite
- POSTGRES_USER=termite
- POSTGRES_PASSWORD=termite
- POSTGRES_DB=termite
volumes:
- postgres-data:/var/lib/postgresql/data
healthcheck:
test: [ "CMD-SHELL", "pg_isready", "-d", "termite" ]
test: [ "CMD-SHELL", "pg_isready", "-d", "termite", "-U", "${PGUSER}", "-q" ]
interval: 10s
timeout: 10s
retries: 5
Expand Down
69 changes: 53 additions & 16 deletions src/main/kotlin/de/itcr/termite/api/CodeSystemController.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package de.itcr.termite.api

import ca.uhn.fhir.context.FhirContext
import de.itcr.termite.api.ValueSetController.Companion
import de.itcr.termite.database.TerminologyStorage
import de.itcr.termite.exception.NotFoundException
import de.itcr.termite.metadata.annotation.*
Expand All @@ -18,15 +19,7 @@ import org.springframework.http.MediaType
import org.springframework.http.RequestEntity
import org.springframework.http.ResponseEntity
import org.springframework.stereotype.Controller
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PathVariable
import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.PutMapping
import org.springframework.web.bind.annotation.RequestBody
import org.springframework.web.bind.annotation.RequestHeader
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RequestParam
import org.springframework.web.bind.annotation.ResponseBody
import org.springframework.web.bind.annotation.*
import org.springframework.web.server.ResponseStatusException
import java.net.URI
import java.util.*
Expand All @@ -35,7 +28,7 @@ import java.util.*
type = "CodeSystem",
versioning = "no-version",
readHistory = false,
updateCreate = false,
updateCreate = true,
conditionalCreate = false,
conditionalRead = "not-supported",
conditionalUpdate = false,
Expand All @@ -48,10 +41,15 @@ import java.util.*
name = "url",
type = "uri",
documentation = "URL of the resource to locate"
),
SearchParameter(
name = "version",
type = "string",
documentation = "Version of the resource to locate"
)
]
)
@SupportsInteraction(["create", "search-type"])
@SupportsInteraction(["create", "search-type", "delete"])
@SupportsOperation(
name = "CodeSystem-lookup",
title = "CodeSystem-lookup",
Expand Down Expand Up @@ -180,7 +178,7 @@ class CodeSystemController(

@PutMapping(path = ["{id}"], consumes = ["application/json", "application/fhir+json", "application/xml", "application/fhir+xml", "application/fhir+ndjson", "application/ndjson"])
@ResponseBody
fun conditionalCreate(requestEntity: RequestEntity<String>, @RequestHeader("Content-Type") contentType: String, @PathVariable(name = "id") id: String): ResponseEntity<String> {
fun updateCreate(requestEntity: RequestEntity<String>, @RequestHeader("Content-Type") contentType: String, @PathVariable(name = "id") id: String): ResponseEntity<String> {
logger.info("Creating CodeSystem instance if not present")
try {
val cs = parseBodyAsResource(requestEntity, contentType)
Expand Down Expand Up @@ -353,19 +351,22 @@ class CodeSystemController(
}
}

@GetMapping(params = ["url"])
@GetMapping
@ResponseBody
fun search(@RequestParam url: String): ResponseEntity<String>{
fun search(
@RequestParam url: String,
@RequestParam(required = false) version: String?
): ResponseEntity<String>{
logger.info("Searching for code system [url = $url]")
try{
val csList = database.searchCodeSystem(url)
val csList = database.searchCodeSystem(url, version)
val bundle = Bundle()
bundle.id = UUID.randomUUID().toString()
bundle.type = Bundle.BundleType.SEARCHSET
bundle.total = csList.size
//Should be faster since otherwise an internal array list would have to resized all the time
bundle.entry = csList.map { cs -> Bundle.BundleEntryComponent().setResource(cs) }
logger.debug("Found ${csList.size} code systems for URL $url")
logger.debug("Found ${csList.size} CodeSystem instances for URL $url" + if (version != null) " and version $version" else "")
return ResponseEntity.ok().contentType(MediaType.APPLICATION_JSON).body(jsonParser.encodeResourceToString(bundle))
}
catch (e: Exception){
Expand All @@ -384,4 +385,40 @@ class CodeSystemController(
}
}

@DeleteMapping("{id}")
@ResponseBody
fun delete(@PathVariable id: String): ResponseEntity<String> {
logger.info("Deleting CodeSystem instance [id = $id]")
try {
var opOutcome: String
try {
database.deleteCodeSystem(id)
opOutcome = generateOperationOutcomeString(
OperationOutcome.IssueSeverity.INFORMATION,
OperationOutcome.IssueType.INFORMATIONAL,
"Successfully deleted CodeSystem instance [ID = $id]",
jsonParser
)
}
catch (e: NotFoundException) {
opOutcome = generateOperationOutcomeString(
OperationOutcome.IssueSeverity.INFORMATION,
OperationOutcome.IssueType.INFORMATIONAL,
"No CodeSystem instance with such an ID [ID = $id]",
jsonParser
)
}
return ResponseEntity.ok().eTag("W/\"0\"").contentType(MediaType.APPLICATION_JSON).body(opOutcome)
}
catch (e: Exception) {
val opOutcome = generateOperationOutcomeString(
OperationOutcome.IssueSeverity.ERROR,
OperationOutcome.IssueType.PROCESSING,
e.message,
jsonParser
)
return ResponseEntity.internalServerError().contentType(MediaType.APPLICATION_JSON).body(opOutcome)
}
}

}
11 changes: 8 additions & 3 deletions src/main/kotlin/de/itcr/termite/api/ResourceController.kt
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,17 @@ abstract class ResourceController(protected val database: TerminologyStorage, pr
val ndjson = fhirContext.newNDJsonParser() to "ndjson"
this.parsers = mapOf(
"application/json" to json,
"application/json;charset=utf-8" to json,
"application/fhir+json" to json,
"application/fhir+json; charset=UTF-8" to json,
"application/fhir+json;charset=utf-8" to json,
"application/xml" to xml,
"application/xml;charset=utf-8" to xml,
"application/fhir+xml" to xml,
"application/fhir+xml;charset=utf-8" to xml,
"application/ndjson" to ndjson,
"application/fhir+ndjson" to ndjson
"application/ndjson;charset=utf-8" to ndjson,
"application/fhir+ndjson" to ndjson,
"application/fhir+ndjson;charset=utf-8" to ndjson
)
}

Expand All @@ -36,7 +41,7 @@ abstract class ResourceController(protected val database: TerminologyStorage, pr
*/
protected fun parseBodyAsResource(requestEntity: RequestEntity<String>, contentType: String): IBaseResource {
try{
val (parser, parserFormat) = parsers[contentType] ?: throw Exception("Unsupported content type: $contentType")
val (parser, parserFormat) = parsers[contentType.trim().lowercase().replace(" ", "")] ?: throw Exception("Unsupported content type: $contentType")
try {
return parser.parseResource(requestEntity.body)
} catch (e: DataFormatException) {
Expand Down
47 changes: 44 additions & 3 deletions src/main/kotlin/de/itcr/termite/api/ValueSetController.kt
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ import kotlin.math.min
type = "ValueSet",
versioning = "no-version",
readHistory = false,
updateCreate = false,
updateCreate = true,
conditionalCreate = false,
conditionalRead = "not-supported",
conditionalUpdate = false,
Expand All @@ -48,10 +48,15 @@ import kotlin.math.min
name = "url",
type = "uri",
documentation = "URL of the resource to locate"
),
SearchParameter(
name = "version",
type = "string",
documentation = "Version of the resource to locate"
)
]
)
@SupportsInteraction(["create", "search-type"])
@SupportsInteraction(["create", "search-type", "delete"])
@SupportsOperation(
name = "ValueSet-lookup",
title = "ValueSet-lookup",
Expand Down Expand Up @@ -217,7 +222,7 @@ class ValueSetController(

@PutMapping(path = ["{id}"], consumes = ["application/json", "application/fhir+json", "application/xml", "application/fhir+xml", "application/fhir+ndjson", "application/ndjson"])
@ResponseBody
fun conditionalCreate(requestEntity: RequestEntity<String>, @RequestHeader("Content-Type") contentType: String, @PathVariable(name = "id") id: String): ResponseEntity<String> {
fun updateCreate(requestEntity: RequestEntity<String>, @RequestHeader("Content-Type") contentType: String, @PathVariable(name = "id") id: String): ResponseEntity<String> {
logger.info("Creating ValueSet instance if not present")
try {
val vs = parseBodyAsResource(requestEntity, contentType)
Expand Down Expand Up @@ -353,6 +358,42 @@ class ValueSetController(
}
}

@DeleteMapping("{id}")
@ResponseBody
fun delete(@PathVariable id: String): ResponseEntity<String> {
logger.info("Deleting ValueSet instance [id = $id]")
try {
var opOutcome: String
try {
database.deleteValueSet(id)
opOutcome = generateOperationOutcomeString(
OperationOutcome.IssueSeverity.INFORMATION,
OperationOutcome.IssueType.INFORMATIONAL,
"Successfully deleted ValueSet instance [ID = $id]",
jsonParser
)
}
catch (e: NotFoundException) {
opOutcome = generateOperationOutcomeString(
OperationOutcome.IssueSeverity.INFORMATION,
OperationOutcome.IssueType.INFORMATIONAL,
"No ValueSet instance with such an ID [ID = $id]",
jsonParser
)
}
return ResponseEntity.ok().eTag("W/\"0\"").contentType(MediaType.APPLICATION_JSON).body(opOutcome)
}
catch (e: Exception) {
val opOutcome = generateOperationOutcomeString(
OperationOutcome.IssueSeverity.ERROR,
OperationOutcome.IssueType.PROCESSING,
e.message,
jsonParser
)
return ResponseEntity.internalServerError().contentType(MediaType.APPLICATION_JSON).body(opOutcome)
}
}

/**
* Validates a code with respect to the given value set
* @see <a href="http://www.hl7.org/FHIR/valueset-operation-validate-code.html">validate-code operation</a>
Expand Down
10 changes: 8 additions & 2 deletions src/main/kotlin/de/itcr/termite/database/TerminologyStorage.kt
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,12 @@ interface TerminologyStorage {

fun readConceptMap(id: String): ConceptMap

fun deleteValueSet(id: String)

fun deleteCodeSystem(id: String)

fun deleteConceptMap(id: String)

/**
* Validates if the given code is in the given value set
*
Expand All @@ -55,9 +61,9 @@ interface TerminologyStorage {
*/
fun searchValueSet(url: String, version: String?): List<ValueSet>

fun searchCodeSystem(url: String): List<CodeSystem>
fun searchCodeSystem(url: String, version: String?): List<CodeSystem>

fun searchConceptMap(url: String): List<ConceptMap>
fun searchConceptMap(url: String, version: String?): List<ConceptMap>

fun validateCodeCS(code: String, display: String?, url: String): Boolean

Expand Down
Loading

0 comments on commit a7425c7

Please sign in to comment.