Merge 49d64c1633
into 3f6d1eb29b
This commit is contained in:
commit
e57f774d6a
|
@ -0,0 +1 @@
|
||||||
|
|
|
@ -35,6 +35,7 @@ import org.apache.commons.cli.ParseException;
|
||||||
import org.apache.commons.io.IOUtils;
|
import org.apache.commons.io.IOUtils;
|
||||||
import org.apache.commons.lang3.text.WordUtils;
|
import org.apache.commons.lang3.text.WordUtils;
|
||||||
import org.fusesource.jansi.Ansi.Color;
|
import org.fusesource.jansi.Ansi.Color;
|
||||||
|
import org.hl7.fhir.common.hapi.validation.support.NpmPackageValidationSupport;
|
||||||
import org.hl7.fhir.common.hapi.validation.support.ValidationSupportChain;
|
import org.hl7.fhir.common.hapi.validation.support.ValidationSupportChain;
|
||||||
import org.hl7.fhir.common.hapi.validation.validator.FhirInstanceValidator;
|
import org.hl7.fhir.common.hapi.validation.validator.FhirInstanceValidator;
|
||||||
|
|
||||||
|
@ -86,6 +87,8 @@ public class ValidateCommand extends BaseCommand {
|
||||||
"igpack",
|
"igpack",
|
||||||
true,
|
true,
|
||||||
"If specified, provides the filename of an IGPack file to include in validation");
|
"If specified, provides the filename of an IGPack file to include in validation");
|
||||||
|
addOptionalOption(
|
||||||
|
retVal, null, "oneCode", false, "Validate allowing one coding to satisfy CodeableConcept binding");
|
||||||
addOptionalOption(retVal, "x", "xsd", false, "Validate using Schemas");
|
addOptionalOption(retVal, "x", "xsd", false, "Validate using Schemas");
|
||||||
addOptionalOption(retVal, "s", "sch", false, "Validate using Schematrons");
|
addOptionalOption(retVal, "s", "sch", false, "Validate using Schematrons");
|
||||||
addOptionalOption(retVal, "e", "encoding", "encoding", "File encoding (default is UTF-8)");
|
addOptionalOption(retVal, "e", "encoding", "encoding", "File encoding (default is UTF-8)");
|
||||||
|
@ -149,20 +152,23 @@ public class ValidateCommand extends BaseCommand {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (theCommandLine.hasOption("p")) {
|
if (theCommandLine.hasOption("p")) {
|
||||||
|
ValidationSupportChain validationSupportChain;
|
||||||
switch (ctx.getVersion().getVersion()) {
|
switch (ctx.getVersion().getVersion()) {
|
||||||
case DSTU2: {
|
case DSTU2: {
|
||||||
FhirInstanceValidator instanceValidator;
|
FhirInstanceValidator instanceValidator;
|
||||||
ValidationSupportChain validationSupportChain =
|
validationSupportChain =
|
||||||
ValidationSupportChainCreator.getValidationSupportChainDstu2(ctx, theCommandLine);
|
ValidationSupportChainCreator.getValidationSupportChainDstu2(ctx, theCommandLine);
|
||||||
|
validationSupportChain.oneCodingIsSufficient = true;
|
||||||
instanceValidator = new FhirInstanceValidator(validationSupportChain);
|
instanceValidator = new FhirInstanceValidator(validationSupportChain);
|
||||||
val.registerValidatorModule(instanceValidator);
|
val.registerValidatorModule(instanceValidator);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DSTU3:
|
case DSTU3:
|
||||||
case R4: {
|
case R4: {
|
||||||
|
ourLog.info("Adding FHIR R4 validation support chain");
|
||||||
FhirInstanceValidator instanceValidator = new FhirInstanceValidator(ctx);
|
FhirInstanceValidator instanceValidator = new FhirInstanceValidator(ctx);
|
||||||
val.registerValidatorModule(instanceValidator);
|
val.registerValidatorModule(instanceValidator);
|
||||||
ValidationSupportChain validationSupportChain =
|
validationSupportChain =
|
||||||
ValidationSupportChainCreator.getValidationSupportChainR4(ctx, theCommandLine);
|
ValidationSupportChainCreator.getValidationSupportChainR4(ctx, theCommandLine);
|
||||||
instanceValidator.setValidationSupport(validationSupportChain);
|
instanceValidator.setValidationSupport(validationSupportChain);
|
||||||
break;
|
break;
|
||||||
|
@ -171,6 +177,25 @@ public class ValidateCommand extends BaseCommand {
|
||||||
throw new ParseException(
|
throw new ParseException(
|
||||||
Msg.code(1620) + "Profile validation (-p) is not supported for this FHIR version");
|
Msg.code(1620) + "Profile validation (-p) is not supported for this FHIR version");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Do we allow CodeableConcepts to be satisfied by only one coding?
|
||||||
|
// Useful when we are using additionalBindings.
|
||||||
|
validationSupportChain.oneCodingIsSufficient = theCommandLine.hasOption("oneCode");
|
||||||
|
|
||||||
|
// If they want to do profile validation - there might be a whole IG to load...
|
||||||
|
if (theCommandLine.hasOption("igpack")) {
|
||||||
|
String igPack = theCommandLine.getOptionValue("igpack");
|
||||||
|
ourLog.info("Loading IG Package from {} to the validation support chain", igPack);
|
||||||
|
try {
|
||||||
|
NpmPackageValidationSupport npmPackageSupport = new NpmPackageValidationSupport(ctx);
|
||||||
|
npmPackageSupport.loadPackageFromFile(igPack);
|
||||||
|
validationSupportChain.addValidationSupport(0, npmPackageSupport);
|
||||||
|
} catch (IOException iox) {
|
||||||
|
throw new ParseException(
|
||||||
|
Msg.code(1620) + "IGpack validation (--igpack) failed: " + iox.getMessage());
|
||||||
|
}
|
||||||
|
ourLog.info("Completed loading IG Package from {}", igPack);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val.setValidateAgainstStandardSchema(theCommandLine.hasOption("x"));
|
val.setValidateAgainstStandardSchema(theCommandLine.hasOption("x"));
|
||||||
|
|
|
@ -23,6 +23,7 @@ import ca.uhn.fhir.context.FhirContext;
|
||||||
import ca.uhn.fhir.context.support.DefaultProfileValidationSupport;
|
import ca.uhn.fhir.context.support.DefaultProfileValidationSupport;
|
||||||
import ca.uhn.fhir.i18n.Msg;
|
import ca.uhn.fhir.i18n.Msg;
|
||||||
import org.apache.commons.cli.CommandLine;
|
import org.apache.commons.cli.CommandLine;
|
||||||
|
import org.hl7.fhir.common.hapi.validation.support.CommonCodeSystemsTerminologyService;
|
||||||
import org.hl7.fhir.common.hapi.validation.support.InMemoryTerminologyServerValidationSupport;
|
import org.hl7.fhir.common.hapi.validation.support.InMemoryTerminologyServerValidationSupport;
|
||||||
import org.hl7.fhir.common.hapi.validation.support.LocalFileValidationSupport;
|
import org.hl7.fhir.common.hapi.validation.support.LocalFileValidationSupport;
|
||||||
import org.hl7.fhir.common.hapi.validation.support.SnapshotGeneratingValidationSupport;
|
import org.hl7.fhir.common.hapi.validation.support.SnapshotGeneratingValidationSupport;
|
||||||
|
@ -52,7 +53,7 @@ public class ValidationSupportChainCreator {
|
||||||
if (commandLine.hasOption("r")) {
|
if (commandLine.hasOption("r")) {
|
||||||
chain.addValidationSupport(new LoadingValidationSupportDstu3());
|
chain.addValidationSupport(new LoadingValidationSupportDstu3());
|
||||||
}
|
}
|
||||||
|
chain.addValidationSupport(new CommonCodeSystemsTerminologyService(ctx));
|
||||||
return chain;
|
return chain;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -63,7 +63,7 @@
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>jakarta.servlet</groupId>
|
<groupId>jakarta.servlet</groupId>
|
||||||
<artifactId>jakarta.servlet-api</artifactId>
|
<artifactId>jakarta.servlet-api</artifactId>
|
||||||
<scope>test</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
|
|
|
@ -81,7 +81,7 @@ public class InstanceReindexServiceImplR5Test extends BaseJpaR5Test {
|
||||||
|
|
||||||
IIdType id = createPatient(withFamily("Simpson"), withGiven("Homer"));
|
IIdType id = createPatient(withFamily("Simpson"), withGiven("Homer"));
|
||||||
|
|
||||||
runInTransaction(this::logAllNonUniqueIndexes);
|
runInTransaction((Runnable) this::logAllNonUniqueIndexes);
|
||||||
|
|
||||||
Parameters outcome = (Parameters) mySvc.reindexDryRun(new SystemRequestDetails(), id, null);
|
Parameters outcome = (Parameters) mySvc.reindexDryRun(new SystemRequestDetails(), id, null);
|
||||||
ourLog.info("Output:{}", myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome));
|
ourLog.info("Output:{}", myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome));
|
||||||
|
|
|
@ -133,7 +133,11 @@
|
||||||
<version>${project.version}</version>
|
<version>${project.version}</version>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>jakarta.servlet</groupId>
|
||||||
|
<artifactId>jakarta.servlet-api</artifactId>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
|
|
@ -3,13 +3,14 @@ package org.hl7.fhir.common.hapi.validation.support;
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
import ca.uhn.fhir.parser.IParser;
|
import ca.uhn.fhir.parser.IParser;
|
||||||
import ca.uhn.fhir.parser.LenientErrorHandler;
|
import ca.uhn.fhir.parser.LenientErrorHandler;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
|
||||||
import ca.uhn.fhir.util.ClasspathUtil;
|
import ca.uhn.fhir.util.ClasspathUtil;
|
||||||
import jakarta.annotation.Nonnull;
|
import jakarta.annotation.Nonnull;
|
||||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
import org.hl7.fhir.utilities.TextFile;
|
import org.hl7.fhir.utilities.TextFile;
|
||||||
import org.hl7.fhir.utilities.npm.NpmPackage;
|
import org.hl7.fhir.utilities.npm.NpmPackage;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
|
@ -31,11 +32,16 @@ public class NpmPackageValidationSupport extends PrePopulatedValidationSupport {
|
||||||
super(theFhirContext);
|
super(theFhirContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return getFhirContext().getVersion().getVersion() + " NPM Package Validation Support";
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load an NPM package using a classpath specification, e.g. <code>/path/to/resource/my_package.tgz</code>. The
|
* Load an NPM package using a classpath specification, e.g. <code>/path/to/resource/my_package.tgz</code>. The
|
||||||
* classpath spec can optionally be prefixed with the string <code>classpath:</code>
|
* classpath spec can optionally be prefixed with the string <code>classpath:</code>
|
||||||
*
|
*
|
||||||
* @throws InternalErrorException If the classpath file can't be found
|
* @throws IOException If the classpath file can't be found
|
||||||
*/
|
*/
|
||||||
public void loadPackageFromClasspath(String theClasspath) throws IOException {
|
public void loadPackageFromClasspath(String theClasspath) throws IOException {
|
||||||
try (InputStream is = ClasspathUtil.loadResourceAsStream(theClasspath)) {
|
try (InputStream is = ClasspathUtil.loadResourceAsStream(theClasspath)) {
|
||||||
|
@ -47,6 +53,21 @@ public class NpmPackageValidationSupport extends PrePopulatedValidationSupport {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load an NPM package from the filesystem e.g. <code>my_package.tgz</code>.
|
||||||
|
*
|
||||||
|
* @throws IOException If the package file can't be found
|
||||||
|
*/
|
||||||
|
public void loadPackageFromFile(String theFile) throws IOException {
|
||||||
|
File inFile = new File(theFile);
|
||||||
|
InputStream is = new FileInputStream(inFile);
|
||||||
|
NpmPackage pkg = NpmPackage.fromPackage(is);
|
||||||
|
if (pkg.getFolders().containsKey("package")) {
|
||||||
|
loadResourcesFromPackage(pkg);
|
||||||
|
loadBinariesFromPackage(pkg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void loadResourcesFromPackage(NpmPackage thePackage) {
|
private void loadResourcesFromPackage(NpmPackage thePackage) {
|
||||||
NpmPackage.NpmPackageFolder packageFolder = thePackage.getFolders().get("package");
|
NpmPackage.NpmPackageFolder packageFolder = thePackage.getFolders().get("package");
|
||||||
|
|
||||||
|
|
|
@ -371,12 +371,13 @@ public class ValidationSupportChain implements IValidationSupport {
|
||||||
if (retVal != null) {
|
if (retVal != null) {
|
||||||
if (ourLog.isDebugEnabled()) {
|
if (ourLog.isDebugEnabled()) {
|
||||||
ourLog.debug(
|
ourLog.debug(
|
||||||
"Code {}|{} '{}' in ValueSet {} validated by {}",
|
"Code {}|{} '{}' in ValueSet {} validated by {} result: {}",
|
||||||
theCodeSystem,
|
theCodeSystem,
|
||||||
theCode,
|
theCode,
|
||||||
theDisplay,
|
theDisplay,
|
||||||
theValueSetUrl,
|
theValueSetUrl,
|
||||||
next.getName());
|
next.getName(),
|
||||||
|
retVal.getMessage() != null ? retVal.getMessage() : "Success");
|
||||||
}
|
}
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
@ -401,12 +402,13 @@ public class ValidationSupportChain implements IValidationSupport {
|
||||||
if (retVal != null) {
|
if (retVal != null) {
|
||||||
if (ourLog.isDebugEnabled()) {
|
if (ourLog.isDebugEnabled()) {
|
||||||
ourLog.debug(
|
ourLog.debug(
|
||||||
"Code {}|{} '{}' in ValueSet {} validated by {}",
|
"Code {}|{} '{}' in ValueSet {} validated by {} result: {}",
|
||||||
theCodeSystem,
|
theCodeSystem,
|
||||||
theCode,
|
theCode,
|
||||||
theDisplay,
|
theDisplay,
|
||||||
theValueSet.getIdElement(),
|
theValueSet.getIdElement(),
|
||||||
next.getName());
|
next.getName(),
|
||||||
|
retVal.getMessage() != null ? retVal.getMessage() : "Success");
|
||||||
}
|
}
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
@ -445,4 +447,18 @@ public class ValidationSupportChain implements IValidationSupport {
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* See VersionSpecificWorkerContextWrapper#validateCode in hapi-fhir-validation.
|
||||||
|
* <p>
|
||||||
|
* If true, validation for codings will return a positive result if AT LEAST ONE coding is valid.
|
||||||
|
* If false, validation for codings will return a positive result if there is ALL codings are valid.
|
||||||
|
* </p>
|
||||||
|
* @return if the application has configured validation to use logical AND, as opposed to logical OR, which is the default
|
||||||
|
*/
|
||||||
|
public boolean oneCodingIsSufficient = false; // default value from parent Interface (it's the wrong way round !!!)
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEnabledValidationForCodingsLogicalAnd() { // should be named ....LogicalAny
|
||||||
|
return oneCodingIsSufficient;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
7
pom.xml
7
pom.xml
|
@ -1050,9 +1050,9 @@
|
||||||
|
|
||||||
<!-- Site properties -->
|
<!-- Site properties -->
|
||||||
<fontawesomeVersion>5.4.1</fontawesomeVersion>
|
<fontawesomeVersion>5.4.1</fontawesomeVersion>
|
||||||
<maven.compiler.source>11</maven.compiler.source>
|
<maven.compiler.source>17</maven.compiler.source>
|
||||||
<maven.compiler.target>11</maven.compiler.target>
|
<maven.compiler.target>17</maven.compiler.target>
|
||||||
<maven.compiler.release>11</maven.compiler.release>
|
<maven.compiler.release>17</maven.compiler.release>
|
||||||
<maven.compiler.testSource>17</maven.compiler.testSource>
|
<maven.compiler.testSource>17</maven.compiler.testSource>
|
||||||
<maven.compiler.testTarget>17</maven.compiler.testTarget>
|
<maven.compiler.testTarget>17</maven.compiler.testTarget>
|
||||||
<maven.compiler.testRelease>17</maven.compiler.testRelease>
|
<maven.compiler.testRelease>17</maven.compiler.testRelease>
|
||||||
|
@ -3299,4 +3299,3 @@
|
||||||
</profile>
|
</profile>
|
||||||
</profiles>
|
</profiles>
|
||||||
</project>
|
</project>
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue