Add jurisdiction parameter to Validator

This commit is contained in:
Grahame Grieve 2022-05-18 08:23:05 +10:00
parent 919d6e6d8b
commit d39ed690f8
19 changed files with 6098 additions and 22 deletions

View File

@ -69,6 +69,8 @@ import org.hl7.fhir.r5.model.StructureDefinition.StructureDefinitionKind;
import org.hl7.fhir.r5.model.StructureDefinition.TypeDerivationRule;
import org.hl7.fhir.r5.model.StructureMap.StructureMapModelMode;
import org.hl7.fhir.r5.model.StructureMap.StructureMapStructureComponent;
import org.hl7.fhir.r5.terminologies.CodeSystemUtilities;
import org.hl7.fhir.r5.terminologies.JurisdictionUtilities;
import org.hl7.fhir.r5.terminologies.TerminologyClient;
import org.hl7.fhir.r5.utils.validation.IResourceValidator;
import org.hl7.fhir.r5.utils.XVerExtensionManager;
@ -579,7 +581,7 @@ public class SimpleWorkerContext extends BaseWorkerContext implements IWorkerCon
public IResourceValidator newValidator() throws FHIRException {
if (validatorFactory == null)
throw new Error(formatMessage(I18nConstants.NO_VALIDATOR_CONFIGURED));
return validatorFactory.makeValidator(this, xverManager);
return validatorFactory.makeValidator(this, xverManager).setJurisdiction(JurisdictionUtilities.getJurisdictionCodingFromLocale(Locale.getDefault().getCountry()));
}

View File

@ -50,6 +50,7 @@ import org.hl7.fhir.r5.model.CodeSystem.ConceptPropertyComponent;
import org.hl7.fhir.r5.model.CodeSystem.PropertyComponent;
import org.hl7.fhir.r5.model.CodeSystem.PropertyType;
import org.hl7.fhir.r5.model.CodeType;
import org.hl7.fhir.r5.model.Coding;
import org.hl7.fhir.r5.model.DataType;
import org.hl7.fhir.r5.model.DateTimeType;
import org.hl7.fhir.r5.model.Enumerations.PublicationStatus;
@ -532,5 +533,10 @@ public class CodeSystemUtilities {
}
}
}
public static Coding readCoding(String jurisdiction) {
return jurisdiction == null || !jurisdiction.contains("#") ? null : new Coding().setCode(jurisdiction.substring(jurisdiction.indexOf("#")+1)).setSystem(jurisdiction.substring(0, jurisdiction.indexOf("#")));
}
}

View File

@ -33,6 +33,7 @@ package org.hl7.fhir.r5.utils.validation;
import com.google.gson.JsonObject;
import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.r5.elementmodel.Manager.FhirFormat;
import org.hl7.fhir.r5.model.Coding;
import org.hl7.fhir.r5.model.StructureDefinition;
import org.hl7.fhir.r5.utils.validation.constants.BestPracticeWarningLevel;
import org.hl7.fhir.r5.utils.validation.constants.CheckDisplayOption;
@ -145,6 +146,9 @@ public interface IResourceValidator {
boolean isValidateValueSetCodesOnTxServer();
void setValidateValueSetCodesOnTxServer(boolean value);
public Coding getJurisdiction();
public IResourceValidator setJurisdiction(Coding jurisdiction);
/**
* Bundle validation rules allow for requesting particular entries in a bundle get validated against particular profiles
* Typically this is used from the command line to avoid having to construct profile just to validate a particular resource

View File

@ -121,6 +121,7 @@ public class BaseValidator implements IValidationContextResourceLoader {
protected List<TrackedLocationRelatedMessage> trackedMessages = new ArrayList<>();
protected List<ValidationMessage> messagesToRemove = new ArrayList<>();
private ValidationLevel level = ValidationLevel.HINTS;
protected Coding jurisdiction;
public BaseValidator(IWorkerContext context, XVerExtensionManager xverManager) {
super();
@ -1102,4 +1103,5 @@ public class BaseValidator implements IValidationContextResourceLoader {
return level;
}
}

View File

@ -167,6 +167,7 @@ public class ValidationEngine implements IValidatorResourceFetcher, IValidationP
@Getter @Setter private ValidationLevel level = ValidationLevel.HINTS;
@Getter @Setter private FHIRPathEngine fhirPathEngine;
@Getter @Setter private IgLoader igLoader;
@Getter @Setter private Coding jurisdiction;
/**
* Systems that host the ValidationEngine can use this to control what validation the validator performs.
@ -623,7 +624,7 @@ public class ValidationEngine implements IValidatorResourceFetcher, IValidationP
if (format == FhirFormat.SHC) {
igLoader.loadIg(getIgs(), getBinaries(), SHCParser.CURRENT_PACKAGE, true);
}
validator.setJurisdiction(jurisdiction);
return validator;
}

View File

@ -60,6 +60,7 @@ POSSIBILITY OF SUCH DAMAGE.
import org.hl7.fhir.r5.model.ImplementationGuide;
import org.hl7.fhir.r5.model.StructureDefinition;
import org.hl7.fhir.r5.terminologies.JurisdictionUtilities;
import org.hl7.fhir.utilities.TimeTracker;
import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.VersionUtilities;
@ -231,6 +232,8 @@ public class ValidatorCli {
if (cliContext.getSv() == null) {
cliContext.setSv(validationService.determineVersion(cliContext));
}
System.out.println(" Jurisdiction: "+JurisdictionUtilities.displayJurisdiction(cliContext.getJurisdiction()));
System.out.println("Loading");
// Comment this out because definitions filename doesn't necessarily contain version (and many not even be 14 characters long).
// Version gets spit out a couple of lines later after we've loaded the context

View File

@ -7,6 +7,8 @@ import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import org.hl7.fhir.r5.terminologies.CodeSystemUtilities;
import org.hl7.fhir.r5.terminologies.JurisdictionUtilities;
import org.hl7.fhir.r5.utils.validation.BundleValidationRule;
import org.hl7.fhir.utilities.VersionUtilities;
import org.hl7.fhir.validation.cli.utils.QuestionnaireMode;
@ -111,7 +113,9 @@ public class CliContext {
// TODO: Mark what goes here?
private List<BundleValidationRule> bundleValidationRules = new ArrayList<>();
@JsonProperty("jurisdiction")
private String jurisdiction = JurisdictionUtilities.getJurisdictionFromLocale(Locale.getDefault().getCountry());
@JsonProperty("map")
public String getMap() {
return map;
@ -564,6 +568,14 @@ public class CliContext {
this.noUnicodeBiDiControlChars = noUnicodeBiDiControlChars;
}
public String getJurisdiction() {
return jurisdiction;
}
public void setJurisdiction(String jurisdiction) {
this.jurisdiction = jurisdiction;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
@ -604,6 +616,7 @@ public class CliContext {
mode == that.mode &&
Objects.equals(locale, that.locale) &&
Objects.equals(outputStyle, that.outputStyle) &&
Objects.equals(jurisdiction, that.jurisdiction) &&
Objects.equals(locations, that.locations);
}
@ -611,7 +624,7 @@ public class CliContext {
public int hashCode() {
return Objects.hash(doNative, extensions, hintAboutNonMustSupport, recursive, doDebug, assumeValidRestReferences, canDoNative, noInternalCaching,
noExtensibleBindingMessages, noInvariants, wantInvariantsInMessages, map, output, htmlOutput, txServer, sv, txLog, txCache, mapLog, lang, fhirpath, snomedCT,
targetVer, igs, questionnaireMode, level, profiles, sources, mode, locale, locations, crumbTrails, showTimes, allowExampleUrls, outputStyle, noUnicodeBiDiControlChars);
targetVer, igs, questionnaireMode, level, profiles, sources, mode, locale, locations, crumbTrails, showTimes, allowExampleUrls, outputStyle, jurisdiction, noUnicodeBiDiControlChars);
}
@Override
@ -650,6 +663,7 @@ public class CliContext {
", securityChecks=" + securityChecks +
", crumbTrails=" + crumbTrails +
", outputStyle=" + outputStyle +
", jurisdiction=" + jurisdiction +
", allowExampleUrls=" + allowExampleUrls +
", showTimes=" + showTimes +
", locale='" + locale + '\'' +

View File

@ -16,6 +16,7 @@ import org.hl7.fhir.r5.renderers.spreadsheets.CodeSystemSpreadsheetGenerator;
import org.hl7.fhir.r5.renderers.spreadsheets.ConceptMapSpreadsheetGenerator;
import org.hl7.fhir.r5.renderers.spreadsheets.StructureDefinitionSpreadsheetGenerator;
import org.hl7.fhir.r5.renderers.spreadsheets.ValueSetSpreadsheetGenerator;
import org.hl7.fhir.r5.terminologies.CodeSystemUtilities;
import org.hl7.fhir.r5.utils.ToolingExtensions;
import org.hl7.fhir.utilities.FhirPublication;
import org.hl7.fhir.utilities.TextFile;
@ -364,6 +365,7 @@ public class ValidationService {
validator.setFetcher(fetcher);
validator.getContext().setLocator(fetcher);
validator.getBundleValidationRules().addAll(cliContext.getBundleValidationRules());
validator.setJurisdiction(CodeSystemUtilities.readCoding(cliContext.getJurisdiction()));
TerminologyCache.setNoCaching(cliContext.isNoInternalCaching());
validator.prepare(); // generate any missing snapshots
System.out.println(" go (" + tt.milestone() + ")");
@ -373,6 +375,7 @@ public class ValidationService {
return sessionId;
}
public String determineVersion(CliContext cliContext) throws Exception {
return determineVersion(cliContext, null);
}

View File

@ -3,6 +3,7 @@ package org.hl7.fhir.validation.cli.utils;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.hl7.fhir.r5.model.Constants;
import org.hl7.fhir.r5.terminologies.JurisdictionUtilities;
import org.hl7.fhir.utilities.VersionUtilities;
import org.hl7.fhir.utilities.npm.FilesystemPackageCacheManager;
import org.hl7.fhir.utilities.npm.ToolsVersion;

View File

@ -1,5 +1,8 @@
package org.hl7.fhir.validation.cli.utils;
import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.r5.terminologies.CodeSystemUtilities;
import org.hl7.fhir.r5.terminologies.JurisdictionUtilities;
import org.hl7.fhir.r5.utils.validation.BundleValidationRule;
import org.hl7.fhir.utilities.VersionUtilities;
import org.hl7.fhir.validation.cli.model.CliContext;
@ -65,6 +68,7 @@ public class Params {
public static final String SHOW_TIMES = "-show-times";
public static final String ALLOW_EXAMPLE_URLS = "-allow-example-urls";
public static final String OUTPUT_STYLE = "-output-style";
private static final Object JURISDICTION = "-jurisdiction";
/**
* Checks the list of passed in params to see if it contains the passed in param.
@ -249,6 +253,11 @@ public class Params {
throw new Error("Specified -language without indicating language");
else
cliContext.setLang(args[++i]);
} else if (args[i].equals(JURISDICTION)) {
if (i + 1 == args.length)
throw new Error("Specified -jurisdiction without indicating jurisdiction");
else
cliContext.setJurisdiction(processJurisdiction(args[++i]));
} else if (args[i].equals(IMPLEMENTATION_GUIDE) || args[i].equals(DEFINITION)) {
if (i + 1 == args.length)
throw new Error("Specified " + args[i] + " without indicating ig file");
@ -290,6 +299,19 @@ public class Params {
return cliContext;
}
private static String processJurisdiction(String s) {
if (s.startsWith("urn:iso:std:iso:3166#") || s.startsWith("urn:iso:std:iso:3166:-2#") || s.startsWith("http://unstats.un.org/unsd/methods/m49/m49.htm#")) {
return s;
} else {
String v = JurisdictionUtilities.getJurisdictionFromLocale(s);
if (v != null) {
return v;
} else {
throw new FHIRException("Unable to understand Jurisdiction '"+s+"'");
}
}
}
public static String getTerminologyServerLog(String[] args) {
String txLog = null;
if (hasParam(args, "-txLog")) {

View File

@ -4529,27 +4529,27 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
public void checkSpecials(ValidatorHostContext hostContext, List<ValidationMessage> errors, Element element, NodeStack stack, boolean checkSpecials) {
// specific known special validations
if (element.getType().equals(BUNDLE)) {
new BundleValidator(context, serverBase, this, xverManager).validateBundle(errors, element, stack, checkSpecials, hostContext);
new BundleValidator(context, serverBase, this, xverManager, jurisdiction).validateBundle(errors, element, stack, checkSpecials, hostContext);
} else if (element.getType().equals("Observation")) {
validateObservation(errors, element, stack);
} else if (element.getType().equals("Questionnaire")) {
new QuestionnaireValidator(context, myEnableWhenEvaluator, fpe, timeTracker, questionnaireMode, xverManager).validateQuestionannaire(errors, element, element, stack);
new QuestionnaireValidator(context, myEnableWhenEvaluator, fpe, timeTracker, questionnaireMode, xverManager, jurisdiction).validateQuestionannaire(errors, element, element, stack);
} else if (element.getType().equals("QuestionnaireResponse")) {
new QuestionnaireValidator(context, myEnableWhenEvaluator, fpe, timeTracker, questionnaireMode, xverManager).validateQuestionannaireResponse(hostContext, errors, element, stack);
new QuestionnaireValidator(context, myEnableWhenEvaluator, fpe, timeTracker, questionnaireMode, xverManager, jurisdiction).validateQuestionannaireResponse(hostContext, errors, element, stack);
} else if (element.getType().equals("Measure")) {
new MeasureValidator(context, timeTracker, xverManager).validateMeasure(hostContext, errors, element, stack);
new MeasureValidator(context, timeTracker, xverManager, jurisdiction).validateMeasure(hostContext, errors, element, stack);
} else if (element.getType().equals("MeasureReport")) {
new MeasureValidator(context, timeTracker, xverManager).validateMeasureReport(hostContext, errors, element, stack);
new MeasureValidator(context, timeTracker, xverManager, jurisdiction).validateMeasureReport(hostContext, errors, element, stack);
} else if (element.getType().equals("CapabilityStatement")) {
validateCapabilityStatement(errors, element, stack);
} else if (element.getType().equals("CodeSystem")) {
new CodeSystemValidator(context, timeTracker, xverManager).validateCodeSystem(errors, element, stack, baseOptions.setLanguage(stack.getWorkingLang()));
new CodeSystemValidator(context, timeTracker, xverManager, jurisdiction).validateCodeSystem(errors, element, stack, baseOptions.setLanguage(stack.getWorkingLang()));
} else if (element.getType().equals("SearchParameter")) {
new SearchParameterValidator(context, timeTracker, fpe, xverManager).validateSearchParameter(errors, element, stack);
new SearchParameterValidator(context, timeTracker, fpe, xverManager, jurisdiction).validateSearchParameter(errors, element, stack);
} else if (element.getType().equals("StructureDefinition")) {
new StructureDefinitionValidator(context, timeTracker, fpe, wantCheckSnapshotUnchanged, xverManager).validateStructureDefinition(errors, element, stack);
new StructureDefinitionValidator(context, timeTracker, fpe, wantCheckSnapshotUnchanged, xverManager, jurisdiction).validateStructureDefinition(errors, element, stack);
} else if (element.getType().equals("ValueSet")) {
new ValueSetValidator(context, timeTracker, this, xverManager).validateValueSet(errors, element, stack);
new ValueSetValidator(context, timeTracker, this, xverManager, jurisdiction).validateValueSet(errors, element, stack);
}
}
@ -5954,7 +5954,6 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
child.setParentForValidator(element);
setParentsInner(child);
}
}
public void setQuestionnaireMode(QuestionnaireMode questionnaireMode) {
@ -5989,4 +5988,13 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
this.noUnicodeBiDiControlChars = noUnicodeBiDiControlChars;
}
public Coding getJurisdiction() {
return jurisdiction;
}
public IResourceValidator setJurisdiction(Coding jurisdiction) {
this.jurisdiction = jurisdiction;
return this;
}
}

View File

@ -10,6 +10,7 @@ import java.util.Set;
import org.apache.commons.lang3.StringUtils;
import org.hl7.fhir.r5.context.IWorkerContext;
import org.hl7.fhir.r5.elementmodel.Element;
import org.hl7.fhir.r5.model.Coding;
import org.hl7.fhir.r5.model.Constants;
import org.hl7.fhir.r5.model.Enumerations.FHIRVersion;
import org.hl7.fhir.r5.model.StructureDefinition;
@ -32,10 +33,11 @@ public class BundleValidator extends BaseValidator {
private String serverBase;
private InstanceValidator validator;
public BundleValidator(IWorkerContext context, String serverBase, InstanceValidator validator, XVerExtensionManager xverManager) {
public BundleValidator(IWorkerContext context, String serverBase, InstanceValidator validator, XVerExtensionManager xverManager, Coding jurisdiction) {
super(context, xverManager);
this.serverBase = serverBase;
this.validator = validator;
this.jurisdiction = jurisdiction;
}
public void validateBundle(List<ValidationMessage> errors, Element bundle, NodeStack stack, boolean checkSpecials, ValidatorHostContext hostContext) {

View File

@ -6,6 +6,7 @@ import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.r5.context.IWorkerContext;
import org.hl7.fhir.r5.elementmodel.Element;
import org.hl7.fhir.r5.model.CodeSystem;
import org.hl7.fhir.r5.model.Coding;
import org.hl7.fhir.r5.model.ValueSet;
import org.hl7.fhir.r5.utils.XVerExtensionManager;
import org.hl7.fhir.utilities.Utilities;
@ -22,10 +23,12 @@ import ca.uhn.fhir.validation.ValidationResult;
public class CodeSystemValidator extends BaseValidator {
public CodeSystemValidator(IWorkerContext context, TimeTracker timeTracker, XVerExtensionManager xverManager) {
public CodeSystemValidator(IWorkerContext context, TimeTracker timeTracker, XVerExtensionManager xverManager, Coding jurisdiction) {
super(context, xverManager);
source = Source.InstanceValidator;
this.timeTracker = timeTracker;
this.jurisdiction = jurisdiction;
}
public void validateCodeSystem(List<ValidationMessage> errors, Element cs, NodeStack stack, ValidationOptions options) {

View File

@ -42,10 +42,12 @@ import org.w3c.dom.Document;
public class MeasureValidator extends BaseValidator {
public MeasureValidator(IWorkerContext context, TimeTracker timeTracker, XVerExtensionManager xverManager) {
public MeasureValidator(IWorkerContext context, TimeTracker timeTracker, XVerExtensionManager xverManager, Coding jurisdiction) {
super(context, xverManager);
source = Source.InstanceValidator;
this.timeTracker = timeTracker;
this.jurisdiction = jurisdiction;
}
public void validateMeasure(ValidatorHostContext hostContext, List<ValidationMessage> errors, Element element, NodeStack stack) throws FHIRException {

View File

@ -119,13 +119,14 @@ public class QuestionnaireValidator extends BaseValidator {
private FHIRPathEngine fpe;
private QuestionnaireMode questionnaireMode;
public QuestionnaireValidator(IWorkerContext context, EnableWhenEvaluator myEnableWhenEvaluator, FHIRPathEngine fpe, TimeTracker timeTracker, QuestionnaireMode questionnaireMode, XVerExtensionManager xverManager) {
public QuestionnaireValidator(IWorkerContext context, EnableWhenEvaluator myEnableWhenEvaluator, FHIRPathEngine fpe, TimeTracker timeTracker, QuestionnaireMode questionnaireMode, XVerExtensionManager xverManager, Coding jurisdiction) {
super(context, xverManager);
source = Source.InstanceValidator;
this.myEnableWhenEvaluator = myEnableWhenEvaluator;
this.fpe = fpe;
this.timeTracker = timeTracker;
this.questionnaireMode = questionnaireMode;
this.jurisdiction = jurisdiction;
}
public void validateQuestionannaire(List<ValidationMessage> errors, Element element, Element element2, NodeStack stack) {

View File

@ -7,6 +7,7 @@ import java.util.List;
import org.hl7.fhir.r5.context.IWorkerContext;
import org.hl7.fhir.r5.elementmodel.Element;
import org.hl7.fhir.r5.model.Coding;
import org.hl7.fhir.r5.model.ExpressionNode;
import org.hl7.fhir.r5.model.ExpressionNode.Kind;
import org.hl7.fhir.r5.model.ExpressionNode.Operation;
@ -35,11 +36,12 @@ public class SearchParameterValidator extends BaseValidator {
private FHIRPathEngine fpe;
public SearchParameterValidator(IWorkerContext context, TimeTracker timeTracker, FHIRPathEngine fpe, XVerExtensionManager xverManager) {
public SearchParameterValidator(IWorkerContext context, TimeTracker timeTracker, FHIRPathEngine fpe, XVerExtensionManager xverManager, Coding jurisdiction) {
super(context, xverManager);
source = Source.InstanceValidator;
this.fpe = fpe;
this.timeTracker = timeTracker;
this.jurisdiction = jurisdiction;
}
public void validateSearchParameter(List<ValidationMessage> errors, Element cs, NodeStack stack) {

View File

@ -56,12 +56,13 @@ public class StructureDefinitionValidator extends BaseValidator {
private FHIRPathEngine fpe;
private boolean wantCheckSnapshotUnchanged;
public StructureDefinitionValidator(IWorkerContext context, TimeTracker timeTracker, FHIRPathEngine fpe, boolean wantCheckSnapshotUnchanged, XVerExtensionManager xverManager) {
public StructureDefinitionValidator(IWorkerContext context, TimeTracker timeTracker, FHIRPathEngine fpe, boolean wantCheckSnapshotUnchanged, XVerExtensionManager xverManager, Coding jurisdiction) {
super(context, xverManager);
source = Source.InstanceValidator;
this.fpe = fpe;
this.timeTracker = timeTracker;
this.wantCheckSnapshotUnchanged = wantCheckSnapshotUnchanged;
this.jurisdiction = jurisdiction;
}
public void validateStructureDefinition(List<ValidationMessage> errors, Element src, NodeStack stack) {

View File

@ -43,11 +43,13 @@ public class ValueSetValidator extends BaseValidator {
private InstanceValidator parent;
public ValueSetValidator(IWorkerContext context, TimeTracker timeTracker, InstanceValidator parent, XVerExtensionManager xverManager) {
public ValueSetValidator(IWorkerContext context, TimeTracker timeTracker, InstanceValidator parent, XVerExtensionManager xverManager, Coding jurisdiction) {
super(context, xverManager);
source = Source.InstanceValidator;
this.timeTracker = timeTracker;
this.parent = parent;
this.jurisdiction = jurisdiction;
}
public void validateValueSet(List<ValidationMessage> errors, Element vs, NodeStack stack) {