-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #11 from openmrs/HIE-2-pixm
[HIE-2] Skeleton code for client registry search flow
- Loading branch information
Showing
11 changed files
with
339 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
6 changes: 6 additions & 0 deletions
6
api/src/main/java/org/openmrs/module/clientregistry/ClientRegistryTransactionType.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
package org.openmrs.module.clientregistry; | ||
|
||
public enum ClientRegistryTransactionType { | ||
FHIR, | ||
HL7 | ||
} |
13 changes: 13 additions & 0 deletions
13
api/src/main/java/org/openmrs/module/clientregistry/api/CRPatientService.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
package org.openmrs.module.clientregistry.api; | ||
|
||
import org.hl7.fhir.r4.model.Patient; | ||
import org.openmrs.module.fhir2.api.search.param.PatientSearchParams; | ||
|
||
import java.util.List; | ||
|
||
public interface CRPatientService { | ||
|
||
List<Patient> getCRPatients(String sourceIdentifier, String sourceIdentifierSystem, List<String> extraTargetSystems); | ||
|
||
List<Patient> searchCRForPatients(PatientSearchParams patientSearchParams); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
89 changes: 89 additions & 0 deletions
89
api/src/main/java/org/openmrs/module/clientregistry/api/impl/FhirCRPatientServiceImpl.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
package org.openmrs.module.clientregistry.api.impl; | ||
|
||
import ca.uhn.fhir.rest.client.api.IGenericClient; | ||
import ca.uhn.fhir.rest.gclient.IOperationUntypedWithInputAndPartialOutput; | ||
import ca.uhn.fhir.rest.gclient.IQuery; | ||
import ca.uhn.fhir.rest.gclient.StringClientParam; | ||
import ca.uhn.fhir.rest.param.StringOrListParam; | ||
import ca.uhn.fhir.rest.param.StringParam; | ||
import ca.uhn.fhir.rest.param.TokenParam; | ||
import ca.uhn.fhir.rest.param.UriOrListParam; | ||
import org.hl7.fhir.instance.model.api.IBaseBundle; | ||
import org.hl7.fhir.r4.model.*; | ||
import org.openmrs.module.clientregistry.ClientRegistryConfig; | ||
import org.openmrs.module.clientregistry.api.CRPatientService; | ||
import org.openmrs.module.clientregistry.providers.FhirCRConstants; | ||
import org.openmrs.module.fhir2.FhirConstants; | ||
import org.openmrs.module.fhir2.api.search.param.PatientSearchParams; | ||
import org.springframework.beans.factory.annotation.Autowired; | ||
import org.springframework.stereotype.Component; | ||
|
||
import java.util.Collections; | ||
import java.util.List; | ||
import java.util.Objects; | ||
import java.util.stream.Collectors; | ||
|
||
@Component | ||
public class FhirCRPatientServiceImpl implements CRPatientService { | ||
|
||
@Autowired | ||
private IGenericClient fhirClient; | ||
|
||
@Autowired | ||
private ClientRegistryConfig config; | ||
|
||
/** | ||
* Get patient identifiers from an external client registry's $ihe-pix implementation. Use the | ||
* returned identifiers to then request a matching Patient bundle from the client registry. | ||
*/ | ||
@Override | ||
public List<Patient> getCRPatients(String sourceIdentifier, String sourceIdentifierSystem, List<String> targetSystems) { | ||
// construct request to external FHIR $ihe-pix endpoint | ||
IOperationUntypedWithInputAndPartialOutput<Parameters> identifiersRequest = fhirClient | ||
.operation() | ||
.onType(FhirConstants.PATIENT) | ||
.named(FhirCRConstants.IHE_PIX_OPERATION) | ||
.withSearchParameter(Parameters.class, FhirCRConstants.SOURCE_IDENTIFIER, new TokenParam(sourceIdentifierSystem, sourceIdentifier)); | ||
|
||
if (!targetSystems.isEmpty()) { | ||
identifiersRequest.andSearchParameter(FhirCRConstants.TARGET_SYSTEM, new StringParam(String.join(",", targetSystems))); | ||
} | ||
|
||
Parameters crMatchingParams = identifiersRequest.useHttpGet().execute(); | ||
List<String> crIdentifiers = crMatchingParams.getParameter().stream() | ||
.filter(param -> Objects.equals(param.getName(), "targetId")) | ||
.map(param -> param.getValue().toString()) | ||
.collect(Collectors.toList()); | ||
|
||
if (crIdentifiers.isEmpty()) { | ||
return Collections.emptyList(); | ||
} | ||
|
||
// construct and send request to external client registry | ||
Bundle patientBundle = fhirClient | ||
.search() | ||
.forResource(Patient.class) | ||
.where(new StringClientParam(Patient.SP_RES_ID).matches().values(crIdentifiers)) | ||
.returnBundle(Bundle.class) | ||
.execute(); | ||
|
||
return parseCRPatientSearchResults(patientBundle); | ||
} | ||
|
||
@Override | ||
public List<Patient> searchCRForPatients(PatientSearchParams patientSearchParams) { | ||
return null; | ||
} | ||
|
||
/** | ||
* Filter and parse out fhir patients from Client Registry Patient Search results | ||
*/ | ||
private List<Patient> parseCRPatientSearchResults(Bundle patientBundle) { | ||
return patientBundle | ||
.getEntry() | ||
.stream() | ||
.filter(entry -> entry.hasType(FhirConstants.PATIENT)) | ||
.map(entry -> (Patient) entry.getResource()) | ||
.collect(Collectors.toList()); | ||
} | ||
} |
27 changes: 27 additions & 0 deletions
27
api/src/main/java/org/openmrs/module/clientregistry/providers/FhirCRConstants.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
package org.openmrs.module.clientregistry.providers; | ||
|
||
import ca.uhn.fhir.model.api.annotation.SearchParamDefinition; | ||
import ca.uhn.fhir.rest.gclient.StringClientParam; | ||
import ca.uhn.fhir.rest.gclient.TokenClientParam; | ||
import ca.uhn.fhir.rest.gclient.UriClientParam; | ||
import ca.uhn.fhir.rest.param.StringOrListParam; | ||
|
||
public class FhirCRConstants { | ||
|
||
public static final String IHE_PIX_OPERATION = "$ihe-pix"; | ||
|
||
@SearchParamDefinition(name = "sourceIdentifier", path = "Patient.sourceIdentifier", description = "A patient identifier used to find cross-matching identifiers in client registry", type = "token") | ||
public static final String SOURCE_IDENTIFIER = "sourceIdentifier"; | ||
|
||
public static final TokenClientParam SOURCE_IDENTIFIER_PARAM = new TokenClientParam("sourceIdentifier"); | ||
|
||
@SearchParamDefinition(name = "targetSystem", path = "Patient.targetSystem", description = "Assigning Authorities for the Patient Identifier Domains from which the returned identifiers shall be selected", type = "token") | ||
public static final String TARGET_SYSTEM = "targetSystem"; | ||
|
||
public static final UriClientParam TARGET_SYSTEM_PARAM = new UriClientParam("targetSystem"); | ||
|
||
@SearchParamDefinition(name = "_format", path = "Patient.targetSystem", description = "Assigning Authorities for the Patient Identifier Domains from which the returned identifiers shall be selected", type = "token") | ||
public static final String _FORMAT = "_FORMAT"; | ||
|
||
public static final StringClientParam _FORMAT_PARAM = new StringClientParam("_format"); | ||
} |
99 changes: 99 additions & 0 deletions
99
...in/java/org/openmrs/module/clientregistry/providers/r4/FhirCRPatientResourceProvider.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
package org.openmrs.module.clientregistry.providers.r4; | ||
|
||
import ca.uhn.fhir.model.valueset.BundleTypeEnum; | ||
import ca.uhn.fhir.rest.annotation.Search; | ||
import ca.uhn.fhir.rest.param.StringParam; | ||
import ca.uhn.fhir.rest.param.StringOrListParam; | ||
import ca.uhn.fhir.rest.param.TokenParam; | ||
import ca.uhn.fhir.rest.server.IResourceProvider; | ||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; | ||
import ca.uhn.fhir.rest.server.exceptions.NotImplementedOperationException; | ||
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException; | ||
import lombok.Setter; | ||
import org.hl7.fhir.instance.model.api.IBaseResource; | ||
import org.hl7.fhir.r4.model.Patient; | ||
import ca.uhn.fhir.rest.annotation.Operation; | ||
import ca.uhn.fhir.rest.annotation.OperationParam; | ||
import org.openmrs.module.clientregistry.ClientRegistryConfig; | ||
import org.openmrs.module.clientregistry.api.ClientRegistryManager; | ||
import org.openmrs.module.clientregistry.providers.FhirCRConstants; | ||
import org.openmrs.module.fhir2.api.annotations.R4Provider; | ||
import org.springframework.beans.factory.annotation.Autowired; | ||
import org.springframework.stereotype.Component; | ||
|
||
import java.util.Collections; | ||
import java.util.List; | ||
import java.util.Objects; | ||
import java.util.stream.Collectors; | ||
|
||
import static lombok.AccessLevel.PACKAGE; | ||
|
||
@Component("crPatientFhirR4ResourceProvider") | ||
@R4Provider | ||
@Setter(PACKAGE) | ||
public class FhirCRPatientResourceProvider implements IResourceProvider { | ||
|
||
@Autowired | ||
private ClientRegistryManager clientRegistryManager; | ||
|
||
@Autowired | ||
private ClientRegistryConfig config; | ||
|
||
@Override | ||
public Class<? extends IBaseResource> getResourceType() { | ||
return Patient.class; | ||
} | ||
|
||
/** | ||
* FHIR endpoint to get Patient references from external client registry Example request: GET | ||
* [fhirbase | ||
* ]/Patient/$ihe-pix?sourceIdentifier={sourceSystem|}1234[&targetSystem=system1,system2] | ||
* | ||
* @param sourceIdentifierParam patient identifier token. If source system is included in token, | ||
* we will use it to override the module defined source system. | ||
* @param targetSystemsParam (optional) Patient assigning authorities (ie systems) from which | ||
* the returned identifiers shall be selected | ||
* @return List of matching FHIR patients returned by the client registry | ||
*/ | ||
@Operation(name = FhirCRConstants.IHE_PIX_OPERATION, idempotent=true, type = Patient.class, bundleType = BundleTypeEnum.SEARCHSET) | ||
public List<Patient> getCRPatientById( | ||
@OperationParam(name = FhirCRConstants.SOURCE_IDENTIFIER) TokenParam sourceIdentifierParam, | ||
@OperationParam(name = FhirCRConstants.TARGET_SYSTEM) StringOrListParam targetSystemsParam | ||
) { | ||
|
||
if (sourceIdentifierParam == null || sourceIdentifierParam.getValue() == null) { | ||
throw new InvalidRequestException("sourceIdentifier must be specified"); | ||
} | ||
|
||
List<String> targetSystems = targetSystemsParam == null | ||
? Collections.emptyList() | ||
: targetSystemsParam.getValuesAsQueryTokens().stream().filter(Objects::nonNull).map(StringParam::getValue).collect(Collectors.toList()); | ||
|
||
// If no sourceSystem provided, use config defined default | ||
boolean userDefinedSourceSystem = sourceIdentifierParam.getSystem() != null && !sourceIdentifierParam.getSystem().isEmpty(); | ||
String sourceIdentifierSystem = userDefinedSourceSystem | ||
? sourceIdentifierParam.getSystem() | ||
: config.getClientRegistryDefaultPatientIdentifierSystem(); | ||
|
||
if (sourceIdentifierSystem == null || sourceIdentifierSystem.isEmpty()) { | ||
throw new InvalidRequestException("ClientRegistry module does not have a default source system assigned " + | ||
"via the defaultPatientIdentifierSystem property. Source system must be provided as a token in " + | ||
"the sourceIdentifier request param"); | ||
} | ||
|
||
List<Patient> patients = clientRegistryManager.getPatientService().getCRPatients( | ||
sourceIdentifierParam.getValue(), sourceIdentifierSystem, targetSystems | ||
); | ||
|
||
if (patients.isEmpty()) { | ||
throw new ResourceNotFoundException("No Client Registry patients found."); | ||
} | ||
|
||
return patients; | ||
} | ||
|
||
@Search | ||
public List<Patient> searchClientRegistryPatients() { | ||
throw new NotImplementedOperationException("search client registry is not yet implemented"); | ||
} | ||
} |
Oops, something went wrong.