Skip to content

Commit 3c76753

Browse files
authored
NIAD-3004 - Introduce a feature flag which generates "RCMR_IN030000UK07" messages from GP2GP adaptor (#792)
* [NIAD-3004] Add schemas to MiM * [NIAD-3004] Add initial tests * [NIAD-3004] Refactor OutputMessageWrapperMapper, OutputMessageWrapperTemplateParameters and output_message_wrapper_template.mustache to support both interactions * [NIAD-3004] Enhance tests * [NIAD-3004] Add flag to application.yml * [NIAD-3004] Renamed environment variable for flag within application.yml * [NIAD-3004] Address checkstyle violations * [NIAD-3004] Update CHANGELOG.md * [NIAD-3004] Add redactions feature flag to application.yml * [NIAD-3004] Addressed PR comment #792 (comment) * [NIAD-3004] Address PR comment #792 (comment) * [NIAD-3004] Address PR comment #792 (comment)
1 parent efa1200 commit 3c76753

File tree

14 files changed

+1976
-25
lines changed

14 files changed

+1976
-25
lines changed

service/src/intTest/resources/application.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ management:
1414
include: info, health, metrics
1515

1616
gp2gp:
17+
redactions-enabled: ${GP2GP_REDACTIONS_ENABLED:false}
1718
largeAttachmentThreshold: ${GP2GP_LARGE_ATTACHMENT_THRESHOLD:4500000} # value in bytes. Default value for Spine is ~4.5MB
1819
largeEhrExtractThreshold: ${GP2GP_LARGE_ATTACHMENT_THRESHOLD:4500000}
1920
storage:
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package uk.nhs.adaptors.gp2gp.common.configuration;
2+
3+
import org.springframework.beans.factory.annotation.Value;
4+
import org.springframework.context.annotation.Bean;
5+
import org.springframework.context.annotation.Configuration;
6+
7+
@Configuration
8+
class RedactionsConfiguration {
9+
private static final String EHR_EXTRACT_INTERACTION_ID = "RCMR_IN030000UK06";
10+
private static final String EHR_EXTRACT_INTERACTION_ID_WITH_REDACTIONS = "RCMR_IN030000UK07";
11+
private boolean redactionsEnabled;
12+
13+
@Value("${gp2gp.redactions-enabled}")
14+
protected void setRedactionsEnabled(boolean redactionsEnabled) {
15+
this.redactionsEnabled = redactionsEnabled;
16+
}
17+
18+
@Bean
19+
RedactionsContext redactionsContext() {
20+
final String ehrExtractInteractionId = redactionsEnabled
21+
? EHR_EXTRACT_INTERACTION_ID_WITH_REDACTIONS
22+
: EHR_EXTRACT_INTERACTION_ID;
23+
24+
return new RedactionsContext(ehrExtractInteractionId);
25+
}
26+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package uk.nhs.adaptors.gp2gp.common.configuration;
2+
3+
public record RedactionsContext(
4+
String ehrExtractInteractionId
5+
) { }
Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
package uk.nhs.adaptors.gp2gp.ehr.mapper;
22

3+
import lombok.RequiredArgsConstructor;
4+
35
import org.springframework.beans.factory.annotation.Autowired;
46
import org.springframework.stereotype.Component;
57

68
import com.github.mustachejava.Mustache;
79

8-
import lombok.RequiredArgsConstructor;
10+
import uk.nhs.adaptors.gp2gp.common.configuration.RedactionsContext;
911
import uk.nhs.adaptors.gp2gp.common.service.RandomIdGeneratorService;
1012
import uk.nhs.adaptors.gp2gp.common.service.TimestampService;
1113
import uk.nhs.adaptors.gp2gp.ehr.mapper.parameters.OutputMessageWrapperTemplateParameters;
@@ -14,14 +16,18 @@
1416
import uk.nhs.adaptors.gp2gp.gpc.GetGpcStructuredTaskDefinition;
1517

1618
@Component
17-
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
19+
@RequiredArgsConstructor(onConstructor_ = @__(@Autowired))
1820
public class OutputMessageWrapperMapper {
1921
private static final Mustache TEMPLATE = TemplateUtils.loadTemplate("output_message_wrapper_template.mustache");
22+
2023
private final RandomIdGeneratorService randomIdGeneratorService;
2124
private final TimestampService timestampService;
25+
private final RedactionsContext redactionsContext;
2226

2327
public String map(GetGpcStructuredTaskDefinition getGpcDocumentTaskDefinition, String ehrExtractContent) {
24-
OutputMessageWrapperTemplateParameters outputMessageWrapperTemplateParameters = OutputMessageWrapperTemplateParameters.builder()
28+
final OutputMessageWrapperTemplateParameters outputMessageWrapperTemplateParameters = OutputMessageWrapperTemplateParameters
29+
.builder()
30+
.interactionId(redactionsContext.ehrExtractInteractionId())
2531
.eventId(randomIdGeneratorService.createNewId())
2632
.creationTime(DateFormatUtil.toHl7Format(timestampService.now()))
2733
.fromAsid(getGpcDocumentTaskDefinition.getFromAsid())
@@ -31,4 +37,4 @@ public String map(GetGpcStructuredTaskDefinition getGpcDocumentTaskDefinition, S
3137

3238
return TemplateUtils.fillTemplate(TEMPLATE, outputMessageWrapperTemplateParameters);
3339
}
34-
}
40+
}

service/src/main/java/uk/nhs/adaptors/gp2gp/ehr/mapper/parameters/OutputMessageWrapperTemplateParameters.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
@Data
77
@Builder
88
public class OutputMessageWrapperTemplateParameters {
9+
private String interactionId;
910
private String eventId;
1011
private String creationTime;
1112
private String fromAsid;

service/src/main/java/uk/nhs/adaptors/gp2gp/mhs/MhsRequestBuilder.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import lombok.RequiredArgsConstructor;
2121
import lombok.extern.slf4j.Slf4j;
2222
import reactor.netty.http.client.HttpClient;
23+
import uk.nhs.adaptors.gp2gp.common.configuration.RedactionsContext;
2324
import uk.nhs.adaptors.gp2gp.common.service.RequestBuilderService;
2425
import uk.nhs.adaptors.gp2gp.common.service.WebClientFilterService;
2526
import uk.nhs.adaptors.gp2gp.mhs.configuration.MhsClientConfiguration;
@@ -31,7 +32,6 @@
3132
public class MhsRequestBuilder {
3233
private static final String ODS_CODE = "ods-code";
3334
private static final String INTERACTION_ID = "Interaction-Id";
34-
private static final String MHS_OUTBOUND_EXTRACT_CORE_INTERACTION_ID = "RCMR_IN030000UK06";
3535
private static final String CORRELATION_ID = "Correlation-Id";
3636
private static final String WAIT_FOR_RESPONSE = "wait-for-response";
3737
private static final String FALSE = "false";
@@ -43,10 +43,11 @@ public class MhsRequestBuilder {
4343
private final MhsConfiguration mhsConfiguration;
4444
private final RequestBuilderService requestBuilderService;
4545
private final MhsClientConfiguration mhsClientConfig;
46+
private final RedactionsContext redactionsContext;
4647

4748
public RequestHeadersSpec<?> buildSendEhrExtractCoreRequest(
4849
String extractCoreMessage, String conversationId, String fromOdsCode, String messageId) {
49-
return buildRequest(extractCoreMessage, fromOdsCode, conversationId, MHS_OUTBOUND_EXTRACT_CORE_INTERACTION_ID, messageId);
50+
return buildRequest(extractCoreMessage, fromOdsCode, conversationId, redactionsContext.ehrExtractInteractionId(), messageId);
5051
}
5152

5253
public RequestHeadersSpec<?> buildSendAcknowledgementRequest(
@@ -102,4 +103,4 @@ private WebClient buildWebClient(HttpClient httpClient) {
102103
.defaultUriVariables(Collections.singletonMap("url", mhsConfiguration.getUrl()))
103104
.build();
104105
}
105-
}
106+
}

service/src/main/resources/application.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ management:
1010
include: info, health, metrics, mappings
1111

1212
gp2gp:
13+
redactions-enabled: ${GP2GP_REDACTIONS_ENABLED:false}
1314
largeAttachmentThreshold: ${GP2GP_LARGE_ATTACHMENT_THRESHOLD:4500000} # value in bytes. Default value for Spine is ~4.5MB
1415
largeEhrExtractThreshold: ${GP2GP_LARGE_EHR_EXTRACT_THRESHOLD:4500000}
1516
storage:

service/src/main/resources/templates/output_message_wrapper_template.mustache

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
<?xml version="1.0" encoding="UTF-8"?>
2-
<RCMR_IN030000UK06 xmlns="urn:hl7-org:v3" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:hl7-org:v3 ..\Schemas\RCMR_IN030000UK06.xsd">
2+
<{{interactionId}} xmlns="urn:hl7-org:v3" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:hl7-org:v3 ..\Schemas\{{interactionId}}.xsd">
33
<id root="{{eventId}}" />
44
<creationTime value="{{creationTime}}" />
55
<versionCode code="V3NPfIT3.1.10" />
6-
<interactionId root="2.16.840.1.113883.2.1.3.2.4.12" extension="RCMR_IN030000UK06" />
6+
<interactionId root="2.16.840.1.113883.2.1.3.2.4.12" extension="{{interactionId}}" />
77
<processingCode code="P" />
88
<processingModeCode code="T" />
99
<acceptAckCode code="NE" />
@@ -29,4 +29,4 @@
2929
{{{ehrExtractContent}}}
3030
</subject>
3131
</ControlActEvent>
32-
</RCMR_IN030000UK06>
32+
</{{interactionId}}>
Lines changed: 45 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package uk.nhs.adaptors.gp2gp.ehr.mapper;
22

33
import static org.assertj.core.api.Assertions.assertThat;
4+
import static org.junit.jupiter.api.Assertions.assertAll;
45
import static org.mockito.Mockito.when;
56

67
import java.io.IOException;
@@ -9,53 +10,83 @@
910
import org.junit.jupiter.api.BeforeEach;
1011
import org.junit.jupiter.api.Test;
1112
import org.junit.jupiter.api.extension.ExtendWith;
13+
import org.mockito.InjectMocks;
1214
import org.mockito.Mock;
1315
import org.mockito.junit.jupiter.MockitoExtension;
1416

17+
import uk.nhs.adaptors.gp2gp.common.configuration.RedactionsContext;
1518
import uk.nhs.adaptors.gp2gp.common.service.RandomIdGeneratorService;
1619
import uk.nhs.adaptors.gp2gp.common.service.TimestampService;
1720
import uk.nhs.adaptors.gp2gp.gpc.GetGpcStructuredTaskDefinition;
1821
import uk.nhs.adaptors.gp2gp.utils.ResourceTestFileUtils;
1922

2023
@ExtendWith(MockitoExtension.class)
21-
public class OutputMessageWrapperMapperTest {
24+
class OutputMessageWrapperMapperTest {
2225
private static final String TEST_ID = "394559384658936";
2326
private static final String TEST_DATE_TIME = "2020-02-18T17:09:46.01Z";
24-
private static final String EXPECTED_OUTPUT_MESSAGE_WRAPPER_XML = "/ehr/mapper/expected-output-message-wrapper.xml";
27+
private static final String EHR_EXTRACT_INTERACTION_ID_NO_REDACTIONS = "RCMR_IN030000UK06";
28+
private static final String EHR_EXTRACT_INTERACTION_ID_WITH_REDACTIONS = "RCMR_IN030000UK07";
29+
private static final String EXPECTED_OUTPUT_MESSAGE_WRAPPER_NO_REDACTIONS_XML
30+
= "/ehr/mapper/expected-output-message-wrapper-no-redactions.xml";
31+
private static final String EXPECTED_OUTPUT_MESSAGE_WRAPPER_WITH_REDACTIONS_XML
32+
= "/ehr/mapper/expected-output-message-wrapper-redactions.xml";
2533
private static final String TRANSFORMED_EXTRACT = "<EhrExtract classCode=\"EXTRACT\" moodCode=\"EVN\"><id "
2634
+ "root=\"12345\"/></EhrExtract>";
2735
private static final String TO_ASID_VALUE = "to-asid-value";
2836
private static final String FROM_ASID_VALUE = "from-asid-value";
2937

3038
@Mock
3139
private RandomIdGeneratorService randomIdGeneratorService;
40+
3241
@Mock
3342
private TimestampService timestampService;
3443

44+
@Mock
45+
private RedactionsContext redactionsContext;
46+
47+
@InjectMocks
3548
private OutputMessageWrapperMapper outputMessageWrapperMapper;
36-
private GetGpcStructuredTaskDefinition getGpcStructuredTaskDefinition;
37-
private CharSequence expectedOutputMessage;
49+
50+
private GetGpcStructuredTaskDefinition gpcStructuredTaskDefinition;
3851

3952
@BeforeEach
40-
public void setUp() throws IOException {
53+
void setUp() throws IOException {
4154
when(randomIdGeneratorService.createNewId()).thenReturn(TEST_ID);
4255
when(timestampService.now()).thenReturn(Instant.parse(TEST_DATE_TIME));
43-
outputMessageWrapperMapper = new OutputMessageWrapperMapper(randomIdGeneratorService, timestampService);
4456

45-
getGpcStructuredTaskDefinition = GetGpcStructuredTaskDefinition.builder()
57+
gpcStructuredTaskDefinition = GetGpcStructuredTaskDefinition.builder()
4658
.toAsid(TO_ASID_VALUE)
4759
.fromAsid(FROM_ASID_VALUE)
4860
.build();
61+
}
4962

50-
expectedOutputMessage = ResourceTestFileUtils.getFileContent(EXPECTED_OUTPUT_MESSAGE_WRAPPER_XML);
63+
@Test
64+
void When_MappingOutputMessageWrapperWithStringContentAndRedactionsDisabled_Expect_UK06InteractionIdToBePresentAndProperXmlOutput() {
65+
final String expected = ResourceTestFileUtils.getFileContent(EXPECTED_OUTPUT_MESSAGE_WRAPPER_NO_REDACTIONS_XML);
66+
67+
when(redactionsContext.ehrExtractInteractionId()).thenReturn(EHR_EXTRACT_INTERACTION_ID_NO_REDACTIONS);
68+
69+
final String actual = outputMessageWrapperMapper.map(gpcStructuredTaskDefinition, TRANSFORMED_EXTRACT);
70+
71+
assertAll(
72+
() -> assertThat(actual).isEqualToIgnoringWhitespace(expected),
73+
() -> assertThat(actual).contains(EHR_EXTRACT_INTERACTION_ID_NO_REDACTIONS),
74+
() -> assertThat(actual).doesNotContain(EHR_EXTRACT_INTERACTION_ID_WITH_REDACTIONS)
75+
);
5176
}
5277

5378
@Test
54-
public void When_MappingOutputMessageWrapperWithStringContent_Expect_ProperXmlOutput() {
55-
String outputMessage = outputMessageWrapperMapper.map(
56-
getGpcStructuredTaskDefinition,
57-
TRANSFORMED_EXTRACT);
79+
void When_MappingOutputMessageWrapperWithStringContentAndRedactionsEnabled_Expect_UK07InteractionIdToBePresentAndProperXmlOutput() {
80+
final String expected = ResourceTestFileUtils.getFileContent(EXPECTED_OUTPUT_MESSAGE_WRAPPER_WITH_REDACTIONS_XML);
81+
82+
when(redactionsContext.ehrExtractInteractionId()).thenReturn(EHR_EXTRACT_INTERACTION_ID_WITH_REDACTIONS);
83+
84+
final String actual = outputMessageWrapperMapper.map(gpcStructuredTaskDefinition, TRANSFORMED_EXTRACT);
5885

59-
assertThat(outputMessage).isEqualToIgnoringWhitespace(expectedOutputMessage);
86+
assertAll(
87+
() -> assertThat(actual).isEqualToIgnoringWhitespace(expected),
88+
() -> assertThat(actual).contains(EHR_EXTRACT_INTERACTION_ID_WITH_REDACTIONS),
89+
() -> assertThat(actual).doesNotContain(EHR_EXTRACT_INTERACTION_ID_NO_REDACTIONS)
90+
);
6091
}
61-
}
92+
}

service/src/test/java/uk/nhs/adaptors/gp2gp/uat/EhrExtractUATTest.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
import org.w3c.dom.NodeList;
1515
import org.xml.sax.SAXException;
1616
import uk.nhs.adaptors.gp2gp.RandomIdGeneratorServiceStub;
17+
import uk.nhs.adaptors.gp2gp.common.configuration.RedactionsContext;
1718
import uk.nhs.adaptors.gp2gp.common.service.FhirParseService;
1819
import uk.nhs.adaptors.gp2gp.common.service.RandomIdGeneratorService;
1920
import uk.nhs.adaptors.gp2gp.common.service.TimestampService;
@@ -79,6 +80,7 @@ public class EhrExtractUATTest {
7980

8081
private EhrExtractMapper ehrExtractMapper;
8182
private MessageContext messageContext;
83+
private RedactionsContext redactionsContext;
8284
private OutputMessageWrapperMapper outputMessageWrapperMapper;
8385
private GetGpcStructuredTaskDefinition getGpcStructuredTaskDefinition;
8486

@@ -131,7 +133,7 @@ public void setUp() {
131133
final RandomIdGeneratorService randomIdGeneratorService = new RandomIdGeneratorServiceStub();
132134
when(timestampService.now()).thenReturn(Instant.parse("2020-01-01T01:01:01.01Z"));
133135

134-
outputMessageWrapperMapper = new OutputMessageWrapperMapper(randomIdGeneratorService, timestampService);
136+
outputMessageWrapperMapper = new OutputMessageWrapperMapper(randomIdGeneratorService, timestampService, redactionsContext);
135137
messageContext = new MessageContext(randomIdGeneratorService);
136138

137139
CodeableConceptCdMapper codeableConceptCdMapper = new CodeableConceptCdMapper();

0 commit comments

Comments
 (0)