Skip to content

Commit 9d2fa84

Browse files
NIAD-3430: Adaptor is incorrectly failing schema validation for UK06 messages when the outgoing message is UK07 (#1450)
* NIAD-3430 Adaptor is incorrectly failing schema validation for UK06 messages when the outgoing message is UK07 * Changelog
1 parent f59fd08 commit 9d2fa84

14 files changed

Lines changed: 6540 additions & 14 deletions

File tree

CHANGELOG.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ All notable changes to this project will be documented in this file.
44
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
55
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
66

7+
## Unreleased
8+
* The GP2GP Adaptor will no longer incorrectly fail schema validation.
9+
710
## [3.0.0] - 2025-11-06
811

912
### Added
@@ -12,7 +15,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1215
* The GP2GP Adaptor now populates the ObservationStatement / confidentialityCode field when the .meta.security field of an Uncategorized Data Observation contains NOPAT
1316
* When List.meta.security field contains NOPAT, the GP2GP Adaptor will now populate the CompoundStatement.confidentialityCode
1417
* The GP2GP Adaptor now throws an exception when the Access Structure Record is empty, thereby rejecting the transfer
15-
* The GP2GP Adaptor now throws an exception when the XML is not valid, thereby stopping the transfer from going forward
1618

1719
### Fixed
1820
* When DiagnosticReport doesn't contain a Specimen or Observation reference, instead of "DUMMY" "NOT-PRESENT" value is used

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

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,9 @@
2727

2828
import javax.xml.validation.Schema;
2929
import javax.xml.validation.SchemaFactory;
30-
import javax.xml.validation.Validator;
3130
import javax.xml.transform.stream.StreamSource;
3231
import org.xml.sax.SAXException;
3332

34-
import java.io.File;
3533
import java.io.IOException;
3634
import java.io.StringReader;
3735
import java.util.List;
@@ -46,10 +44,6 @@ public class EhrExtractMapper {
4644
private static final Mustache EHR_EXTRACT_TEMPLATE = TemplateUtils.loadTemplate("ehr_extract_template.mustache");
4745
private static final Mustache SKELETON_COMPONENT_TEMPLATE = TemplateUtils.loadTemplate("ehr_skeleton_component_template.mustache");
4846
private static final String CONSULTATION_LIST_CODE = "325851000000107";
49-
private static final String SCHEMA_PATH = "../service/src/test/resources/mim/Schemas/";
50-
51-
private static final String RCMR_IN030000UK06_SCHEMA_PATH = SCHEMA_PATH + RedactionsContext.NON_REDACTION_INTERACTION_ID + ".xsd";
52-
private static final String RCMR_IN030000UK07_SCHEMA_PATH = SCHEMA_PATH + RedactionsContext.REDACTION_INTERACTION_ID + ".xsd";
5347

5448
private final RandomIdGeneratorService randomIdGeneratorService;
5549
private final TimestampService timestampService;
@@ -67,19 +61,25 @@ public String mapEhrExtractToXml(EhrExtractTemplateParameters ehrExtractTemplate
6761

6862
public void validateXmlAgainstSchema(String xml) {
6963
String interactionId = redactionsContext.ehrExtractInteractionId();
70-
boolean isRedactionInteraction = RedactionsContext.REDACTION_INTERACTION_ID.equals(interactionId);
64+
boolean isRedaction = RedactionsContext.REDACTION_INTERACTION_ID.equals(interactionId);
65+
66+
String schemaId = isRedaction
67+
? RedactionsContext.REDACTION_INTERACTION_ID
68+
: RedactionsContext.NON_REDACTION_INTERACTION_ID;
69+
70+
String schemaFile = "mim/Schemas/" + schemaId + ".xsd";
7171

72-
String schemaPath = isRedactionInteraction ? RCMR_IN030000UK07_SCHEMA_PATH : RCMR_IN030000UK06_SCHEMA_PATH;
7372
try {
73+
var resource = getClass().getClassLoader().getResource(schemaFile);
74+
7475
SchemaFactory factory = SchemaFactory.newDefaultInstance();
75-
Schema schema = factory.newSchema(new File(schemaPath));
76-
Validator validator = schema.newValidator();
76+
Schema schema = factory.newSchema(new StreamSource(resource.openStream(), resource.toExternalForm()));
77+
schema.newValidator().validate(new StreamSource(new StringReader(xml)));
7778

78-
validator.validate(new StreamSource(new StringReader(xml)));
79+
LOGGER.info("XML successfully validated against schema: {}", schemaFile);
7980

80-
LOGGER.info("XML successfully validated against schema: {}", schemaPath);
8181
} catch (SAXException | IOException e) {
82-
LOGGER.error("XML validation failed against schema {}: {}", schemaPath, e.getMessage(), e);
82+
LOGGER.error("XML validation failed against schema {}: {}", schemaFile, e.getMessage(), e);
8383
throw new XmlSchemaValidationException("XML schema validation failed", e);
8484
}
8585
}
Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
2+
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="urn:hl7-org:v3" elementFormDefault="qualified" xmlns="urn:hl7-org:v3" xmlns:hl7="urn:hl7-org:v3">
3+
<xs:include schemaLocation="../dt/datatypes.xsd"/>
4+
<xs:include schemaLocation="../voc/voc.xsd"/>
5+
<xs:annotation>
6+
<xs:documentation>
7+
Generated using schema builder version 1.21p12.
8+
Stylesheets:
9+
10+
RoseTreeToMIFStaticModel.xsl version: 1.1
11+
SplitModels.xsl version: 1.1
12+
AssocInMif.xsl version:1.1
13+
StaticMifToXsd.xsl version 1.1</xs:documentation>
14+
</xs:annotation><!--
15+
*****************************************************************************************************************
16+
* XML schema for message type .
17+
* Generated by XMLITS version 1.21p12, Copyright (C) 2002, 2003 by Health Level 7, Inc.
18+
*
19+
* Copyright (c) 2002, 2003, Health Level Seven. All rights reserved.
20+
* Redistribution and use in source and binary forms, with or without
21+
* modification, are permitted provided that the following conditions
22+
* are met:
23+
* 1. Redistributions of source code must retain the above copyright
24+
* notice, this list of conditions and the following disclaimer.
25+
* 2. Redistributions in binary form must reproduce the above copyright
26+
* notice, this list of conditions and the following disclaimer in the
27+
* documentation and/or other materials provided with the distribution.
28+
* 3. All advertising materials mentioning features or use of this software
29+
* must display the following acknowledgement:
30+
* This product includes software developed by Health Level Seven.
31+
* THIS SOFTWARE IS PROVIDED BY HEALTH LEVEL SEVEN, INC. AND CONTRIBUTORS "AS IS" AND
32+
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
33+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
34+
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
35+
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36+
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37+
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38+
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
39+
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
40+
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
41+
* SUCH DAMAGE.
42+
*
43+
********************************************************************************************************************
44+
-->
45+
<xs:include schemaLocation="UKCT_MT120901UK01.xsd"/>
46+
<xs:include schemaLocation="UKCT_MT121001UK01.xsd"/>
47+
<xs:element name="ControlActEvent" type="MCAI_MT040101UK03.ControlActEvent"/>
48+
<xs:complexType name="MCAI_MT040101UK03.ControlActEvent">
49+
<xs:sequence>
50+
<xs:element type="MCAI_MT040101UK03.Author" minOccurs="0" maxOccurs="1" name="author"/>
51+
<xs:element type="MCAI_MT040101UK03.Author2" minOccurs="1" maxOccurs="2" name="author1"/>
52+
<xs:element type="MCAI_MT040101UK03.Reason" minOccurs="0" maxOccurs="unbounded" name="reason"/>
53+
<xs:element type="MCAI_MT040101UK03.Subject" minOccurs="0" maxOccurs="1" name="subject"/>
54+
</xs:sequence>
55+
<xs:attribute name="type" type="Classes" default="ControlAct"/>
56+
<xs:attribute name="classCode" type="ActClass" use="optional" default="CACT"/>
57+
<xs:attribute name="moodCode" type="ActMood" use="optional" default="EVN"/>
58+
<xs:attribute name="typeID" use="optional">
59+
<xs:simpleType>
60+
<xs:list itemType="oid"/>
61+
</xs:simpleType>
62+
</xs:attribute>
63+
<xs:attribute name="realmCode" use="optional">
64+
<xs:simpleType>
65+
<xs:list itemType="cs"/>
66+
</xs:simpleType>
67+
</xs:attribute>
68+
<xs:attribute name="nullFlavor" type="cs" use="optional"/>
69+
</xs:complexType>
70+
<xs:complexType name="MCAI_MT040101UK03.Author">
71+
<xs:sequence>
72+
<xs:group ref="UKCT_MT120901UK01"/>
73+
</xs:sequence>
74+
<xs:attribute name="type" type="Classes" default="Participation"/>
75+
<xs:attribute name="typeCode" type="ParticipationType" use="optional" default="AUT"/>
76+
<xs:attribute name="typeID" use="optional">
77+
<xs:simpleType>
78+
<xs:list itemType="oid"/>
79+
</xs:simpleType>
80+
</xs:attribute>
81+
<xs:attribute name="realmCode" use="optional">
82+
<xs:simpleType>
83+
<xs:list itemType="cs"/>
84+
</xs:simpleType>
85+
</xs:attribute>
86+
<xs:attribute name="nullFlavor" type="cs" use="optional"/>
87+
</xs:complexType>
88+
<xs:complexType name="MCAI_MT040101UK03.Author2">
89+
<xs:sequence>
90+
<xs:group ref="UKCT_MT121001UK01"/>
91+
</xs:sequence>
92+
<xs:attribute name="type" type="Classes" default="Participation"/>
93+
<xs:attribute name="typeCode" type="ParticipationType" use="optional" default="AUT"/>
94+
<xs:attribute name="typeID" use="optional">
95+
<xs:simpleType>
96+
<xs:list itemType="oid"/>
97+
</xs:simpleType>
98+
</xs:attribute>
99+
<xs:attribute name="realmCode" use="optional">
100+
<xs:simpleType>
101+
<xs:list itemType="cs"/>
102+
</xs:simpleType>
103+
</xs:attribute>
104+
<xs:attribute name="nullFlavor" type="cs" use="optional"/>
105+
</xs:complexType>
106+
<xs:complexType name="MCAI_MT040101UK03.Reason">
107+
<xs:sequence>
108+
<xs:element type="MCAI_MT040101UK03.DetectedIssueEvent" minOccurs="1" maxOccurs="1" name="justifyingDetectedIssueEvent"/>
109+
</xs:sequence>
110+
<xs:attribute name="type" type="Classes" default="ActRelationship"/>
111+
<xs:attribute name="typeCode" type="ActRelationshipType" use="optional" default="RSON"/>
112+
<xs:attribute name="typeID" use="optional">
113+
<xs:simpleType>
114+
<xs:list itemType="oid"/>
115+
</xs:simpleType>
116+
</xs:attribute>
117+
<xs:attribute name="realmCode" use="optional">
118+
<xs:simpleType>
119+
<xs:list itemType="cs"/>
120+
</xs:simpleType>
121+
</xs:attribute>
122+
<xs:attribute name="nullFlavor" type="cs" use="optional"/>
123+
</xs:complexType>
124+
<xs:complexType name="MCAI_MT040101UK03.DetectedIssueEvent">
125+
<xs:sequence>
126+
<xs:element name="code" type="CD" minOccurs="1" maxOccurs="1"/>
127+
</xs:sequence>
128+
<xs:attribute name="type" type="Classes" default="Observation"/>
129+
<xs:attribute name="classCode" type="ActClass" use="optional" default="ALRT"/>
130+
<xs:attribute name="moodCode" type="ActMood" use="optional" default="EVN"/>
131+
<xs:attribute name="typeID" use="optional">
132+
<xs:simpleType>
133+
<xs:list itemType="oid"/>
134+
</xs:simpleType>
135+
</xs:attribute>
136+
<xs:attribute name="realmCode" use="optional">
137+
<xs:simpleType>
138+
<xs:list itemType="cs"/>
139+
</xs:simpleType>
140+
</xs:attribute>
141+
<xs:attribute name="nullFlavor" type="cs" use="optional"/>
142+
</xs:complexType>
143+
<xs:complexType name="MCAI_MT040101UK03.Subject">
144+
<xs:sequence><!--Payload reference-->
145+
<xs:any/>
146+
</xs:sequence>
147+
<xs:attribute name="type" type="Classes" default="ActRelationship"/>
148+
<xs:attribute name="typeCode" type="ActRelationshipType" use="optional" default="SUBJ"/>
149+
<xs:attribute name="contextConductionInd" type="bl" use="optional" default="false"/>
150+
<xs:attribute name="typeID" use="optional">
151+
<xs:simpleType>
152+
<xs:list itemType="oid"/>
153+
</xs:simpleType>
154+
</xs:attribute>
155+
<xs:attribute name="realmCode" use="optional">
156+
<xs:simpleType>
157+
<xs:list itemType="cs"/>
158+
</xs:simpleType>
159+
</xs:attribute>
160+
<xs:attribute name="nullFlavor" type="cs" use="optional"/>
161+
</xs:complexType>
162+
<xs:complexType name="MCAI_MT040101UK03.Act">
163+
<xs:attribute name="type" type="Classes" default="ActHeir"/>
164+
<xs:attribute name="classCode" type="ActClass" use="optional" default="ACT"/>
165+
<xs:attribute name="moodCode" type="ActMood" use="required"/>
166+
<xs:attribute name="typeID" use="optional">
167+
<xs:simpleType>
168+
<xs:list itemType="oid"/>
169+
</xs:simpleType>
170+
</xs:attribute>
171+
<xs:attribute name="realmCode" use="optional">
172+
<xs:simpleType>
173+
<xs:list itemType="cs"/>
174+
</xs:simpleType>
175+
</xs:attribute>
176+
<xs:attribute name="nullFlavor" type="cs" use="optional"/>
177+
</xs:complexType>
178+
</xs:schema>

0 commit comments

Comments
 (0)