fix questionnaire mode support for validator

This commit is contained in:
Grahame Grieve 2020-09-30 09:23:54 +10:00
parent 510344aa1b
commit bcb2d8e148
10 changed files with 82 additions and 46 deletions

View File

@ -133,11 +133,11 @@ Terminology_TX_Code_ValueSetMax = No code provided, and a code must be provided
Terminology_TX_Code_ValueSet_Ext = No code provided, and a code should be provided from the value set {0} ({1})
Terminology_TX_Coding_Count = Expected {0} but found {1} coding elements
Terminology_TX_Confirm_1 = Could not confirm that the codes provided are in the value set {0} and a code from this value set is required (class = {1})
Terminology_TX_Confirm_2 = Could not confirm that the codes provided are in the value set {0} and a code should come from this value set unless it has no suitable code (class = {1})
Terminology_TX_Confirm_2 = Could not confirm that the codes provided are in the value set {0} and a code should come from this value set unless it has no suitable code (the validator cannot judge what is suitable) (class = {1})
Terminology_TX_Confirm_3 = Could not confirm that the codes provided are in the value set {0} and a code is recommended to come from this value set (class = {1})
Terminology_TX_Confirm_4a = The code provided ({2}) is not in the value set {0}, and a code from this value set is required: {1}
Terminology_TX_Confirm_4b = The codes provided ({2}) are not in the value set {0}, and a code from this value set is required: {1}
Terminology_TX_Confirm_5 = Could not confirm that the codes provided are in the value set {0}, and a code should come from this value set unless it has no suitable code
Terminology_TX_Confirm_5 = Could not confirm that the codes provided are in the value set {0}, and a code should come from this value set unless it has no suitable code (the validator cannot judge what is suitable)
Terminology_TX_Confirm_6 = Could not confirm that the codes provided are in the value set {0}, and a code is recommended to come from this value set
Terminology_TX_Display_Wrong = Display should be ''{0}''
Terminology_TX_Error_CodeableConcept = Error {0} validating CodeableConcept
@ -148,16 +148,16 @@ Terminology_TX_NoValid_1 = None of the codes provided are in the value set {0} (
Terminology_TX_NoValid_10 = The code provided is not in the maximum value set {0} ({1}), and a code from this value set is required) (code = {2}#{3})
Terminology_TX_NoValid_11 = The code provided is not in the maximum value set {0} ({1}{2})
Terminology_TX_NoValid_12 = The Coding provided ({2}) is not in the value set {0}, and a code is required from this value set. {1}
Terminology_TX_NoValid_13 = The Coding provided ({2}) is not in the value set {0}, and a code should come from this value set unless it has no suitable code. {1}
Terminology_TX_NoValid_13 = The Coding provided ({2}) is not in the value set {0}, and a code should come from this value set unless it has no suitable code (the validator cannot judge what is suitable). {1}
Terminology_TX_NoValid_14 = The Coding provided ({2}) is not in the value set {0}, and a code is recommended to come from this value set. {1}
Terminology_TX_NoValid_15 = The value provided (''{0}'') could not be validated in the absence of a terminology server
Terminology_TX_NoValid_16 = The value provided (''{0}'') is not in the value set {1} ({2}), and a code is required from this value set){3}
Terminology_TX_NoValid_17 = The value provided (''{0}'') is not in the value set {1} ({2}), and a code should come from this value set unless it has no suitable code){3}
Terminology_TX_NoValid_17 = The value provided (''{0}'') is not in the value set {1} ({2}), and a code should come from this value set unless it has no suitable code and the validator cannot judge what is suitable){3}
Terminology_TX_NoValid_18 = The value provided (''{0}'') is not in the value set {1} ({2}), and a code is recommended to come from this value set){3}
Terminology_TX_NoValid_2 = None of the codes provided are in the value set {0} ({1}), and a code should come from this value set unless it has no suitable code) (codes = {2})
Terminology_TX_NoValid_2 = None of the codes provided are in the value set {0} ({1}), and a code should come from this value set unless it has no suitable code and the validator cannot judge what is suitable) (codes = {2})
Terminology_TX_NoValid_3 = None of the codes provided are in the value set {0} ({1}), and a code is recommended to come from this value set) (codes = {2})
Terminology_TX_NoValid_4 = The Coding provided ({2}) is not in the value set {0}, and a code is required from this value set {1}
Terminology_TX_NoValid_5 = The Coding provided ({2}) is not in the value set {0}, and a code should come from this value set unless it has no suitable code {1}
Terminology_TX_NoValid_5 = The Coding provided ({2}) is not in the value set {0}, and a code should come from this value set unless it has no suitable code (the validator cannot judge what is suitable) {1}
Terminology_TX_NoValid_6 = The Coding provided ({2}) is not in the value set {0}, and a code is recommended to come from this value set {1}
Terminology_TX_NoValid_7 = None of the codes provided could be validated against the maximum value set {0} ({1}), (error = {2})
Terminology_TX_NoValid_8 = None of the codes provided are in the maximum value set {0} ({1}), and a code from this value set is required) (codes = {2})

View File

@ -34,7 +34,13 @@ import org.hl7.fhir.r5.utils.*;
import org.hl7.fhir.r5.utils.IResourceValidator.*;
import org.hl7.fhir.r5.utils.StructureMapUtilities.ITransformerServices;
import org.hl7.fhir.utilities.i18n.I18nConstants;
import org.hl7.fhir.utilities.npm.BasePackageCacheManager;
import org.hl7.fhir.utilities.npm.FilesystemPackageCacheManager;
import org.hl7.fhir.utilities.npm.NpmPackage;
import org.hl7.fhir.utilities.npm.PackageClient;
import org.hl7.fhir.utilities.npm.ToolsVersion;
import org.hl7.fhir.validation.BaseValidator.ValidationControl;
import org.hl7.fhir.validation.Validator.QuestionnaireMode;
import org.hl7.fhir.validation.cli.services.StandAloneValidatorFetcher.IPackageInstaller;
import org.hl7.fhir.validation.instance.InstanceValidator;
import org.hl7.fhir.utilities.IniFile;
@ -42,11 +48,6 @@ import org.hl7.fhir.utilities.TextFile;
import org.hl7.fhir.utilities.TimeTracker;
import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.VersionUtilities;
import org.hl7.fhir.utilities.cache.NpmPackage;
import org.hl7.fhir.utilities.cache.PackageClient;
import org.hl7.fhir.utilities.cache.BasePackageCacheManager;
import org.hl7.fhir.utilities.cache.FilesystemPackageCacheManager;
import org.hl7.fhir.utilities.cache.ToolsVersion;
import org.hl7.fhir.utilities.i18n.I18nBase;
import org.hl7.fhir.utilities.i18n.I18nConstants;
import org.hl7.fhir.utilities.validation.ValidationMessage;
@ -311,6 +312,7 @@ public class ValidationEngine implements IValidatorResourceFetcher, IPackageInst
private boolean showTimes;
private List<BundleValidationRule> bundleValidationRules = new ArrayList<>();
private Map<String, ValidationControl> validationControl = new HashMap<>();
private QuestionnaireMode questionnaireMode;
private class AsteriskFilter implements FilenameFilter {
String dir;
@ -531,7 +533,7 @@ public class ValidationEngine implements IValidatorResourceFetcher, IPackageInst
v = src.substring(src.indexOf("|")+1);
src = src.substring(0, src.indexOf("|"));
}
String pid = pcm.getPackageId(src);
String pid = explore ? pcm.getPackageId(src) : null;
if (!Utilities.noString(pid))
return fetchByPackage(pid+(v == null ? "" : "#"+v));
else
@ -563,7 +565,7 @@ public class ValidationEngine implements IValidatorResourceFetcher, IPackageInst
} else if ((src.matches(FilesystemPackageCacheManager.PACKAGE_REGEX) || src.matches(FilesystemPackageCacheManager.PACKAGE_VERSION_REGEX)) && !src.endsWith(".zip") && !src.endsWith(".tgz")) {
return fetchByPackage(src);
}
throw new FHIRException("Unable to find/resolve/read -ig "+src);
throw new FHIRException("Unable to find/resolve/read "+(explore ? "-ig " : "")+src);
}
private Map<String, byte[]> loadIgSourceForVersion(String src, boolean recursive, boolean explore, VersionSourceInformation versions) throws FHIRException, IOException {
@ -705,7 +707,20 @@ public class ValidationEngine implements IValidatorResourceFetcher, IPackageInst
res.put(Utilities.changeFileExt(src, "."+fmt.getExtension()), cnt);
return res;
}
throw new FHIRException("Unable to find/resolve/read -ig "+src);
String fn = Utilities.path("[tmp]", "fetch-resource-error-content.bin");
TextFile.bytesToFile(cnt, fn);
System.out.println("Error Fetching "+src);
System.out.println("Some content was found, saved to "+fn);
System.out.println("1st 100 bytes = "+presentForDebugging(cnt));
throw new FHIRException("Unable to find/resolve/read "+(explore ? "-ig " : "")+src);
}
private String presentForDebugging(byte[] cnt) {
StringBuilder b = new StringBuilder();
for (int i = 0; i < Integer.min(cnt.length, 50); i++) {
b.append(Integer.toHexString(cnt[i]));
}
return b.toString();
}
private InputStream fetchFromUrlSpecific(String source, boolean optional) throws FHIRException, IOException {
@ -1142,7 +1157,8 @@ public class ValidationEngine implements IValidatorResourceFetcher, IPackageInst
}
}
public void setQuestionnaires(List<String> questionnaires) {
public void setQuestionnaireMode(Validator.QuestionnaireMode questionnaireMode) {
this.questionnaireMode = questionnaireMode;
}
public void setNative(boolean doNative) {
@ -1614,6 +1630,7 @@ public class ValidationEngine implements IValidatorResourceFetcher, IPackageInst
validator.getImplementationGuides().addAll(igs);
validator.getBundleValidationRules().addAll(bundleValidationRules);
validator.getValidationControl().putAll(validationControl );
validator.setQuestionnaireMode(questionnaireMode);
return validator;
}

View File

@ -91,6 +91,8 @@ public class Validator {
public enum EngineMode {
VALIDATION, TRANSFORM, NARRATIVE, SNAPSHOT, SCAN, CONVERT, FHIRPATH, VERSION
}
public enum QuestionnaireMode { NONE, CHECK, REQUIRED }
private static CliContext cliContext;

View File

@ -54,8 +54,9 @@ public class CliContext {
@JsonProperty("igs")
private List<String> igs = new ArrayList<String>();
@JsonProperty("questionnaires")
private List<String> questionnaires = new ArrayList<String>();
@JsonProperty("questionnaire")
private Validator.QuestionnaireMode questionnaireMode = Validator.QuestionnaireMode.CHECK;
@JsonProperty("profiles")
private List<String> profiles = new ArrayList<String>();
@JsonProperty("sources")
@ -118,22 +119,14 @@ public class CliContext {
return this;
}
@JsonProperty("questionnaires")
public List<String> getQuestionnaires() {
return questionnaires;
@JsonProperty("questionnaire")
public Validator.QuestionnaireMode getQuestionnaireMode() {
return questionnaireMode;
}
@JsonProperty("questionnaires")
public CliContext setQuestionnaires(List<String> questionnaires) {
this.questionnaires = questionnaires;
return this;
}
public CliContext addQuestionnaire(String questionnaire) {
if (this.questionnaires == null) {
this.questionnaires = new ArrayList<>();
}
this.questionnaires.add(questionnaire);
@JsonProperty("questionnaire")
public CliContext setQuestionnaireMode(Validator.QuestionnaireMode questionnaireMode) {
this.questionnaireMode = questionnaireMode;
return this;
}
@ -482,7 +475,7 @@ public class CliContext {
Objects.equals(snomedCT, that.snomedCT) &&
Objects.equals(targetVer, that.targetVer) &&
Objects.equals(igs, that.igs) &&
Objects.equals(questionnaires, that.questionnaires) &&
Objects.equals(questionnaireMode, that.questionnaireMode) &&
Objects.equals(profiles, that.profiles) &&
Objects.equals(sources, that.sources) &&
Objects.equals(crumbTrails, that.crumbTrails) &&
@ -494,6 +487,6 @@ public class CliContext {
@Override
public int hashCode() {
return Objects.hash(doNative, anyExtensionsAllowed, hintAboutNonMustSupport, recursive, doDebug, assumeValidRestReferences, canDoNative, noInternalCaching, noExtensibleBindingMessages, map, output, txServer, sv, txLog, mapLog, lang, fhirpath, snomedCT, targetVer, igs, questionnaires, profiles, sources, mode, locale, locations, crumbTrails, showTimes);
return Objects.hash(doNative, anyExtensionsAllowed, hintAboutNonMustSupport, recursive, doDebug, assumeValidRestReferences, canDoNative, noInternalCaching, noExtensibleBindingMessages, map, output, txServer, sv, txLog, mapLog, lang, fhirpath, snomedCT, targetVer, igs, questionnaireMode, profiles, sources, mode, locale, locations, crumbTrails, showTimes);
}
}

View File

@ -14,9 +14,9 @@ import org.hl7.fhir.r5.utils.IResourceValidator.ReferenceValidationPolicy;
import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.VersionUtilities;
import org.hl7.fhir.utilities.VersionUtilities.VersionURLInfo;
import org.hl7.fhir.utilities.cache.BasePackageCacheManager;
import org.hl7.fhir.utilities.cache.FilesystemPackageCacheManager;
import org.hl7.fhir.utilities.cache.NpmPackage;
import org.hl7.fhir.utilities.npm.BasePackageCacheManager;
import org.hl7.fhir.utilities.npm.FilesystemPackageCacheManager;
import org.hl7.fhir.utilities.npm.NpmPackage;
import org.hl7.fhir.validation.cli.services.StandAloneValidatorFetcher.IPackageInstaller;
public class StandAloneValidatorFetcher implements IValidatorResourceFetcher {

View File

@ -203,7 +203,7 @@ public class ValidationService {
validator.loadIg(src, cliContext.isRecursive());
}
System.out.print(" Get set... ");
validator.setQuestionnaires(cliContext.getQuestionnaires());
validator.setQuestionnaireMode(cliContext.getQuestionnaireMode());
validator.setNative(cliContext.isDoNative());
validator.setHintAboutNonMustSupport(cliContext.isHintAboutNonMustSupport());
validator.setAnyExtensionsAllowed(cliContext.isAnyExtensionsAllowed());

View File

@ -2,8 +2,8 @@ package org.hl7.fhir.validation.cli.utils;
import org.hl7.fhir.r5.model.Constants;
import org.hl7.fhir.utilities.VersionUtilities;
import org.hl7.fhir.utilities.cache.FilesystemPackageCacheManager;
import org.hl7.fhir.utilities.cache.ToolsVersion;
import org.hl7.fhir.utilities.npm.FilesystemPackageCacheManager;
import org.hl7.fhir.utilities.npm.ToolsVersion;
import java.io.IOException;

View File

@ -122,8 +122,10 @@ public class Params {
} else if (args[i].equals(QUESTIONNAIRE)) {
if (i + 1 == args.length)
throw new Error("Specified -questionnaire without indicating questionnaire file");
else
cliContext.addQuestionnaire(args[++i]);
else {
String q = args[++i];
cliContext.setQuestionnaireMode(Validator.QuestionnaireMode.valueOf(q));
}
} else if (args[i].equals(NATIVE)) {
cliContext.setDoNative(true);
} else if (args[i].equals(ASSUME_VALID_REST_REF)) {

View File

@ -140,6 +140,7 @@ import org.hl7.fhir.r5.utils.ToolingExtensions;
import org.hl7.fhir.r5.utils.XVerExtensionManager;
import org.hl7.fhir.utilities.i18n.I18nConstants;
import org.hl7.fhir.validation.BaseValidator;
import org.hl7.fhir.validation.Validator.QuestionnaireMode;
import org.hl7.fhir.validation.instance.type.BundleValidator;
import org.hl7.fhir.validation.instance.type.CodeSystemValidator;
import org.hl7.fhir.validation.instance.type.MeasureValidator;
@ -375,6 +376,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
private boolean crumbTrails;
private List<BundleValidationRule> bundleValidationRules = new ArrayList<>();
private boolean validateValueSetCodesOnTxServer = true;
private QuestionnaireMode questionnaireMode;
public InstanceValidator(IWorkerContext theContext, IEvaluationContext hostServices) {
super(theContext);
@ -3844,9 +3846,9 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
} else if (element.getType().equals("Observation")) {
validateObservation(errors, element, stack);
} else if (element.getType().equals("Questionnaire")) {
new QuestionnaireValidator(context, myEnableWhenEvaluator, fpe, timeTracker).validateQuestionannaire(errors, element, element, stack);
new QuestionnaireValidator(context, myEnableWhenEvaluator, fpe, timeTracker, questionnaireMode).validateQuestionannaire(errors, element, element, stack);
} else if (element.getType().equals("QuestionnaireResponse")) {
new QuestionnaireValidator(context, myEnableWhenEvaluator, fpe, timeTracker).validateQuestionannaireResponse(hostContext, errors, element, stack);
new QuestionnaireValidator(context, myEnableWhenEvaluator, fpe, timeTracker, questionnaireMode).validateQuestionannaireResponse(hostContext, errors, element, stack);
} else if (element.getType().equals("Measure")) {
new MeasureValidator(context, timeTracker).validateMeasure(hostContext, errors, element, stack);
} else if (element.getType().equals("MeasureReport")) {
@ -5081,4 +5083,12 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
}
public void setQuestionnaireMode(QuestionnaireMode questionnaireMode) {
this.questionnaireMode = questionnaireMode;
}
public QuestionnaireMode getQuestionnaireMode() {
return questionnaireMode;
}
}

View File

@ -45,6 +45,7 @@ import org.hl7.fhir.utilities.validation.ValidationMessage.IssueType;
import org.hl7.fhir.utilities.validation.ValidationMessage.Source;
import org.hl7.fhir.validation.BaseValidator;
import org.hl7.fhir.validation.TimeTracker;
import org.hl7.fhir.validation.Validator.QuestionnaireMode;
import org.hl7.fhir.validation.instance.EnableWhenEvaluator;
import org.hl7.fhir.validation.instance.EnableWhenEvaluator.QStack;
import org.hl7.fhir.validation.instance.utils.NodeStack;
@ -56,13 +57,15 @@ public class QuestionnaireValidator extends BaseValidator {
private EnableWhenEvaluator myEnableWhenEvaluator;
private FHIRPathEngine fpe;
private QuestionnaireMode questionnaireMode;
public QuestionnaireValidator(IWorkerContext context, EnableWhenEvaluator myEnableWhenEvaluator, FHIRPathEngine fpe, TimeTracker timeTracker) {
public QuestionnaireValidator(IWorkerContext context, EnableWhenEvaluator myEnableWhenEvaluator, FHIRPathEngine fpe, TimeTracker timeTracker, QuestionnaireMode questionnaireMode) {
super(context);
source = Source.InstanceValidator;
this.myEnableWhenEvaluator = myEnableWhenEvaluator;
this.fpe = fpe;
this.timeTracker = timeTracker;
this.questionnaireMode = questionnaireMode;
}
public void validateQuestionannaire(List<ValidationMessage> errors, Element element, Element element2, NodeStack stack) {
@ -164,6 +167,9 @@ public class QuestionnaireValidator extends BaseValidator {
}
public void validateQuestionannaireResponse(ValidatorHostContext hostContext, List<ValidationMessage> errors, Element element, NodeStack stack) throws FHIRException {
if (questionnaireMode == QuestionnaireMode.NONE) {
return;
}
Element q = element.getNamedChild("questionnaire");
String questionnaire = null;
if (q != null) {
@ -179,9 +185,15 @@ public class QuestionnaireValidator extends BaseValidator {
questionnaire = q.getChildValue("reference");
}
}
if (hint(errors, IssueType.REQUIRED, element.line(), element.col(), stack.getLiteralPath(), questionnaire != null, I18nConstants.QUESTIONNAIRE_QR_Q_NONE)) {
boolean ok = questionnaireMode == QuestionnaireMode.REQUIRED ?
rule(errors, IssueType.REQUIRED, element.line(), element.col(), stack.getLiteralPath(), questionnaire != null, I18nConstants.QUESTIONNAIRE_QR_Q_NONE) :
hint(errors, IssueType.REQUIRED, element.line(), element.col(), stack.getLiteralPath(), questionnaire != null, I18nConstants.QUESTIONNAIRE_QR_Q_NONE);
if (ok) {
Questionnaire qsrc = questionnaire.startsWith("#") ? loadQuestionnaire(element, questionnaire.substring(1)) : context.fetchResource(Questionnaire.class, questionnaire);
if (warning(errors, IssueType.REQUIRED, q.line(), q.col(), stack.getLiteralPath(), qsrc != null, I18nConstants.QUESTIONNAIRE_QR_Q_NOTFOUND, questionnaire)) {
ok = questionnaireMode == QuestionnaireMode.REQUIRED ?
rule(errors, IssueType.REQUIRED, q.line(), q.col(), stack.getLiteralPath(), qsrc != null, I18nConstants.QUESTIONNAIRE_QR_Q_NOTFOUND, questionnaire) :
warning(errors, IssueType.REQUIRED, q.line(), q.col(), stack.getLiteralPath(), qsrc != null, I18nConstants.QUESTIONNAIRE_QR_Q_NOTFOUND, questionnaire);
if (ok) {
boolean inProgress = "in-progress".equals(element.getNamedChildValue("status"));
validateQuestionannaireResponseItems(hostContext, qsrc, qsrc.getItem(), errors, element, stack, inProgress, element, new QStack(qsrc, element));
}