diff --git a/PixM_Feed_Documentation/README_PixMFeed.md b/PixM_Feed_Documentation/README_PixMFeed.md new file mode 100644 index 0000000000000000000000000000000000000000..ae0b80bfec74a06b5519b424341f5551fa1376e7 --- /dev/null +++ b/PixM_Feed_Documentation/README_PixMFeed.md @@ -0,0 +1,536 @@ +# PixM Feed + +>Version : 1.0.0 <br /> +>Date : 2021-08-26 + +PixM Feed lets a user to proceed some operations with Cross-Referenced (X-ref) Patient. +The User can do the following ITI-93 transactions : Create, Update, Delete and Merge Patient (called CUDM operations) +Each operation will be decribed later. + +The PixM Feed has 2 components : +* a PixM Consumer : the Client part, where the User can do CUDM operations through a SOAP UI project uploaded in Gazelle Webservice Tester (GWT). The SOAP UI project can perform also all cases covered by the standard and shall send/receive all the required requests. +* a PixM Manager : the Server part, where all the CUDM operations are done in order to feed the Patient database. The PixM Manager has 2 parts : + + PixM Connector: interpret REST FHIR requests and data to transform it into a Gazelle Patient Model for the transfert toward Patient Registry. + + Patient Registry : manage transaction I/O of the Patient Database, CUDM and also X-ref. The access to PatReg has to be done with GIT-B webservices.<br /> + +The communication between PixM Connector and Patient Registry is done by a Java Client in order to translate REST operation into SOAP operation done with GIT-B webservices. + + + + +All the transactions between the PixM Client and the PixM Manager are ruled byt ITI-93 transactions.<br /> +https://fhir.ch/ig/ch-epr-mhealth/iti-93.html<br /> +https://www.ihe.net/uploadedFiles/Documents/ITI/IHE_ITI_Suppl_PMIR.pdf + +<br /> + +## ITI-93 transactions +_____________________________________________________________________________________ +ITI-93 transactions are basically Bundle messages exchanged between a Supplier and a Consumer. +The Supplier sends a Mobile Patient Feed Request to a Consumer. This event is trigerred every time patients are created, updated, merged or deleted by the Supplier. +The Consumer sends back a Mobile Patient feed Response to a Supplier. + +  + +The **Bundle PixMFeed request** has 2 entries (https://fhir.ch/ig/ch-epr-mhealth/Bundle-BundlePIXmFeed.json.html) : +- a Message header +- a History Bundle, containing the Patient Resource (https://www.hl7.org/fhir/patient.html) + +This two entries are mandatory for each transactions. +We will see further that not every fields are mandatory to proceed operations. + +The **Bundle PixMFeed response** has 1 entry (https://fhir.ch/ig/ch-epr-mhealth/Bundle-BundlePIXmResponse.json.html): +- a message response that acknowledge the transaction is done. + +For our purpose, the message response will also return in case of : +- CREATE : the uuid of the newly created patient will be returned in the message +- UPDATE : the whole Patient will be returned +- MERGE : The uuid of the original Patient is returned +- DELETE : The DONE or GONE status + +<br /> + +## PIXM Consumer : SOAP UI Project +__________________________________________________________________ +The SOAP UI Project for CHPixM Feed is splitted in 2 parts : +- the one that the user can interact with to do its request to PixM Server, can test nominal and errors requests +- the MOCK server test implemented methods and mimic the desired comportment from the PixM Server + +4 methods are implemented and their related TestSuite & TestCase +- CREATE (C) +- DELETE (D) +- UPDATE (U) +- MERGE (M) + +For each TestCase, the user can filled a prefilled body with following fields : + +- name.given (CU) +- name.family (CU) +- birthDate (CU) +- gender (CU) +- resource (CUDM) +- system (CU) +- value (CU) +- uuid (UMD) +- uuidToRedirect (M) + +These fields can be accessed in each TestSuite > TestCase +then on the bottom-left corner click on the tab "Custom properties" + + +### CREATE METHOD : +__________________________________________________________________ + +#### NOMINAL CASE : + +Send the following REST Request + + POST : {serverAdress}/{resource}/PatientPIXmFeed + + +With a prefilled body as following : + +```json +{ + "resourceType" : "Bundle", + "id" : "BundlePIXmFeed", + "meta" : { + "profile" : [ + "http://fhir.ch/ig/ch-epr-mhealth/StructureDefinition/ch-pixm-bundle" + ] + }, + "type" : "message", + "entry" : [ + { + "fullUrl" : "http://example.com/fhir/MessageHeader/1", + "resource" : { + "resourceType" : "MessageHeader", + "id" : "1", + "text" : { + "status" : "generated", + "div" : "<div xmlns=\"http://www.w3.org/1999/xhtml\"><p><b>Generated Narrative</b></p><p><b>event</b>: <code>urn:ihe:iti:pmir:2019:patient-feed</code></p><h3>Destinations</h3><table class=\"grid\"><tr><td>-</td><td><b>Endpoint</b></td></tr><tr><td>*</td><td><a href=\"http://example.com/patientEndpoint\">http://example.com/patientEndpoint</a></td></tr></table><h3>Sources</h3><table class=\"grid\"><tr><td>-</td><td><b>Endpoint</b></td></tr><tr><td>*</td><td><a href=\"http://example.com/patientSource\">http://example.com/patientSource</a></td></tr></table><p><b>focus</b>: <a href=\"#Bundle_abc\">See above (Bundle/abc)</a></p></div>" + }, + "eventUri" : "urn:ihe:iti:pmir:2019:patient-feed", + "destination" : [ + { + "endpoint" : "http://example.com/patientEndpoint" + } + ], + "source" : { + "endpoint" : "http://example.com/patientSource" + }, + "focus" : [ + { + "reference" : "Bundle/abc" + } + ] + } + }, + { + "fullUrl" : "http://example.com/fhir/Bundle/abc", + "resource" : { + "resourceType" : "Bundle", + "id" : "abc", + "type" : "history", + "entry" : [ + { + "fullUrl" : "http://example.com/fhir/Patient/PatientPIXmFeed", + "resource" : { + "resourceType" : "Patient", + "id" : "PatientPIXmFeed", + "text" : { + "status" : "generated", + "div" : "<div xmlns=\"http://www.w3.org/1999/xhtml\"><p><b>Generated Narrative</b></p><p><b>id</b>: PatientPIXmFeed</p><p><b>meta</b>: </p><p><b>identifier</b>: Medical record number = 8734</p><p><b>name</b>: Franz Muster , Muster </p><p><b>gender</b>: male</p><p><b>birthDate</b>: 1995-01-27</p></div>" + }, + "contained" : [ + { + "resourceType" : "Organization", + "id" : "org1", + "identifier" : [ + { + "system" : "${system}", + "value" : "${value}" + } + ], + "address" : [ + { + "use" : "work", + "line" : [ + "Doktorgasse", + "2" + ], + "city" : "Musterhausen", + "postalCode" : "8888", + "country" : "CH" + } + ] + } + ], + "identifier" : [ + { + "type" : { + "coding" : [ + { + "system" : "http://terminology.hl7.org/CodeSystem/v2-0203", + "code" : "MR" + } + ] + }, + "system" : "${#system}", + "value" : "${#value}" + } + ], + "name" : [ + { + "family" : "${#name.family}", + "given" : [ + "${#name.given}" + ] + }, + { + "family" : "${#name.family}", + "_family" : { + "extension" : [ + { + "url" : "http://hl7.org/fhir/StructureDefinition/iso21090-EN-qualifier", + "valueCode" : "BR" + } + ] + } + } + ], + "gender" : "${#gender}", + "birthDate" : "${#birthDate}", + "managingOrganization" : { + "reference" : "#org1" + } + }, + "request" : { + "method" : "POST", + "url" : "Patient" + }, + "response" : { + "status" : "200" + } + } + ] + } + } + ] + } +``` + + +These parameters are mandatory in CREATE method +* name.given +* name.family +* birthdate +* gender + + + +The server then should answer a response bundle like : + ```json +{ + "resourceType" : "Bundle", + "id" : "BundlePIXmResponse", + "meta" : { + "profile" : [ + "http://fhir.ch/ig/ch-epr-mhealth/StructureDefinition/ch-pixm-bundle-response" + ] + }, + "type" : "message", + "entry" : [ + { + "fullUrl" : "http://example.com/fhir/MessageHeader/1", + "resource" : { + "resourceType" : "MessageHeader", + "id" : "1", + "text" : { + "status" : "generated", + "div" : "<div xmlns=\"http://www.w3.org/1999/xhtml\"><p><b>Generated Narrative</b></p><p><b>event</b>: <code>urn:ihe:iti:pmir:2019:patient-feed</code></p><h3>Destinations</h3><table class=\"grid\"><tr><td>-</td><td><b>Endpoint</b></td></tr><tr><td>*</td><td><a href=\"http://example.com/patientEndpoint\">http://example.com/patientEndpoint</a></td></tr></table><h3>Sources</h3><table class=\"grid\"><tr><td>-</td><td><b>Endpoint</b></td></tr><tr><td>*</td><td><a href=\"http://example.com/patientSource\">http://example.com/patientSource</a></td></tr></table><h3>Responses</h3><table class=\"grid\"><tr><td>-</td><td><b>Identifier</b></td><td><b>Code</b></td></tr><tr><td>*</td><td>1</td><td>ok</td></tr></table></div>" + }, + "eventUri" : "urn:ihe:iti:pmir:2019:patient-feed", + "destination" : [ + { + "endpoint" : "http://example.com/patientEndpoint" + } + ], + "source" : { + "endpoint" : "http://example.com/patientSource" + }, + "response" : { + "identifier" : "1", + "code" : "ok" + } + } + } + ] + } + ++ The ID of the new patient newly created +``` + + +The following assertion will be tested when the body is sent : +- if the returned HTTP Status is "200" +- if the gender is : male OR female OR unknown OR other +- if the birthDay is an existed date in Calendar AND in the YYYY-MM-DD format AND NOT greater than the Current day +- if the sourceIdentifier (if given) respect the following regex: +>urn:oid:([0-9]+)(\.[0-9]+)+\|([ -~]+) <br /> +>{start with "urn:oid:"} then {"any number"} then {sequence of "."+"any number"} then a pipe ["|"] then {"any string"} + +<br/> + +#### TEST CASE (400) + +>Resource could not be parsed or failed basic FHIR validation rules | malformed bundle message.<br/> + +Same as Nominal Test excepting : + +* The Bundle message is intentionally malformed + +* The following assertion will be tested when the body is sent : + - if the returned HTTP Status is "400" + +<br/> + + +#### TEST CASE (404) +>Resource type not supported, or not a FHIR end-point : request URL is not valid + +The following assertion will be tested when the body is sent : +- if the returned HTTP Status is "404" + +#### TEST CASE (422) + +>The proposed resource violated applicable FHIR profiles or server business rules. This should be accompanied by an OperationOutcome resource providing additional detail. + +The request is a right one but the submitted birthdate OR gender OR sourceIdentifier do NOT respect the assertion rules. + +The following assertion will be tested when the body is sent : + - if the returned HTTP Status is "422" + + +### DELETE METHOD +______________________________________________________________________ + + +#### NOMINAL CASE : +Send the following REST Request +>DELETE : {serverAdress}/{resource}/{id} + + +Same body as a create except : +* request method must be delete at the end : +```json + + "request" : { + "method" : "DELETE", + "url" : "Patient" + }, +``` + + +* Mandatory field to fill in case of DELETE method : + * uuid + +In the case of the DELETE method, none of the fields are taking into account, only the UUID is check, and the Server shall answer 2 DELETE status : +- DONE if the Patient existed and is now deleted +- GONE if the Patient to delete does NOT exist in Databse + +The following assertion will be tested when the body is sent : +- if the returned HTTP Status is "204" + + +<br/> + +#### TEST CASE (404) + +>case where uuid not exist in database + + +Same as NOMINAL except : + +The following assertion will be tested when the body is sent : +- if the returned HTTP Status is "404" + + +### UPDATE METHOD +__________________________________________________________________________________ + +#### NOMINAL CASE : +Send the following REST Request +>PUT : {serverAdress}/{resource}/{id} + + +Same body as CREATE method but : +* the request method should be put AND the patient id is replaced by an UUID +```json + "request" : { + "method" : "PUT", + "url" : "Patient" + }, + +``` + +* Mandatory fields : uuid + +* The body response shall return the modified Patient. + +<br/> + +#### TEST CASE (400) + +>resource could not be parsed or failed basic FHIR validation rules | malformed bundle message + + +Same as Nominal Test excepting : + +The Bundle message is intentionally malformed + +The following assertion will be tested when the body is sent : +- if the returned HTTP Status is "400" + + + + + +#### TEST CASE (422) +> the proposed resource violated applicable FHIR profiles or server business rules. This should be accompanied by an OperationOutcome resource providing additional detail. + +Same as Nominal Test excepting : + + +The following assertion will be tested when the body is sent : +- if the returned HTTP Status is "422" + + <br/> + +### MERGE METHOD (should be updated in further version) +____________________________________________________________________________________ +Send the following REST Request : +>PUT : {serverAdress}/{resource}/{id} + +The body is different because the MERGE is a used in the case where the same patient was created 2 times and the user would like to redirect the duplicated patient to the original one in the database. + +```json +{ + "resourceType": "Bundle", + "type": "message", + "entry": [{ + "fullUrl": "http://qualification.ihe-europe.net/fhir/MessageHeader/1", + "resource": { + "resourceType": "MessageHeader", + "id": "1", + "eventUri": "urn:ihe:iti:pmir:2019:patient-feed", + "source": { + "endpoint": "http://qualification.ihe-europe.net/patientSource" + }, + "focus": [{ + "reference": "Bundle/abc" + }], + "destination": [{ + "endpoint": "http://qualification.ihe-europe.net/patientEndpoint" + }] + } + }, { + "fullUrl": "http://qualification.ihe-europe.net/fhir/Bundle/abc", + "resource": { + "resourceType": "Bundle", + "id": "abc", + "type": "history", + "entry": [{ + "fullUrl": "http://qualification.ihe-europe.net/fhir/Patient/${uuid}", + "resource": { + "resourceType": "Patient", + "id": "${uuid}", + "active": false, + "link": [{ + "other": { + "reference": "http://qualification.ihe-europe.net/fhir/Patient/${uuidToRedirect}" + }, + "type": "replaced-by" + }] + }, + "request": { + "method": "PUT", + "url": "Patient/${uuid}" + }, + "response": { + "status": "200" + } + }] + } + }] +} +``` +* Mandatory fields to fill in MERGE request : + * uuid + * uuidToRedirect + +* The response should be as Following : + + - a Patient Identifier is mandatory [1..*] + - On the GWT, I can choose a project {projectName} and select the Merge Test Suite and modify : the endpoint, the formerSourceIdentifier I want to deprecate, the newSourceIdentifier I want for my Patient. + - 200 status is returned if the patient is merged + - 400 status is returned if I provided malformed Bundle Json + - 404 status is returned if I provided well-formed sourceIdentifier but not exist in PatReg + - 405 status is returned if I provide a sourceIdentifier for a deactivated patient + - 422 status is returned if I provide a malformed sourceIdentifier + +<br/> + +## PIX-M MANAGER +__________________________________________________________________________________ + +### PixM Connector + +PixM Connector is a FHIR application server exposing REST services. It uses the HAPI FHIR Server framework (a fast solution to deploy a FHIR Server and implement a specific treatment for the request). + +The PixM Connector is a Java Project which receives the SUT Request and transfer it to the Java Client for Patreg. +It shall manage received CREATE, UPDATE, DELETE, MERGE request from SUT. +It has also to convert a FHIR Bundle Object from ITI-93 transaction into a manageable Patient Object by Patient Registry. +It has to received response message from Patient Registry to transfer to the SUT. + +It has 3 parts : +* **server part** : define the context of the deployed FHIR Server +* **provider part** : feed the server with the methods that it needs to expose. In our case it defines the treatment of parameters that needs to be transferred +* **call-the-java-client part** : in this part, the module initialize the Java client with de Patient Registry adress. It uses the JAVA client to transfer the request and interpret the response and reported errors. It also prepares the content of the FHIR reponse and sends back to the SUT. + +<br/> + +### Java Client (part of PixM Connector) + +It acts like a connector to Patient Registry. +Its role is to initialize the connection with Patient Registry and translate the research parameters into GITB Model. +It implements the same interface as the service. This connector is embedded in PIXm-Connector to communicate with this module. + +<br/> + +### Patient Registry + +Patient Registry is a module that allows you to interact with the database of Patient Manager database. +This module has no web interface. It is only accessible through its webservices just like PIX-Connector. +With one exception, the latter uses REST webservices while Patient Registry uses Soap technology with a GITB overlay. + +The GITB model is a standardization project initiated by the European Commission. +The specifications aim at the interoperability of the test tools in a test bucket. It is about +defining a common interface between the tools and a test bench. This common interface +defines the data exchanges via the webservices. They use a standardized data type standardized data type that requires a correspondence with the gazelle data models. +It is expected that in the next few years that the GITB standard will migrate to REST webservices. + +The Patient Registry Webservice implements the GITB model. It only receives requests in this format. It identifies the operation to be performed (here a cross-reference search operation) and +operation) and establishes the reverse correspondence, from the GITB model to the +Gazelle model. + +The webservice then transmits these parameters to the service application layer which +returns the result or the exceptions raised during the operation. Again, we perform the +the results in a report indicating the status and the result of the operation. +the result of the operation. This report is then translated and interpreted by the Java client. + + + + + + diff --git a/PixM_Feed_Documentation/pictures/iti_93_interaction_diagram.png b/PixM_Feed_Documentation/pictures/iti_93_interaction_diagram.png new file mode 100644 index 0000000000000000000000000000000000000000..d65ca11ee29cda0694cd6f2d5b2d25e81006542e Binary files /dev/null and b/PixM_Feed_Documentation/pictures/iti_93_interaction_diagram.png differ diff --git a/PixM_Feed_Documentation/pictures/pixm_connector.png b/PixM_Feed_Documentation/pictures/pixm_connector.png new file mode 100644 index 0000000000000000000000000000000000000000..e2eb7b8aeb0b979b5bf7854aabde52452c89a8c8 Binary files /dev/null and b/PixM_Feed_Documentation/pictures/pixm_connector.png differ diff --git a/PixM_Feed_Documentation/pictures/pixm_scheme_total.png b/PixM_Feed_Documentation/pictures/pixm_scheme_total.png new file mode 100644 index 0000000000000000000000000000000000000000..ba1ad2f1ea3f7eb9b9ba0ffa63403eaa850929d9 Binary files /dev/null and b/PixM_Feed_Documentation/pictures/pixm_scheme_total.png differ diff --git a/src/test/java/net/ihe/gazelle/business/provider/CHBundleProviderTest.java b/src/test/java/net/ihe/gazelle/business/provider/CHBundleProviderTest.java index bed7db1e83454177144c2e05e35a130f17dd5d8a..94e56ba3f29be306361d744f9bc195ece5052445 100644 --- a/src/test/java/net/ihe/gazelle/business/provider/CHBundleProviderTest.java +++ b/src/test/java/net/ihe/gazelle/business/provider/CHBundleProviderTest.java @@ -46,7 +46,7 @@ class CHBundleProviderTest { @Description("Test on the Create Method with a Bundle with No Patient inside") void testCreateNoPatientInBundle() { String fileName = "post_request_NO_PATIENT.json"; - assertThrows(InvalidRequestException.class, ()-> bundle_feed_provider.create(cbpm.returnBundleFromResource(fileName)),"Missing Pat in Bundle"); + assertThrows(InvalidRequestException.class, ()-> bundle_feed_provider.create(cbpm.returnBundleFromResource(fileName)),"Missing Patient in Bundle"); } @Test