better validation of derived valuesets + better handling of validation failures on UCUM when no terminology server

This commit is contained in:
Grahame Grieve 2023-07-05 07:22:30 +10:00
parent 29e9f28add
commit 7166d55153
4 changed files with 44 additions and 6 deletions

View File

@ -51,6 +51,7 @@ import org.hl7.fhir.r5.conformance.ElementRedirection;
import org.hl7.fhir.r5.conformance.profile.ProfileUtilities.AllowUnknownProfile;
import org.hl7.fhir.r5.conformance.profile.ProfileUtilities.ElementDefinitionCounter;
import org.hl7.fhir.r5.context.IWorkerContext;
import org.hl7.fhir.r5.context.IWorkerContext.ValidationResult;
import org.hl7.fhir.r5.elementmodel.ObjectConverter;
import org.hl7.fhir.r5.elementmodel.Property;
import org.hl7.fhir.r5.model.Base;
@ -2599,9 +2600,23 @@ public class ProfileUtilities extends TranslatingUtilities {
messages.add(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.BUSINESSRULE, pn+"."+base.getPath(), "Binding "+base.getBinding().getValueSet()+" could not be expanded", ValidationMessage.IssueSeverity.WARNING));
else if (expDerived.getValueset() == null)
messages.add(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.BUSINESSRULE, pn+"."+derived.getPath(), "Binding "+derived.getBinding().getValueSet()+" could not be expanded", ValidationMessage.IssueSeverity.WARNING));
else if (ToolingExtensions.hasExtension(expBase.getValueset().getExpansion(), ToolingExtensions.EXT_EXP_TOOCOSTLY))
messages.add(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.BUSINESSRULE, pn+"."+derived.getPath(), "Unable to check if "+derived.getBinding().getValueSet()+" is a proper subset of " +base.getBinding().getValueSet()+" - base value set is too large to check", ValidationMessage.IssueSeverity.WARNING));
else if (!isSubset(expBase.getValueset(), expDerived.getValueset()))
else if (ToolingExtensions.hasExtension(expBase.getValueset().getExpansion(), ToolingExtensions.EXT_EXP_TOOCOSTLY)) {
if (ToolingExtensions.hasExtension(expDerived.getValueset().getExpansion(), ToolingExtensions.EXT_EXP_TOOCOSTLY) || expDerived.getValueset().getExpansion().getContains().size() > 100) {
messages.add(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.BUSINESSRULE, pn+"."+derived.getPath(), "Unable to check if "+derived.getBinding().getValueSet()+" is a proper subset of " +base.getBinding().getValueSet()+" - base value set is too large to check", ValidationMessage.IssueSeverity.WARNING));
} else {
boolean ok = true;
for (ValueSetExpansionContainsComponent cc : expDerived.getValueset().getExpansion().getContains()) {
ValidationResult vr = context.validateCode(null, cc.getSystem(), cc.getVersion(), cc.getCode(), null, baseVs);
if (!vr.isOk()) {
ok = false;
break;
}
}
if (!ok) {
messages.add(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.BUSINESSRULE, pn+"."+derived.getPath(), "Binding "+derived.getBinding().getValueSet()+" is not a subset of binding "+base.getBinding().getValueSet(), ValidationMessage.IssueSeverity.ERROR));
}
}
} else if (!isSubset(expBase.getValueset(), expDerived.getValueset()))
messages.add(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.BUSINESSRULE, pn+"."+derived.getPath(), "Binding "+derived.getBinding().getValueSet()+" is not a subset of binding "+base.getBinding().getValueSet(), ValidationMessage.IssueSeverity.ERROR));
}
}

View File

@ -1066,6 +1066,7 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
Set<String> unknownSystems = new HashSet<>();
String localError = null;
String localWarning = null;
if (options.isUseClient()) {
// ok, first we try to validate locally
try {
@ -1080,7 +1081,11 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
return res;
}
} catch (VSCheckerException e) {
localError = e.getMessage();
if (e.isWarning()) {
localWarning = e.getMessage();
} else {
localError = e.getMessage();
}
if (e.getIssues() != null) {
issues.addAll(e.getIssues());
}
@ -1097,8 +1102,15 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
return new ValidationResult(IssueSeverity.ERROR, localError, TerminologyServiceErrorClass.UNKNOWN, issues);
}
}
if (localWarning != null && tcc.getClient() == null) {
return new ValidationResult(IssueSeverity.WARNING,formatMessage(I18nConstants.UNABLE_TO_VALIDATE_CODE_WITHOUT_USING_SERVER, localWarning), TerminologyServiceErrorClass.BLOCKED_BY_OPTIONS, issues);
}
if (!options.isUseServer()) {
return new ValidationResult(IssueSeverity.WARNING,formatMessage(I18nConstants.UNABLE_TO_VALIDATE_CODE_WITHOUT_USING_SERVER, localError), TerminologyServiceErrorClass.BLOCKED_BY_OPTIONS, issues);
if (localWarning != null) {
return new ValidationResult(IssueSeverity.WARNING,formatMessage(I18nConstants.UNABLE_TO_VALIDATE_CODE_WITHOUT_USING_SERVER, localWarning), TerminologyServiceErrorClass.BLOCKED_BY_OPTIONS, issues);
} else {
return new ValidationResult(IssueSeverity.WARNING,formatMessage(I18nConstants.UNABLE_TO_VALIDATE_CODE_WITHOUT_USING_SERVER, localError), TerminologyServiceErrorClass.BLOCKED_BY_OPTIONS, issues);
}
}
String codeKey = getCodeKey(code);
if (unsupportedCodeSystems.contains(codeKey)) {

View File

@ -8,16 +8,27 @@ import org.hl7.fhir.r5.model.OperationOutcome.OperationOutcomeIssueComponent;
public class VSCheckerException extends FHIRException {
private List<OperationOutcomeIssueComponent> issues;
private boolean warning;
public VSCheckerException(String message, List<OperationOutcomeIssueComponent> issues) {
super(message);
this.issues = issues;
}
public VSCheckerException(String message, List<OperationOutcomeIssueComponent> issues, boolean warning) {
super(message);
this.issues = issues;
this.warning = warning;
}
public List<OperationOutcomeIssueComponent> getIssues() {
return issues;
}
private static final long serialVersionUID = -5889505119633054187L;
public boolean isWarning() {
return warning;
}
}

View File

@ -435,7 +435,7 @@ public class ValueSetValidator {
if (cs!=null && cs.getContent() != CodeSystemContentMode.COMPLETE) {
warningMessage = "Resolved system "+system+(cs.hasVersion() ? " (v"+cs.getVersion()+")" : "")+", but the definition is not complete";
if (!inExpansion && cs.getContent() != CodeSystemContentMode.FRAGMENT) { // we're going to give it a go if it's a fragment
throw new VSCheckerException(warningMessage, null);
throw new VSCheckerException(warningMessage, null, true);
}
}