Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NIAD-2873: Change how we query the persist duration from SDS #330

Merged
merged 5 commits into from
Oct 16, 2023
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -19,21 +19,23 @@
public class SdsRequestBuilder {

private static final String ROUTING_AND_READABILITY_ENDPOINT = "/Endpoint";
private static final String ACCREDITED_SYSTEMS_INFORMATION_DEVICE_ENDPOINT = "/Device";
private static final String IDENTIFIER_HEADER = "identifier";
private static final String INTERACTION_ID_IDENTIFIER =
"https://fhir.nhs.uk/Id/nhsServiceInteractionId|urn:nhs:names:services:gp2gp:";
private static final String ORGANISATION_HEADER = "organization";
private static final String ORGANISATION_CODE_IDENTIFIER = "https://fhir.nhs.uk/Id/ods-organization-code|";
private static final String NHS_MHS_PARTY_KEY_URL = "https://fhir.nhs.uk/Id/nhsMhsPartyKey|";
private static final String CORRELATION_ID = "X-Correlation-Id";
private static final String API_KEY_HEADER = "apikey";

private final RequestBuilderService requestBuilderService;
private final SdsConfiguration sdsConfiguration;

public WebClient.RequestHeadersSpec<?> buildGetRequest(String messageType, String odsCode, String conversationId) {
SslContext sslContext = requestBuilderService.buildSSLContext();
HttpClient httpClient = HttpClient.create().secure(t -> t.sslContext(sslContext));
WebClient client = buildWebClient(httpClient);
public WebClient.RequestHeadersSpec<?> buildEndpointGetRequestWithIdentifierAndOrgParams(String messageType,
String odsCode,
String conversationId) {
WebClient client = fetchWebClient();

WebClient.RequestBodySpec uri = client.method(GET).uri(
uriBuilder -> uriBuilder
Expand All @@ -49,6 +51,49 @@ public WebClient.RequestHeadersSpec<?> buildGetRequest(String messageType, Strin
.header(API_KEY_HEADER, sdsConfiguration.getApikey());
}

public WebClient.RequestHeadersSpec<?> buildEndpointGetRequestWithDoubleIdentifierParams(String messageType,
String nhsMhsPartyKey,
String conversationId) {
WebClient client = fetchWebClient();

WebClient.RequestBodySpec uri = client.method(GET).uri(
uriBuilder -> uriBuilder
.path(ROUTING_AND_READABILITY_ENDPOINT)
.queryParam(IDENTIFIER_HEADER, INTERACTION_ID_IDENTIFIER.concat(messageType))
.queryParam(IDENTIFIER_HEADER, NHS_MHS_PARTY_KEY_URL.concat(nhsMhsPartyKey))
.build()
);

return uri
.accept(APPLICATION_JSON)
.header(CORRELATION_ID, conversationId)
.header(API_KEY_HEADER, sdsConfiguration.getApikey());
}

public WebClient.RequestHeadersSpec<?> buildDeviceGetRequest(String messageType, String odsCode, String conversationId) {
WebClient client = fetchWebClient();

WebClient.RequestBodySpec uri = client.method(GET).uri(
uriBuilder -> uriBuilder
.path(ACCREDITED_SYSTEMS_INFORMATION_DEVICE_ENDPOINT)
.queryParam(IDENTIFIER_HEADER, INTERACTION_ID_IDENTIFIER.concat(messageType))
.queryParam(ORGANISATION_HEADER, ORGANISATION_CODE_IDENTIFIER.concat(odsCode))
.build()
);

return uri
.accept(APPLICATION_JSON)
.header(CORRELATION_ID, conversationId)
.header(API_KEY_HEADER, sdsConfiguration.getApikey());
}

private WebClient fetchWebClient() {
SslContext sslContext = requestBuilderService.buildSSLContext();
HttpClient httpClient = HttpClient.create().secure(t -> t.sslContext(sslContext));
return buildWebClient(httpClient);
}


private WebClient buildWebClient(HttpClient httpClient) {
return WebClient
.builder()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@

import org.hl7.fhir.dstu3.model.Bundle;
import org.hl7.fhir.dstu3.model.Extension;
import org.hl7.fhir.dstu3.model.Identifier;
import org.hl7.fhir.dstu3.model.Property;
import org.hl7.fhir.dstu3.model.Resource;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.client.WebClientResponseException;
Expand All @@ -25,51 +27,62 @@
public class SDSService {

private static final String EXTENSION_KEY_VALUE = "extension";
private static final String IDENTIFIER_KEY_VALUE = "identifier";
private static final String PERSIST_DURATION_URL = "nhsMHSPersistDuration";
private static final String NHS_MHS_PARTY_KEY_URL = "https://fhir.nhs.uk/Id/nhsMhsPartyKey";

private final SdsRequestBuilder requestBuilder;
private final SdsClientService sdsClientService;
private final FhirParser fhirParser;

public Duration getPersistDurationFor(String messageType, String odsCode, String conversationId) throws SdsRetrievalException {

String sdsResponse = getResponseFromSds(messageType, odsCode, conversationId);
String sdsResponseWithNhsMhsPartyKey = getNhsMhsPartyKeyFromSds(messageType, odsCode, conversationId);
String nhsMhsPartyKey = parseNhsMhsPartyKey(sdsResponseWithNhsMhsPartyKey);
String sdsResponse = getResponseFromSds(messageType, nhsMhsPartyKey, conversationId);
Duration duration = parsePersistDuration(sdsResponse);

LOGGER.debug("Retrieved persist duration of [{}] for odscode [{}] and messageType [{}]", duration, odsCode, messageType);
return duration;
}

private String getResponseFromSds(String messageType, String odsCode, String conversationId) throws SdsRetrievalException {
var request = requestBuilder.buildGetRequest(messageType, odsCode, conversationId);
public String parseNhsMhsPartyKey(String sdsResponse) throws SdsRetrievalException {

Property identifierChildren = getResourceSubelement(sdsResponse, IDENTIFIER_KEY_VALUE);
return identifierChildren.getValues()
.stream()
.map(Identifier.class::cast)
.filter(identifierChild -> NHS_MHS_PARTY_KEY_URL.equals(identifierChild.getSystem()))
.findFirst()
.map(Identifier::getValue).get();
}

private String getNhsMhsPartyKeyFromSds(String messageType, String odsCode, String conversationId) {

var request = requestBuilder.buildDeviceGetRequest(messageType, odsCode, conversationId);

try {
return sdsClientService.send(request);
} catch (WebClientResponseException e) {
LOGGER.error("Received an ERROR response from SDS: [{}]", e.getMessage());
throw new SdsRetrievalException(String.format("Error getting messageType [%s] info from SDS", messageType));
}
}

private Duration parsePersistDuration(String sdsResponse) throws SdsRetrievalException {
}

Bundle bundle;
private String getResponseFromSds(String messageType, String nhsMhsPartyKey, String conversationId) throws SdsRetrievalException {
var request = requestBuilder.buildEndpointGetRequestWithDoubleIdentifierParams(messageType, nhsMhsPartyKey, conversationId);

try {
bundle = fhirParser.parseResource(sdsResponse, Bundle.class);
} catch (FhirValidationException e) {
throw new SdsRetrievalException(e.getMessage());
return sdsClientService.send(request);
} catch (WebClientResponseException e) {
LOGGER.error("Received an ERROR response from SDS: [{}]", e.getMessage());
throw new SdsRetrievalException(String.format("Error getting messageType [%s] info from SDS", messageType));
}
}

List<Bundle.BundleEntryComponent> entries = bundle.getEntry();

if (entries.isEmpty()) {
throw new SdsRetrievalException("sds response doesn't contain any results");
}
private Duration parsePersistDuration(String sdsResponse) throws SdsRetrievalException {

Resource resource = entries.get(0).getResource();
Property matchingChildren = resource.getChildByName(EXTENSION_KEY_VALUE);
Optional<Extension> extensions = matchingChildren.getValues().stream().map(child -> (Extension) child).findFirst();
Optional<Extension> extensions = getExtensions(sdsResponse);

Optional<Extension> persistDuration = extensions
.orElseThrow(() -> new SdsRetrievalException("Error parsing persist duration extension"))
Expand All @@ -83,4 +96,29 @@ private Duration parsePersistDuration(String sdsResponse) throws SdsRetrievalExc

return Duration.parse(isoDuration);
}

@NotNull
private Optional<Extension> getExtensions(String sdsResponse) {
Property matchingChildren = getResourceSubelement(sdsResponse, EXTENSION_KEY_VALUE);
return matchingChildren.getValues().stream().map(Extension.class::cast).findFirst();
}

private Property getResourceSubelement(String sdsResponse, String resourceSubelement) {
Bundle bundle;

try {
bundle = fhirParser.parseResource(sdsResponse, Bundle.class);
} catch (FhirValidationException e) {
throw new SdsRetrievalException(e.getMessage());
}

List<Bundle.BundleEntryComponent> entries = bundle.getEntry();

if (entries.isEmpty()) {
throw new SdsRetrievalException("sds response doesn't contain any results");
}

Resource resource = entries.get(0).getResource();
return resource.getChildByName(resourceSubelement);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,16 @@ public void When_GetPersistDurationFor_WhenEHRExtractValidInput_Expect_CorrectDu
assertEquals(EHR_DURATION, parsedDuration);
}

@Test
public void When_GetNhsMhsPartyKey_WhenEHRExtractValidInput_Expect_CorrectNhsMhsPartyKey() {

when(fhirParser.parseResource(any(), eq(Bundle.class))).thenReturn(ehrResponseBundle);

String nhsMhsPartyKey = sdsService.parseNhsMhsPartyKey(sdsResponseEHRExtract);

assertEquals("P83007-822482", nhsMhsPartyKey);
}

@Test
public void When_GetPersistDurationFor_WhenCOPCValidInput_Expect_CorrectDuration() {
when(sdsClientService.send(any())).thenReturn(sdsResponseCopcMessage);
Expand Down