Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
143 changes: 141 additions & 2 deletions Fhir Operations.postman_collection.json
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
{
"info": {
"_postman_id": "93839e15-42f8-48d7-9487-733f99d42f16",
"_postman_id": "438a5820-f866-436b-8d77-21ced8d026c8",
"name": "Fhir Operations",
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json",
"_exporter_id": "24615511"
"_exporter_id": "14557818"
},
"item": [
{
Expand Down Expand Up @@ -359,6 +359,145 @@
},
"response": []
},
{
"name": "Questionnaire-Simple",
"protocolProfileBehavior": {
"disabledSystemHeaders": {}
},
"request": {
"method": "PUT",
"header": [
{
"key": "Content-Type",
"value": "multipart/form-data",
"type": "text",
"disabled": true
},
{
"key": "charset",
"value": "UTF-8",
"type": "text",
"disabled": true
}
],
"body": {
"mode": "raw",
"raw": "{\r\n \"resourceType\": \"Questionnaire\",\r\n \"id\": \"client-registration-sample\",\r\n \"meta\": {\r\n \"versionId\": \"1\",\r\n \"lastUpdated\": \"2024-04-30T18:11:56.539+05:30\",\r\n \"source\": \"#Vqdr1Oe8Js5cFtLk\"\r\n },\r\n \"extension\": [\r\n {\r\n \"url\": \"http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-targetStructureMap\",\r\n \"valueCanonical\": \"https://fhir.labs.smartregister.org/StructureMap/PatientRegistration\"\r\n }\r\n ],\r\n \"status\": \"active\",\r\n \"subjectType\": [\r\n \"Patient\"\r\n ],\r\n \"date\": \"2020-11-18T07:24:47.111Z\",\r\n \"item\": [\r\n {\r\n \"linkId\": \"PR\",\r\n \"type\": \"group\",\r\n \"item\": [\r\n {\r\n \"linkId\": \"patient-0-birth-date\",\r\n \"text\": \"Date of Birth\",\r\n \"type\": \"date\"\r\n }\r\n ]\r\n }\r\n ]\r\n}",
"options": {
"raw": {
"language": "json"
}
}
},
"url": {
"raw": "http://localhost:8080/fhir/Questionnaire/client-registration-sample",
"protocol": "http",
"host": [
"localhost"
],
"port": "8080",
"path": [
"fhir",
"Questionnaire",
"client-registration-sample"
]
}
},
"response": []
},
{
"name": "StructureMap-Simple",
"protocolProfileBehavior": {
"disabledSystemHeaders": {}
},
"request": {
"method": "PUT",
"header": [
{
"key": "Content-Type",
"value": "multipart/form-data",
"type": "text",
"disabled": true
},
{
"key": "charset",
"value": "UTF-8",
"type": "text",
"disabled": true
}
],
"body": {
"mode": "raw",
"raw": "{\r\n \"resourceType\": \"StructureMap\",\r\n \"id\": \"PatientRegistration\",\r\n \"meta\": {\r\n \"versionId\": \"1\",\r\n \"lastUpdated\": \"2024-04-30T18:11:59.744+05:30\",\r\n \"source\": \"#rBggDJDCECBpeIsd\"\r\n },\r\n \"text\": {\r\n \"status\": \"additional\",\r\n \"div\": \"<div xmlns=\\\"http://www.w3.org/1999/xhtml\\\"><pre>map &quot;http://hl7.org/fhir/StructureMap/PatientRegistration&quot; = 'PatientRegistration'\\n\\n uses &quot;http://hl7.org/fhir/StructureDefinition/QuestionnaireReponse&quot; as source\\n uses &quot;http://hl7.org/fhir/StructureDefinition/Bundle&quot; as target\\n \\n group PatientRegistration(source src : QuestionnaireResponse, target bundle: Bundle) {\\n src -&gt; bundle.id = uuid() &quot;rule_c&quot;;\\n src -&gt; bundle.type = 'collection' &quot;rule_b&quot;;\\n src -&gt; bundle.entry as entry, entry.resource = create('Patient') as patient then\\n ExtractPatient(src, patient) &quot;rule_z&quot;;\\n }\\n \\n group ExtractPatient(source src : QuestionnaireResponse, target tgt : Patient) {\\n src.item as item where(linkId = 'PR') then {\\n item.item as inner_item where (linkId = 'patient-0-birth-date') then {\\n inner_item.answer first as ans then { \\n ans.value as val -&gt; tgt.birthDate = val &quot;rule_a&quot;;\\n } ;\\n } ;\\n };\\n }</pre></div>\"\r\n },\r\n \"url\": \"http://hl7.org/fhir/StructureMap/PatientRegistration\",\r\n \"name\": \"PatientRegistration\",\r\n \"structure\": [\r\n {\r\n \"url\": \"http://hl7.org/fhir/StructureDefinition/QuestionnaireReponse\",\r\n \"mode\": \"source\"\r\n },\r\n {\r\n \"url\": \"http://hl7.org/fhir/StructureDefinition/Bundle\",\r\n \"mode\": \"target\"\r\n }\r\n ],\r\n \"group\": [\r\n {\r\n \"name\": \"PatientRegistration\",\r\n \"typeMode\": \"none\",\r\n \"input\": [\r\n {\r\n \"name\": \"src\",\r\n \"type\": \"QuestionnaireResponse\",\r\n \"mode\": \"source\"\r\n },\r\n {\r\n \"name\": \"bundle\",\r\n \"type\": \"Bundle\",\r\n \"mode\": \"target\"\r\n }\r\n ],\r\n \"rule\": [\r\n {\r\n \"name\": \"rule_c\",\r\n \"source\": [\r\n {\r\n \"context\": \"src\"\r\n }\r\n ],\r\n \"target\": [\r\n {\r\n \"context\": \"bundle\",\r\n \"contextType\": \"variable\",\r\n \"element\": \"id\",\r\n \"transform\": \"uuid\"\r\n }\r\n ]\r\n },\r\n {\r\n \"name\": \"rule_b\",\r\n \"source\": [\r\n {\r\n \"context\": \"src\"\r\n }\r\n ],\r\n \"target\": [\r\n {\r\n \"context\": \"bundle\",\r\n \"contextType\": \"variable\",\r\n \"element\": \"type\",\r\n \"transform\": \"copy\",\r\n \"parameter\": [\r\n {\r\n \"valueString\": \"collection\"\r\n }\r\n ]\r\n }\r\n ]\r\n },\r\n {\r\n \"name\": \"rule_z\",\r\n \"source\": [\r\n {\r\n \"context\": \"src\"\r\n }\r\n ],\r\n \"target\": [\r\n {\r\n \"context\": \"bundle\",\r\n \"contextType\": \"variable\",\r\n \"element\": \"entry\",\r\n \"variable\": \"entry\"\r\n },\r\n {\r\n \"context\": \"entry\",\r\n \"contextType\": \"variable\",\r\n \"element\": \"resource\",\r\n \"variable\": \"patient\",\r\n \"transform\": \"create\",\r\n \"parameter\": [\r\n {\r\n \"valueString\": \"Patient\"\r\n }\r\n ]\r\n }\r\n ],\r\n \"dependent\": [\r\n {\r\n \"name\": \"ExtractPatient\",\r\n \"variable\": [\r\n \"src\",\r\n \"patient\"\r\n ]\r\n }\r\n ]\r\n }\r\n ]\r\n },\r\n {\r\n \"name\": \"ExtractPatient\",\r\n \"typeMode\": \"none\",\r\n \"input\": [\r\n {\r\n \"name\": \"src\",\r\n \"type\": \"QuestionnaireResponse\",\r\n \"mode\": \"source\"\r\n },\r\n {\r\n \"name\": \"tgt\",\r\n \"type\": \"Patient\",\r\n \"mode\": \"target\"\r\n }\r\n ],\r\n \"rule\": [\r\n {\r\n \"name\": \"item\",\r\n \"source\": [\r\n {\r\n \"context\": \"src\",\r\n \"element\": \"item\",\r\n \"variable\": \"item\",\r\n \"condition\": \"(linkId = 'PR')\"\r\n }\r\n ],\r\n \"rule\": [\r\n {\r\n \"name\": \"item\",\r\n \"source\": [\r\n {\r\n \"context\": \"item\",\r\n \"element\": \"item\",\r\n \"variable\": \"inner_item\",\r\n \"condition\": \"(linkId = 'patient-0-birth-date')\"\r\n }\r\n ],\r\n \"rule\": [\r\n {\r\n \"name\": \"answer\",\r\n \"source\": [\r\n {\r\n \"context\": \"inner_item\",\r\n \"element\": \"answer\",\r\n \"listMode\": \"first\",\r\n \"variable\": \"ans\"\r\n }\r\n ],\r\n \"rule\": [\r\n {\r\n \"name\": \"rule_a\",\r\n \"source\": [\r\n {\r\n \"context\": \"ans\",\r\n \"element\": \"value\",\r\n \"variable\": \"val\"\r\n }\r\n ],\r\n \"target\": [\r\n {\r\n \"context\": \"tgt\",\r\n \"contextType\": \"variable\",\r\n \"element\": \"birthDate\",\r\n \"transform\": \"copy\",\r\n \"parameter\": [\r\n {\r\n \"valueId\": \"val\"\r\n }\r\n ]\r\n }\r\n ]\r\n }\r\n ]\r\n }\r\n ]\r\n }\r\n ]\r\n }\r\n ]\r\n }\r\n ]\r\n}",
"options": {
"raw": {
"language": "json"
}
}
},
"url": {
"raw": "http://localhost:8080/fhir/StructureMap/PatientRegistration",
"protocol": "http",
"host": [
"localhost"
],
"port": "8080",
"path": [
"fhir",
"StructureMap",
"PatientRegistration"
]
}
},
"response": []
},
{
"name": "$Extract-Simple",
"protocolProfileBehavior": {
"disabledSystemHeaders": {}
},
"request": {
"method": "POST",
"header": [
{
"key": "Content-Type",
"value": "multipart/form-data",
"type": "text",
"disabled": true
},
{
"key": "charset",
"value": "UTF-8",
"type": "text",
"disabled": true
}
],
"body": {
"mode": "raw",
"raw": "{\r\n \"resourceType\": \"QuestionnaireResponse\",\r\n \"questionnaire\": \"client-registration-sample\",\r\n \"item\": [\r\n {\r\n \"linkId\": \"PR\",\r\n \"item\": [\r\n {\r\n \"linkId\": \"patient-0-birth-date\",\r\n \"answer\": [\r\n {\r\n \"valueDate\": \"2016-02-11\"\r\n }\r\n ]\r\n }\r\n ]\r\n }\r\n ]\r\n}",
"options": {
"raw": {
"language": "json"
}
}
},
"url": {
"raw": "http://localhost:8080/fhir/QuestionnaireResponse/client-registration-sample/$extract",
"protocol": "http",
"host": [
"localhost"
],
"port": "8080",
"path": [
"fhir",
"QuestionnaireResponse",
"client-registration-sample",
"$extract"
]
}
},
"response": []
},
{
"name": "Library",
"protocolProfileBehavior": {
Expand Down
2 changes: 1 addition & 1 deletion configs/hapi_application.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ hapi:
implementationguides:
# ### example from registry (packages.fhir.org)
smart:
packageUrl: https://worldhealthorganization.github.io/smart-immunizations-measles/package.tgz
packageUrl: https://worldhealthorganization.github.io/smart-immunizations-measles/branches/testing/package.tgz
name: smart.who.int.immunizations-measles
version: 0.1.0
reloadExisting: false
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,22 @@
package ca.uhn.fhir.jpa.starter.customOperations.r4

import ca.uhn.fhir.context.FhirContext
import ca.uhn.fhir.jpa.starter.AppProperties
import ca.uhn.fhir.jpa.starter.customOperations.r4.r4mapping.R4StructureMapExtractionContext
import ca.uhn.fhir.jpa.starter.customOperations.r4.r4mapping.targetStructureMap
import ca.uhn.fhir.jpa.starter.customOperations.services.HelperService
import ca.uhn.fhir.rest.annotation.IdParam
import ca.uhn.fhir.rest.annotation.Operation
import ca.uhn.fhir.rest.annotation.OperationParam
import ca.uhn.fhir.rest.client.api.IGenericClient
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException
import kotlinx.coroutines.runBlocking
import org.hl7.fhir.r4.model.QuestionnaireResponse
import org.hl7.fhir.r4.model.Questionnaire
import org.hl7.fhir.r4.model.StructureMap
import org.hl7.fhir.r4.model.IdType
import org.hl7.fhir.r4.model.Bundle
import org.hl7.fhir.r4.model.Resource
import org.hl7.fhir.r4.utils.StructureMapUtilities
import org.hl7.fhir.utilities.npm.NpmPackage
import org.slf4j.LoggerFactory
Expand All @@ -21,7 +25,7 @@ import org.springframework.stereotype.Service
import java.io.IOException

@Service
class ExtractOperationProvider {
class ExtractOperationProvider @Autowired constructor(private val appProperties: AppProperties) {

@Autowired
private lateinit var helperService: HelperService
Expand All @@ -31,6 +35,11 @@ class ExtractOperationProvider {

private val logger = LoggerFactory.getLogger(ExtractOperationProvider::class.java)

private val context: FhirContext = FhirContext.forR4()

// Create a FHIR client
private val client: IGenericClient = context.newRestfulGenericClient(appProperties.fhir_baseUrl)

@Operation(name = "\$extract", idempotent = true, global = true, type = QuestionnaireResponse::class)
fun extract(
@IdParam theId: IdType,
Expand All @@ -43,14 +52,24 @@ class ExtractOperationProvider {
val workerContext = r4FhirOperationHelper.loadWorkerContext(measlesOutbreakPackage, basePackage)
val transformSupportServices = R4TransformSupportServicesLM(workerContext, mutableListOf())
// Fetch resources
val questionnaire =
var questionnaire =
workerContext.fetchResource(Questionnaire::class.java, theQuestionnaireResponse.questionnaire)
?: throw ResourceNotFoundException("Questionnaire Resource not found")

val structureMap =
workerContext.fetchResource(StructureMap::class.java, questionnaire.targetStructureMap!!)
if(questionnaire == null) {
questionnaire = fetchResourceById(Questionnaire::class.java, theQuestionnaireResponse.questionnaire)
?: throw ResourceNotFoundException("Questionnaire Resource not found")
}
val structureMapExtensionValue = questionnaire.targetStructureMap
?: throw ResourceNotFoundException("StructureMap Resource not found")

var structureMap =
workerContext.fetchResource(StructureMap::class.java, structureMapExtensionValue)
if(structureMap == null) {
val structureMapId = structureMapExtensionValue.split("/").lastOrNull()
?: throw ResourceNotFoundException("StructureMap Resource not found")
structureMap = fetchResourceById(StructureMap::class.java, structureMapId)
?: throw ResourceNotFoundException("StructureMap Resource not found")
}

r4FhirOperationHelper.extract(
questionnaire,
theQuestionnaireResponse,
Expand All @@ -63,6 +82,7 @@ class ExtractOperationProvider {
)
}
} catch (e: Exception) {
e.printStackTrace()
return handleException(e)
}
}
Expand All @@ -81,6 +101,13 @@ class ExtractOperationProvider {
return bundle
}

private fun <T : Resource> fetchResourceById(resourceType: Class<T>, resourceId: String): T? {
return client.read()
.resource(resourceType)
.withId(resourceId)
.execute()
}



}