Skip to content

Commit

Permalink
NIAD-2873: changing the way how we querying SDS service (#330)
Browse files Browse the repository at this point in the history
* changing the way how we querying SDS service

* checkstyle fix

* removal of unnecessary comment

* endpoint param correction
  • Loading branch information
hospel authored Oct 16, 2023
1 parent 662a1b1 commit e9e85fc
Show file tree
Hide file tree
Showing 3 changed files with 115 additions and 22 deletions.
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

0 comments on commit e9e85fc

Please sign in to comment.