diff --git a/Fhir Operations.postman_collection.json b/Fhir Operations.postman_collection.json
index b30776b..76d369e 100644
--- a/Fhir Operations.postman_collection.json
+++ b/Fhir Operations.postman_collection.json
@@ -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": [
{
@@ -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\": \"
map "http://hl7.org/fhir/StructureMap/PatientRegistration" = 'PatientRegistration'\\n\\n uses "http://hl7.org/fhir/StructureDefinition/QuestionnaireReponse" as source\\n uses "http://hl7.org/fhir/StructureDefinition/Bundle" as target\\n \\n group PatientRegistration(source src : QuestionnaireResponse, target bundle: Bundle) {\\n src -> bundle.id = uuid() "rule_c";\\n src -> bundle.type = 'collection' "rule_b";\\n src -> bundle.entry as entry, entry.resource = create('Patient') as patient then\\n ExtractPatient(src, patient) "rule_z";\\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 -> tgt.birthDate = val "rule_a";\\n } ;\\n } ;\\n };\\n } \"\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": {
diff --git a/configs/hapi_application.yaml b/configs/hapi_application.yaml
index 5edc323..81b0cdd 100644
--- a/configs/hapi_application.yaml
+++ b/configs/hapi_application.yaml
@@ -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
diff --git a/src/main/java/ca/uhn/fhir/jpa/starter/customOperations/r4/ExtractOperationProvider.kt b/src/main/java/ca/uhn/fhir/jpa/starter/customOperations/r4/ExtractOperationProvider.kt
index 57f5f83..4436eed 100644
--- a/src/main/java/ca/uhn/fhir/jpa/starter/customOperations/r4/ExtractOperationProvider.kt
+++ b/src/main/java/ca/uhn/fhir/jpa/starter/customOperations/r4/ExtractOperationProvider.kt
@@ -1,11 +1,14 @@
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
@@ -13,6 +16,7 @@ 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
@@ -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
@@ -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,
@@ -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,
@@ -63,6 +82,7 @@ class ExtractOperationProvider {
)
}
} catch (e: Exception) {
+ e.printStackTrace()
return handleException(e)
}
}
@@ -81,6 +101,13 @@ class ExtractOperationProvider {
return bundle
}
+ private fun fetchResourceById(resourceType: Class, resourceId: String): T? {
+ return client.read()
+ .resource(resourceType)
+ .withId(resourceId)
+ .execute()
+ }
+
}
\ No newline at end of file