1- package software .nhs .FHIRValidator ;
1+ package software .nhs .fhirvalidator . configuration ;
22
33import java .io .IOException ;
4+ import java .io .InputStream ;
5+ import java .util .ArrayList ;
46import java .util .List ;
5- import java .util .stream .Collectors ;
67
7- import com .google .common .collect .ImmutableList ;
88import com .google .gson .Gson ;
9- import com .google .gson .JsonSyntaxException ;
109
10+ import org .hl7 .fhir .common .hapi .validation .support .CachingValidationSupport ;
1111import org .hl7 .fhir .common .hapi .validation .support .CommonCodeSystemsTerminologyService ;
1212import org .hl7 .fhir .common .hapi .validation .support .InMemoryTerminologyServerValidationSupport ;
1313import org .hl7 .fhir .common .hapi .validation .support .NpmPackageValidationSupport ;
1818import org .hl7 .fhir .r4 .model .CanonicalType ;
1919import org .hl7 .fhir .r4 .model .ElementDefinition ;
2020import org .hl7 .fhir .r4 .model .StructureDefinition ;
21+ import org .hl7 .fhir .utilities .npm .NpmPackage ;
2122
2223import ca .uhn .fhir .context .FhirContext ;
2324import ca .uhn .fhir .context .support .ConceptValidationOptions ;
2425import ca .uhn .fhir .context .support .DefaultProfileValidationSupport ;
2526import ca .uhn .fhir .context .support .IValidationSupport ;
2627import ca .uhn .fhir .context .support .ValidationSupportContext ;
2728import ca .uhn .fhir .rest .server .exceptions .InternalErrorException ;
28- import ca .uhn .fhir .rest . server . exceptions . InvalidRequestException ;
29+ import ca .uhn .fhir .util . ClasspathUtil ;
2930import ca .uhn .fhir .validation .FhirValidator ;
30- import ca .uhn .fhir .validation .ValidationResult ;
31+ import software .nhs .fhirvalidator .models .SimplifierPackage ;
32+ import software .nhs .fhirvalidator .util .ResourceUtils ;
33+
3134import org .apache .logging .log4j .LogManager ;
3235import org .apache .logging .log4j .Logger ;
33- import software .nhs .FHIRValidator .models .SimplifierPackage ;
34- import software .amazon .lambda .powertools .logging .Logging ;
3536
3637/**
3738 * This class is a wrapper around the HAPI FhirValidator.
3839 * The FhirValidator is built using default settings and the available
3940 * implementation guides are loaded into it.
4041 */
4142
42- public class Validator {
43- private final FhirValidator validator ;
43+ public class ValidatorConfiguration {
44+ public final FhirValidator validator ;
45+ public final FhirContext fhirContext ;
46+ public final List <NpmPackage > npmPackages = new ArrayList <>();
4447
45- private final FhirContext ctx ;
46- Logger log = LogManager .getLogger (Validator .class );
48+ Logger log = LogManager .getLogger (ValidatorConfiguration .class );
4749
48- public Validator () {
49- ctx = FhirContext .forR4 ();
50+ public ValidatorConfiguration () {
51+ fhirContext = FhirContext .forR4 ();
5052
5153 // Create a chain that will hold our modules
5254 ValidationSupportChain supportChain = new ValidationSupportChain (
53- new DefaultProfileValidationSupport (ctx ),
54- new CommonCodeSystemsTerminologyService (ctx ),
55- terminologyValidationSupport (ctx ),
56- new SnapshotGeneratingValidationSupport (ctx ));
55+ new DefaultProfileValidationSupport (fhirContext ),
56+ new CommonCodeSystemsTerminologyService (fhirContext ),
57+ terminologyValidationSupport (fhirContext ),
58+ new SnapshotGeneratingValidationSupport (fhirContext ));
5759
58- NpmPackageValidationSupport npmPackageSupport = new NpmPackageValidationSupport (ctx );
5960 SimplifierPackage [] packages = getPackages ();
61+ NpmPackageValidationSupport npmPackageSupport = new NpmPackageValidationSupport (fhirContext );
62+
6063 try {
6164 for (SimplifierPackage individualPackage : packages ) {
6265 String packagePath = String .format ("classpath:package/%s-%s.tgz" , individualPackage .packageName ,
6366 individualPackage .version );
6467 npmPackageSupport .loadPackageFromClasspath (packagePath );
68+ try (InputStream is = ClasspathUtil .loadResourceAsStream (packagePath )) {
69+ NpmPackage pkg = NpmPackage .fromPackage (is );
70+ npmPackages .add (pkg );
71+ }
6572 }
6673 } catch (InternalErrorException | IOException ex ) {
6774 log .error (ex .getMessage (), ex );
@@ -71,40 +78,11 @@ public Validator() {
7178 generateSnapshots (supportChain );
7279 supportChain .fetchCodeSystem ("http://snomed.info/sct" );
7380
74- // Create a validator using the FhirInstanceValidator module.
75- FhirInstanceValidator validatorModule = new FhirInstanceValidator (supportChain );
76- validator = ctx .newValidator ().registerValidatorModule (validatorModule );
77- }
78-
79- @ Logging
80- public ValidatorResponse validate (String resourceAsJsonText ) {
81- try {
82- ValidationResult result = validator .validateWithResult (resourceAsJsonText );
83- return toValidatorResponse (result );
84- } catch (JsonSyntaxException | NullPointerException | IllegalArgumentException | InvalidRequestException e ) {
85- log .error (e .toString ());
86- return ValidatorResponse .builder ()
87- .isSuccessful (false )
88- .errorMessages (ImmutableList .of (ValidatorErrorMessage .builder ()
89- .msg ("Invalid JSON" )
90- .severity ("error" )
91- .build ()))
92- .build ();
93- }
94- }
81+ CachingValidationSupport validationSupport = new CachingValidationSupport (supportChain );
9582
96- private ValidatorResponse toValidatorResponse (ValidationResult result ) {
97- return ValidatorResponse .builder ()
98- .isSuccessful (result .isSuccessful ())
99- .errorMessages (result .getMessages ().stream ()
100- .map (singleValidationMessage -> ValidatorErrorMessage .builder ()
101- .severity (singleValidationMessage .getSeverity ().getCode ())
102- .msg (singleValidationMessage .getLocationString () + " - "
103- + singleValidationMessage .getMessage ())
104- .build ())
105-
106- .collect (Collectors .toList ()))
107- .build ();
83+ // Create a validator using the FhirInstanceValidator module.
84+ FhirInstanceValidator validatorModule = new FhirInstanceValidator (validationSupport );
85+ validator = fhirContext .newValidator ().registerValidatorModule (validatorModule );
10886 }
10987
11088 private void generateSnapshots (IValidationSupport supportChain ) {
@@ -121,7 +99,7 @@ private void generateSnapshots(IValidationSupport supportChain) {
12199 try {
122100 circularReferenceCheck (it , supportChain );
123101 } catch (Exception e ) {
124- log .error ("Failed to generate snapshot for " + it , e );
102+ log .error (String . format ( "Failed to generate snapshot for %s" , it ) , e );
125103 }
126104 });
127105
@@ -131,7 +109,7 @@ private void generateSnapshots(IValidationSupport supportChain) {
131109 try {
132110 supportChain .generateSnapshot (context , it , it .getUrl (), "https://fhir.nhs.uk/R4" , it .getName ());
133111 } catch (Exception e ) {
134- log .error ("Failed to generate snapshot for " + it , e );
112+ log .error (String . format ( "Failed to generate snapshot for %s" , it ) , e );
135113 }
136114 });
137115 }
@@ -144,7 +122,7 @@ private boolean shouldGenerateSnapshot(StructureDefinition structureDefinition)
144122 private StructureDefinition circularReferenceCheck (StructureDefinition structureDefinition ,
145123 IValidationSupport supportChain ) {
146124 if (structureDefinition .hasSnapshot ()) {
147- log .error (structureDefinition . getUrl () + " has snapshot!!" );
125+ log .error (String . format ( "%s has snapshot!!", structureDefinition . getUrl ()) );
148126 }
149127
150128 for (ElementDefinition element : structureDefinition .getDifferential ().getElement ()) {
@@ -163,7 +141,8 @@ private StructureDefinition circularReferenceCheck(StructureDefinition structure
163141 element .getId ().contains ("Encounter.reasonReference" ) ||
164142 element .getId ().contains ("Encounter.appointment" )) && element .hasType ()) {
165143
166- log .warn (structureDefinition .getUrl () + " has circular references (" + element .getId () + ")" );
144+ log .warn (String .format ("%s has circular references (%s)" , structureDefinition .getUrl (),
145+ element .getId ()));
167146
168147 for (ElementDefinition .TypeRefComponent typeRef : element .getType ()) {
169148 if (typeRef .hasTargetProfile ()) {
@@ -202,7 +181,7 @@ public IValidationSupport.CodeValidationResult validateCodeInValueSet(
202181 String theCode ,
203182 String theDisplay ,
204183 IBaseResource theValueSet ) {
205- String valueSetUrl = CommonCodeSystemsTerminologyService .getValueSetUrl (theValueSet );
184+ String valueSetUrl = CommonCodeSystemsTerminologyService .getValueSetUrl (fhirContext , theValueSet );
206185
207186 if ("https://fhir.nhs.uk/ValueSet/NHSDigital-MedicationRequest-Code" .equals (valueSetUrl )
208187 || "https://fhir.nhs.uk/ValueSet/NHSDigital-MedicationDispense-Code" .equals (valueSetUrl )
@@ -224,8 +203,7 @@ public IValidationSupport.CodeValidationResult validateCodeInValueSet(
224203 }
225204
226205 private SimplifierPackage [] getPackages () {
227- String manifestContent = Utils .getResourceContent ("manifest.json" );
228- SimplifierPackage [] packages = new Gson ().fromJson (manifestContent , SimplifierPackage [].class );
229- return packages ;
206+ String manifestContent = ResourceUtils .getResourceContent ("manifest.json" );
207+ return new Gson ().fromJson (manifestContent , SimplifierPackage [].class );
230208 }
231209}
0 commit comments