Change CDS on FHIR Prefetch (#5778)
* Change CR services to use auto prefetch and not pass fhirServer as dataEndpoint * Add documentation for CDS Hooks
This commit is contained in:
parent
ba5311d4cc
commit
7005e83b03
|
@ -0,0 +1,4 @@
|
||||||
|
---
|
||||||
|
type: add
|
||||||
|
issue: 5777
|
||||||
|
title: "Change the implementation of CDS on FHIR to use the Auto Prefetch functionality and to no longer pass the fhirServer from the request into the dataEndpoint parameter of $apply."
|
|
@ -0,0 +1,143 @@
|
||||||
|
# CDS Hooks
|
||||||
|
|
||||||
|
CDS Hooks are services called by CDS Clients (typically Electronic Health Record Systems (EHRs) or other health
|
||||||
|
information systems). They implement a "hook"-based pattern for invoking decision support from within a clinician's
|
||||||
|
workflow.
|
||||||
|
|
||||||
|
HAPI FHIR implements [Version 1.1 of the CDS Hooks Specification](https://cds-hooks.hl7.org/ballots/2020Sep/).
|
||||||
|
|
||||||
|
The HAPI FHIR CDS Hooks Module simplifies the effort for creating CDS Hooks. All you need to do is create a method that
|
||||||
|
accepts a `CdsServiceRequestJson` parameter and returns a `CdsServiceResponseJson` value and annotate this method with
|
||||||
|
the `@CdsService` annotation. This annotation and the Json classes and all their subcomponents are available in the
|
||||||
|
open-source project called `hapi-fhir-server-cds-hooks`. Any FHIR resources in requests and responses are automatically serialized
|
||||||
|
into hapi-fhir FHIR resource instances for you, so they are easy to work with within your code.
|
||||||
|
|
||||||
|
In addition to simplifying the effort to build CDS Hooks, the HAPI FHIR CDS Hooks module also provides the following:
|
||||||
|
|
||||||
|
* All access is logged in the HAPI FHIR Audit Trail.
|
||||||
|
* Authorization is controlled by the HAPI FHIR security framework.
|
||||||
|
* Management and monitoring capabilities are provided by the HAPI FHIR platform.
|
||||||
|
* [CDS on FHIR](/docs/cds_hooks/#cds-on-fhir) implementation that auto-generates CDS Services from PlanDefinitions and executes via the $apply operation.
|
||||||
|
|
||||||
|
# Auto Prefetch
|
||||||
|
|
||||||
|
The HAPI FHIR CDS Hooks module provides a couple of powerful Auto-Prefetch features:
|
||||||
|
|
||||||
|
1. If `allowAutoFhirClientPrefetch` is set to `true` in the `@CdsService` annotation on your CDS Service method, then
|
||||||
|
before calling your method, HAPI FHIR will compare the prefetch elements declared by your service method in
|
||||||
|
the `@CdsService` annotation to the prefetch elements included within the `CdsServiceRequestJson` REST request and if
|
||||||
|
it detects any are missing, then HAPI FHIR will use the FHIR endpoint authorization details included within
|
||||||
|
the `fhirAuthorization` element in the request to automatically add them to the prefetch before calling your method.
|
||||||
|
2. Even simpler, if your HAPI FHIR server has a FHIR Storage module, you can optionally add a dependency from your
|
||||||
|
CDS Hooks Module on your FHIR Storage module. If you do this, then when HAPI FHIR detects any required prefetch
|
||||||
|
elements missing in a request, it will automatically fetch the missing data from your storage module before calling
|
||||||
|
your CDS Hooks method. Note in this case, the same credentials used to call the CDS Hooks endpoint are used to
|
||||||
|
authorize access to the FHIR Storage module.
|
||||||
|
|
||||||
|
## CDS Hooks Auto Prefetch Rules
|
||||||
|
|
||||||
|
- If there are no missing prefetch elements, the CDS Hooks service method is called directly with the request. (Note
|
||||||
|
that per the CDS Hooks specification, a value of `null` is not considered to be missing. CDS Hooks clients set a
|
||||||
|
prefetch value to `null` to indicate that this prefetch data is known to not exist).
|
||||||
|
- Otherwise, if a `fhirServer` is included in the request
|
||||||
|
- If the `@CdsService` annotation on the service method has `allowAutoFhirClientPrefetch = true`, then HAPI FHIR will
|
||||||
|
perform a FHIR REST call to that `fhirServer` endpoint to fetch the missing data.
|
||||||
|
- otherwise, the CDS Hooks service method is expected to call the `fhirServer` endpoint itself to retrieve the
|
||||||
|
missing data.
|
||||||
|
- Otherwise, if the CDS Hooks Module declares a dependency on a FHIR Storage Module, then HAPI FHIR will fetch the
|
||||||
|
missing data from that FHIR Storage Module.
|
||||||
|
- Otherwise, the method will fail with HTTP 412 PRECONDITION FAILED (per the CDS Hooks specification).
|
||||||
|
- The Auto-Prefetch rules can be overridden for individual elements by setting a `source` for the `@CdsServicePrefetch`.
|
||||||
|
HAPI FHIR will attempt to use the `source` strategy for the query instead of following the order above.
|
||||||
|
|
||||||
|
# Architecture
|
||||||
|
|
||||||
|
The diagram below shows how CDS Hooks work. The box in grey contains *customer code*, which is code that you write.
|
||||||
|
|
||||||
|
<img src="/docs/images/cds_hooks.svg" alt="CDS Hooks Architecture" style="width: 1120px;"/>
|
||||||
|
|
||||||
|
A CDS Hooks implementation is packaged as a Java JAR file that contains several key components:
|
||||||
|
|
||||||
|
* **CDS Service** classes, which implement CDS Hooks *service* and *feedback* methods.
|
||||||
|
* A **Spring Context Config** class, which is a Spring Framework class used to instantiate and configure the CDS Hooks
|
||||||
|
classes.
|
||||||
|
|
||||||
|
# CDS Hooks Classes
|
||||||
|
|
||||||
|
A CDS Hooks class contains annotated *service* and *feedback* methods. One CDS Hooks class can contain any number of
|
||||||
|
these methods. A CDS Hooks *service* method is annotated with the `@CdsService` annotation and a CDS Hooks *feedback*
|
||||||
|
method is annotated with the `@CdsServiceFeedback` annotation. The "value" of these annotations corresponds to the id of
|
||||||
|
the CDS Hooks service. For example:
|
||||||
|
|
||||||
|
A method annotated with `@CdsService(value="example-service")` is accessed at a path
|
||||||
|
like `https://example.com:8888/cds-services/example-service`
|
||||||
|
|
||||||
|
A method annotated with `@CdsServiceFeedback(value="my-service")` is accessed at a path
|
||||||
|
like `https://example.com:8888/cds-services/my-service/feedback`.
|
||||||
|
|
||||||
|
A very basic example is shown below:
|
||||||
|
|
||||||
|
```java
|
||||||
|
{{snippet:file:hapi-fhir-server-cds-hooks/src/test/java/ca.uhn.hapi.fhir.cdshooks/controller/ExampleCdsService.java}}
|
||||||
|
```
|
||||||
|
|
||||||
|
Both of these example methods accept a single json instance parameter (`CdsServiceRequestJson`
|
||||||
|
and `CdsServiceFeedbackJson` respectively). Alternatively, these methods can accept a single String parameter in which
|
||||||
|
case the CDS Hooks module will string-encode the instance before calling the method.
|
||||||
|
|
||||||
|
# The Spring Context Config Class
|
||||||
|
|
||||||
|
This mandatory class is a [Spring Framework](https://springframework.org) Annotation-based Application Context Config
|
||||||
|
class. It is characterized by having the `@Configuration` annotation on the class itself, as well as having one or more
|
||||||
|
non-static factory methods annotated with the `@Bean` method, which create instances of your providers (as well as
|
||||||
|
creating any other utility classes you might need, such as database pools, HTTP clients, etc.).
|
||||||
|
|
||||||
|
This class must instantiate a bean named `cdsServices`:
|
||||||
|
|
||||||
|
* The `cdsServices` bean method should return a `List<Object>` of classes that contain `@CdsService`
|
||||||
|
and/or `@CdsServiceFeedback` annotated methods.
|
||||||
|
|
||||||
|
The following example shows a Spring Context Config class that registers the CDS Hooks example above.
|
||||||
|
|
||||||
|
```java
|
||||||
|
@Configuration
|
||||||
|
public class TestServerAppCtx {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This bean is a list of CDS Hooks classes, each one
|
||||||
|
* of which implements one or more CDS-Hook Services.
|
||||||
|
*/
|
||||||
|
@Bean(name = "cdsServices")
|
||||||
|
public List<Object> cdsServices(){
|
||||||
|
List<Object> retVal = new ArrayList<>();
|
||||||
|
retVal.add(new ExampleCdsService());
|
||||||
|
// add other CDS Hooks classes...
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
# Calling CDS Hooks
|
||||||
|
|
||||||
|
Per [Version 1.1 of the CDS Hooks Specification](https://cds-hooks.hl7.org/ballots/2020Sep/), a list of all registered
|
||||||
|
services is available at a path like `https://example.com:8888/cds-services`. As a convenience, swagger REST
|
||||||
|
documentation is provided at the root of the endpoint: `https://example.com:8888/`.
|
||||||
|
|
||||||
|
# Example Project
|
||||||
|
|
||||||
|
A sample CDS Hooks project is available at the following links:
|
||||||
|
|
||||||
|
* [cdr-endpoint-cds-hooks-demoproject-1.0.zip](/docs/downloads/cdr-endpoint-cds-hooks-demoproject-1.0.zip)
|
||||||
|
* [cdr-endpoint-cds-hooks-demoproject-1.0.tar.gz](/docs/downloads/cdr-endpoint-cds-hooks-demoproject-1.0.tar.gz)
|
||||||
|
|
||||||
|
# CDS on FHIR
|
||||||
|
|
||||||
|
To create CDS Services from PlanDefinitions the dependencies for a FHIR Storage Module, FHIR Endpoint and CQL module must be set. This will create a listener on the storage module so that any changes to PlanDefinition resources will update the CDS Service cache.
|
||||||
|
|
||||||
|
Any PlanDefinition resource with an action that has a trigger of type [named-event](http://hl7.org/fhir/R4/codesystem-trigger-type.html#trigger-type-named-event) will have a CDS Service created using the PlanDefinition.id as the service id and the name of the trigger as the hook that the service is created for per the [CDS on FHIR Specification](https://hl7.org/fhir/clinicalreasoning-cds-on-fhir.html#surfacing-clinical-decision-support).
|
||||||
|
|
||||||
|
CDS Services created this way will show up as registered services and can be called just as other services are called. The CDS Service request will be converted into parameters for the [$apply operation](/docs/clinical_reasoning/plan_definitions.html#apply), the results of which are then converted into a CDS Response per the [CDS on FHIR Specification](https://hl7.org/fhir/clinicalreasoning-cds-on-fhir.html#consuming-decision-support).
|
||||||
|
|
||||||
|
These CDS Services will take advantage of the [Auto Prefetch](/docs/cds_hooks/#auto-prefetch) feature. Prefetch data is included as a Bundle in the `data` parameter of the $apply call.
|
||||||
|
|
||||||
|
The $apply operation is running against the FHIR Storage Module, so it will also have access to any data stored there. Any CQL evaluation during the $apply operation that results in a retrieve will always pull from the Bundle and the FHIR Storage Module. This is done regardless of what data is passed into the prefetch of the service request.
|
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 24 KiB |
|
@ -38,8 +38,7 @@ public class CdsCrServiceMethod extends BaseCdsCrMethod implements ICdsServiceMe
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isAllowAutoFhirClientPrefetch() {
|
public boolean isAllowAutoFhirClientPrefetch() {
|
||||||
// The $apply operation will make FHIR requests for any data it needs
|
// The $apply operation will NOT make FHIR requests for any data it needs.
|
||||||
// directly against the fhirServer of the ServiceRequest.
|
return true;
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,13 +51,13 @@ import java.util.stream.Collectors;
|
||||||
* is complete so that other beans can use the stuff it creates.
|
* is complete so that other beans can use the stuff it creates.
|
||||||
*/
|
*/
|
||||||
public class CdsHooksContextBooter {
|
public class CdsHooksContextBooter {
|
||||||
private static final Logger ourLog = LoggerFactory.getLogger(CdsHooksContextBooter.class);
|
protected static final Logger ourLog = LoggerFactory.getLogger(CdsHooksContextBooter.class);
|
||||||
private static final String CDS_SERVICES_BEAN_NAME = "cdsServices";
|
protected static final String CDS_SERVICES_BEAN_NAME = "cdsServices";
|
||||||
private Class<?> myDefinitionsClass;
|
protected Class<?> myDefinitionsClass;
|
||||||
private AnnotationConfigApplicationContext myAppCtx;
|
protected AnnotationConfigApplicationContext myAppCtx;
|
||||||
|
|
||||||
private List<Object> myCdsServiceBeans = new ArrayList<>();
|
protected List<Object> myCdsServiceBeans = new ArrayList<>();
|
||||||
private final CdsServiceCache myCdsServiceCache = new CdsServiceCache();
|
protected final CdsServiceCache myCdsServiceCache = new CdsServiceCache();
|
||||||
|
|
||||||
public void setDefinitionsClass(Class<?> theDefinitionsClass) {
|
public void setDefinitionsClass(Class<?> theDefinitionsClass) {
|
||||||
myDefinitionsClass = theDefinitionsClass;
|
myDefinitionsClass = theDefinitionsClass;
|
||||||
|
@ -70,7 +70,7 @@ public class CdsHooksContextBooter {
|
||||||
return myCdsServiceCache;
|
return myCdsServiceCache;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void extractCdsServices(Object theServiceBean) {
|
protected void extractCdsServices(Object theServiceBean) {
|
||||||
Method[] methods = theServiceBean.getClass().getMethods();
|
Method[] methods = theServiceBean.getClass().getMethods();
|
||||||
// Sort alphabetically so service list output is deterministic (to ensure GET /cds-services is idempotent).
|
// Sort alphabetically so service list output is deterministic (to ensure GET /cds-services is idempotent).
|
||||||
// This also simplifies testing :-)
|
// This also simplifies testing :-)
|
||||||
|
@ -104,7 +104,7 @@ public class CdsHooksContextBooter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String validateJson(String theExtension) {
|
protected String validateJson(String theExtension) {
|
||||||
if (StringUtils.isEmpty(theExtension)) {
|
if (StringUtils.isEmpty(theExtension)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,7 +33,6 @@ import ca.uhn.hapi.fhir.cdshooks.api.json.CdsServiceResponseSuggestionJson;
|
||||||
import ca.uhn.hapi.fhir.cdshooks.api.json.CdsServiceResponseSystemActionJson;
|
import ca.uhn.hapi.fhir.cdshooks.api.json.CdsServiceResponseSystemActionJson;
|
||||||
import org.hl7.fhir.dstu3.model.Bundle;
|
import org.hl7.fhir.dstu3.model.Bundle;
|
||||||
import org.hl7.fhir.dstu3.model.CarePlan;
|
import org.hl7.fhir.dstu3.model.CarePlan;
|
||||||
import org.hl7.fhir.dstu3.model.Endpoint;
|
|
||||||
import org.hl7.fhir.dstu3.model.Extension;
|
import org.hl7.fhir.dstu3.model.Extension;
|
||||||
import org.hl7.fhir.dstu3.model.IdType;
|
import org.hl7.fhir.dstu3.model.IdType;
|
||||||
import org.hl7.fhir.dstu3.model.ParameterDefinition;
|
import org.hl7.fhir.dstu3.model.ParameterDefinition;
|
||||||
|
@ -54,7 +53,6 @@ import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import static ca.uhn.hapi.fhir.cdshooks.svc.cr.CdsCrConstants.APPLY_PARAMETER_DATA;
|
import static ca.uhn.hapi.fhir.cdshooks.svc.cr.CdsCrConstants.APPLY_PARAMETER_DATA;
|
||||||
import static ca.uhn.hapi.fhir.cdshooks.svc.cr.CdsCrConstants.APPLY_PARAMETER_DATA_ENDPOINT;
|
|
||||||
import static ca.uhn.hapi.fhir.cdshooks.svc.cr.CdsCrConstants.APPLY_PARAMETER_ENCOUNTER;
|
import static ca.uhn.hapi.fhir.cdshooks.svc.cr.CdsCrConstants.APPLY_PARAMETER_ENCOUNTER;
|
||||||
import static ca.uhn.hapi.fhir.cdshooks.svc.cr.CdsCrConstants.APPLY_PARAMETER_PARAMETERS;
|
import static ca.uhn.hapi.fhir.cdshooks.svc.cr.CdsCrConstants.APPLY_PARAMETER_PARAMETERS;
|
||||||
import static ca.uhn.hapi.fhir.cdshooks.svc.cr.CdsCrConstants.APPLY_PARAMETER_PRACTITIONER;
|
import static ca.uhn.hapi.fhir.cdshooks.svc.cr.CdsCrConstants.APPLY_PARAMETER_PRACTITIONER;
|
||||||
|
@ -113,22 +111,6 @@ public class CdsCrServiceDstu3 implements ICdsCrService {
|
||||||
if (data.hasEntry()) {
|
if (data.hasEntry()) {
|
||||||
parameters.addParameter(part(APPLY_PARAMETER_DATA, data));
|
parameters.addParameter(part(APPLY_PARAMETER_DATA, data));
|
||||||
}
|
}
|
||||||
if (theJson.getFhirServer() != null) {
|
|
||||||
Endpoint endpoint = new Endpoint().setAddress(theJson.getFhirServer());
|
|
||||||
if (theJson.getServiceRequestAuthorizationJson().getAccessToken() != null) {
|
|
||||||
String tokenType = getTokenType(theJson.getServiceRequestAuthorizationJson());
|
|
||||||
endpoint.addHeader(String.format(
|
|
||||||
"Authorization: %s %s",
|
|
||||||
tokenType, theJson.getServiceRequestAuthorizationJson().getAccessToken()));
|
|
||||||
if (theJson.getServiceRequestAuthorizationJson().getSubject() != null) {
|
|
||||||
endpoint.addHeader(String.format(
|
|
||||||
"%s: %s",
|
|
||||||
myCdsConfigService.getCdsCrSettings().getClientIdHeaderName(),
|
|
||||||
theJson.getServiceRequestAuthorizationJson().getSubject()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
parameters.addParameter(part(APPLY_PARAMETER_DATA_ENDPOINT, endpoint));
|
|
||||||
}
|
|
||||||
return parameters;
|
return parameters;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -36,7 +36,6 @@ import ca.uhn.hapi.fhir.cdshooks.api.json.CdsServiceResponseSystemActionJson;
|
||||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
import org.hl7.fhir.r4.model.Bundle;
|
import org.hl7.fhir.r4.model.Bundle;
|
||||||
import org.hl7.fhir.r4.model.CanonicalType;
|
import org.hl7.fhir.r4.model.CanonicalType;
|
||||||
import org.hl7.fhir.r4.model.Endpoint;
|
|
||||||
import org.hl7.fhir.r4.model.Extension;
|
import org.hl7.fhir.r4.model.Extension;
|
||||||
import org.hl7.fhir.r4.model.IdType;
|
import org.hl7.fhir.r4.model.IdType;
|
||||||
import org.hl7.fhir.r4.model.ParameterDefinition;
|
import org.hl7.fhir.r4.model.ParameterDefinition;
|
||||||
|
@ -56,7 +55,6 @@ import java.util.Map;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import static ca.uhn.hapi.fhir.cdshooks.svc.cr.CdsCrConstants.APPLY_PARAMETER_DATA;
|
import static ca.uhn.hapi.fhir.cdshooks.svc.cr.CdsCrConstants.APPLY_PARAMETER_DATA;
|
||||||
import static ca.uhn.hapi.fhir.cdshooks.svc.cr.CdsCrConstants.APPLY_PARAMETER_DATA_ENDPOINT;
|
|
||||||
import static ca.uhn.hapi.fhir.cdshooks.svc.cr.CdsCrConstants.APPLY_PARAMETER_ENCOUNTER;
|
import static ca.uhn.hapi.fhir.cdshooks.svc.cr.CdsCrConstants.APPLY_PARAMETER_ENCOUNTER;
|
||||||
import static ca.uhn.hapi.fhir.cdshooks.svc.cr.CdsCrConstants.APPLY_PARAMETER_PARAMETERS;
|
import static ca.uhn.hapi.fhir.cdshooks.svc.cr.CdsCrConstants.APPLY_PARAMETER_PARAMETERS;
|
||||||
import static ca.uhn.hapi.fhir.cdshooks.svc.cr.CdsCrConstants.APPLY_PARAMETER_PRACTITIONER;
|
import static ca.uhn.hapi.fhir.cdshooks.svc.cr.CdsCrConstants.APPLY_PARAMETER_PRACTITIONER;
|
||||||
|
@ -115,22 +113,6 @@ public class CdsCrServiceR4 implements ICdsCrService {
|
||||||
if (data.hasEntry()) {
|
if (data.hasEntry()) {
|
||||||
parameters.addParameter(part(APPLY_PARAMETER_DATA, data));
|
parameters.addParameter(part(APPLY_PARAMETER_DATA, data));
|
||||||
}
|
}
|
||||||
if (theJson.getFhirServer() != null) {
|
|
||||||
Endpoint endpoint = new Endpoint().setAddress(theJson.getFhirServer());
|
|
||||||
if (theJson.getServiceRequestAuthorizationJson().getAccessToken() != null) {
|
|
||||||
String tokenType = getTokenType(theJson.getServiceRequestAuthorizationJson());
|
|
||||||
endpoint.addHeader(String.format(
|
|
||||||
"Authorization: %s %s",
|
|
||||||
tokenType, theJson.getServiceRequestAuthorizationJson().getAccessToken()));
|
|
||||||
if (theJson.getServiceRequestAuthorizationJson().getSubject() != null) {
|
|
||||||
endpoint.addHeader(String.format(
|
|
||||||
"%s: %s",
|
|
||||||
myCdsConfigService.getCdsCrSettings().getClientIdHeaderName(),
|
|
||||||
theJson.getServiceRequestAuthorizationJson().getSubject()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
parameters.addParameter(part(APPLY_PARAMETER_DATA_ENDPOINT, endpoint));
|
|
||||||
}
|
|
||||||
return parameters;
|
return parameters;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -36,7 +36,6 @@ import ca.uhn.hapi.fhir.cdshooks.api.json.CdsServiceResponseSystemActionJson;
|
||||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
import org.hl7.fhir.r5.model.Bundle;
|
import org.hl7.fhir.r5.model.Bundle;
|
||||||
import org.hl7.fhir.r5.model.CanonicalType;
|
import org.hl7.fhir.r5.model.CanonicalType;
|
||||||
import org.hl7.fhir.r5.model.Endpoint;
|
|
||||||
import org.hl7.fhir.r5.model.Extension;
|
import org.hl7.fhir.r5.model.Extension;
|
||||||
import org.hl7.fhir.r5.model.IdType;
|
import org.hl7.fhir.r5.model.IdType;
|
||||||
import org.hl7.fhir.r5.model.ParameterDefinition;
|
import org.hl7.fhir.r5.model.ParameterDefinition;
|
||||||
|
@ -56,7 +55,6 @@ import java.util.Map;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import static ca.uhn.hapi.fhir.cdshooks.svc.cr.CdsCrConstants.APPLY_PARAMETER_DATA;
|
import static ca.uhn.hapi.fhir.cdshooks.svc.cr.CdsCrConstants.APPLY_PARAMETER_DATA;
|
||||||
import static ca.uhn.hapi.fhir.cdshooks.svc.cr.CdsCrConstants.APPLY_PARAMETER_DATA_ENDPOINT;
|
|
||||||
import static ca.uhn.hapi.fhir.cdshooks.svc.cr.CdsCrConstants.APPLY_PARAMETER_ENCOUNTER;
|
import static ca.uhn.hapi.fhir.cdshooks.svc.cr.CdsCrConstants.APPLY_PARAMETER_ENCOUNTER;
|
||||||
import static ca.uhn.hapi.fhir.cdshooks.svc.cr.CdsCrConstants.APPLY_PARAMETER_PARAMETERS;
|
import static ca.uhn.hapi.fhir.cdshooks.svc.cr.CdsCrConstants.APPLY_PARAMETER_PARAMETERS;
|
||||||
import static ca.uhn.hapi.fhir.cdshooks.svc.cr.CdsCrConstants.APPLY_PARAMETER_PRACTITIONER;
|
import static ca.uhn.hapi.fhir.cdshooks.svc.cr.CdsCrConstants.APPLY_PARAMETER_PRACTITIONER;
|
||||||
|
@ -115,22 +113,6 @@ public class CdsCrServiceR5 implements ICdsCrService {
|
||||||
if (data.hasEntry()) {
|
if (data.hasEntry()) {
|
||||||
parameters.addParameter(part(APPLY_PARAMETER_DATA, data));
|
parameters.addParameter(part(APPLY_PARAMETER_DATA, data));
|
||||||
}
|
}
|
||||||
if (theJson.getFhirServer() != null) {
|
|
||||||
Endpoint endpoint = new Endpoint().setAddress(theJson.getFhirServer());
|
|
||||||
if (theJson.getServiceRequestAuthorizationJson().getAccessToken() != null) {
|
|
||||||
String tokenType = getTokenType(theJson.getServiceRequestAuthorizationJson());
|
|
||||||
endpoint.addHeader(String.format(
|
|
||||||
"Authorization: %s %s",
|
|
||||||
tokenType, theJson.getServiceRequestAuthorizationJson().getAccessToken()));
|
|
||||||
if (theJson.getServiceRequestAuthorizationJson().getSubject() != null) {
|
|
||||||
endpoint.addHeader(String.format(
|
|
||||||
"%s: %s",
|
|
||||||
myCdsConfigService.getCdsCrSettings().getClientIdHeaderName(),
|
|
||||||
theJson.getServiceRequestAuthorizationJson().getSubject()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
parameters.addParameter(part(APPLY_PARAMETER_DATA_ENDPOINT, endpoint));
|
|
||||||
}
|
|
||||||
return parameters;
|
return parameters;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -68,13 +68,13 @@ public class CrDiscoveryElementDstu3 implements ICrDiscoveryElement {
|
||||||
|| p.equals("Patient?_id=Patient/{{context.patientId}}"))) {
|
|| p.equals("Patient?_id=Patient/{{context.patientId}}"))) {
|
||||||
String key = getKey(++itemNo);
|
String key = getKey(++itemNo);
|
||||||
service.addPrefetch(key, "Patient?_id={{context.patientId}}");
|
service.addPrefetch(key, "Patient?_id={{context.patientId}}");
|
||||||
service.addSource(key, CdsResolutionStrategyEnum.SERVICE);
|
service.addSource(key, CdsResolutionStrategyEnum.FHIR_CLIENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (String item : myPrefetchUrlList) {
|
for (String item : myPrefetchUrlList) {
|
||||||
String key = getKey(++itemNo);
|
String key = getKey(++itemNo);
|
||||||
service.addPrefetch(key, item);
|
service.addPrefetch(key, item);
|
||||||
service.addSource(key, CdsResolutionStrategyEnum.SERVICE);
|
service.addSource(key, CdsResolutionStrategyEnum.FHIR_CLIENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
return service;
|
return service;
|
||||||
|
|
|
@ -68,13 +68,13 @@ public class CrDiscoveryElementR4 implements ICrDiscoveryElement {
|
||||||
|| p.equals("Patient?_id=Patient/{{context.patientId}}"))) {
|
|| p.equals("Patient?_id=Patient/{{context.patientId}}"))) {
|
||||||
String key = getKey(++itemNo);
|
String key = getKey(++itemNo);
|
||||||
service.addPrefetch(key, "Patient?_id={{context.patientId}}");
|
service.addPrefetch(key, "Patient?_id={{context.patientId}}");
|
||||||
service.addSource(key, CdsResolutionStrategyEnum.NONE);
|
service.addSource(key, CdsResolutionStrategyEnum.FHIR_CLIENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (String item : myPrefetchUrlList) {
|
for (String item : myPrefetchUrlList) {
|
||||||
String key = getKey(++itemNo);
|
String key = getKey(++itemNo);
|
||||||
service.addPrefetch(key, item);
|
service.addPrefetch(key, item);
|
||||||
service.addSource(key, CdsResolutionStrategyEnum.NONE);
|
service.addSource(key, CdsResolutionStrategyEnum.FHIR_CLIENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
return service;
|
return service;
|
||||||
|
|
|
@ -68,13 +68,13 @@ public class CrDiscoveryElementR5 implements ICrDiscoveryElement {
|
||||||
|| p.equals("Patient?_id=Patient/{{context.patientId}}"))) {
|
|| p.equals("Patient?_id=Patient/{{context.patientId}}"))) {
|
||||||
String key = getKey(++itemNo);
|
String key = getKey(++itemNo);
|
||||||
service.addPrefetch(key, "Patient?_id={{context.patientId}}");
|
service.addPrefetch(key, "Patient?_id={{context.patientId}}");
|
||||||
service.addSource(key, CdsResolutionStrategyEnum.SERVICE);
|
service.addSource(key, CdsResolutionStrategyEnum.FHIR_CLIENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (String item : myPrefetchUrlList) {
|
for (String item : myPrefetchUrlList) {
|
||||||
String key = getKey(++itemNo);
|
String key = getKey(++itemNo);
|
||||||
service.addPrefetch(key, item);
|
service.addPrefetch(key, item);
|
||||||
service.addSource(key, CdsResolutionStrategyEnum.SERVICE);
|
service.addSource(key, CdsResolutionStrategyEnum.FHIR_CLIENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
return service;
|
return service;
|
||||||
|
|
|
@ -27,7 +27,6 @@ import ca.uhn.hapi.fhir.cdshooks.api.ICdsHooksDaoAuthorizationSvc;
|
||||||
import ca.uhn.hapi.fhir.cdshooks.api.ICdsServiceMethod;
|
import ca.uhn.hapi.fhir.cdshooks.api.ICdsServiceMethod;
|
||||||
import ca.uhn.hapi.fhir.cdshooks.api.json.CdsServiceJson;
|
import ca.uhn.hapi.fhir.cdshooks.api.json.CdsServiceJson;
|
||||||
import ca.uhn.hapi.fhir.cdshooks.api.json.CdsServiceRequestJson;
|
import ca.uhn.hapi.fhir.cdshooks.api.json.CdsServiceRequestJson;
|
||||||
import ca.uhn.hapi.fhir.cdshooks.svc.CdsCrServiceMethod;
|
|
||||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
@ -57,11 +56,6 @@ public class CdsPrefetchSvc {
|
||||||
|
|
||||||
public void augmentRequest(CdsServiceRequestJson theCdsServiceRequestJson, ICdsServiceMethod theServiceMethod) {
|
public void augmentRequest(CdsServiceRequestJson theCdsServiceRequestJson, ICdsServiceMethod theServiceMethod) {
|
||||||
CdsServiceJson serviceSpec = theServiceMethod.getCdsServiceJson();
|
CdsServiceJson serviceSpec = theServiceMethod.getCdsServiceJson();
|
||||||
if (theServiceMethod instanceof CdsCrServiceMethod) {
|
|
||||||
// CdsCrServices will retrieve data from the dao or fhir server passed in as needed,
|
|
||||||
// checking for missing prefetch is not necessary.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Set<String> missingPrefetch = findMissingPrefetch(serviceSpec, theCdsServiceRequestJson);
|
Set<String> missingPrefetch = findMissingPrefetch(serviceSpec, theCdsServiceRequestJson);
|
||||||
if (missingPrefetch.isEmpty()) {
|
if (missingPrefetch.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -47,7 +47,7 @@ public class CdsCrServiceR4Test extends BaseCrTest {
|
||||||
requestDetails.setId(planDefinitionId);
|
requestDetails.setId(planDefinitionId);
|
||||||
final Parameters params = new CdsCrServiceR4(requestDetails, repository, myCdsConfigService).encodeParams(cdsServiceRequestJson);
|
final Parameters params = new CdsCrServiceR4(requestDetails, repository, myCdsConfigService).encodeParams(cdsServiceRequestJson);
|
||||||
|
|
||||||
assertTrue(params.getParameter().size() == 3);
|
assertTrue(params.getParameter().size() == 2);
|
||||||
assertTrue(params.getParameter("parameters").hasResource());
|
assertTrue(params.getParameter("parameters").hasResource());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue