diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/InstanceValidator.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/InstanceValidator.java index 675d3b849..d27ca99f6 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/InstanceValidator.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/InstanceValidator.java @@ -1118,7 +1118,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat timeTracker.tx(t, "vc "+system+"#"+code+" '"+display+"'"); if (s == null) return true; - ok = calculateSeverityForIssuesAndUpdateErrors(errors, s, element, path, false, null, null) & ok; + ok = calculateSeverityForTxIssuesAndUpdateErrors(errors, s, element, path, false, null, null) & ok; if (s.isOk()) { if (s.getMessage() != null && !s.messageIsInIssues()) { @@ -1375,7 +1375,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat if (cc.hasCoding()) { long t = System.nanoTime(); ValidationResult vr = checkCodeOnServer(stack, null, cc); - bh.see(calculateSeverityForIssuesAndUpdateErrors(errors, vr, element, path, false, null, null)); + bh.see(calculateSeverityForTxIssuesAndUpdateErrors(errors, vr, element, path, false, null, null)); timeTracker.tx(t, "vc " + cc.toString()); } } catch (CheckCodeOnServerException e) { @@ -1620,7 +1620,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat } else { checked.set(true); ValidationResult vr = checkCodeOnServer(stack, valueset, cc); - bh.see(calculateSeverityForIssuesAndUpdateErrors(errors, vr, element, path, false, vsRef, strength)); + bh.see(calculateSeverityForTxIssuesAndUpdateErrors(errors, vr, element, path, false, vsRef, strength)); if (!vr.isOk()) { bindingsOk = false; if (vr.getErrorClass() != null && vr.getErrorClass() == TerminologyServiceErrorClass.NOSERVICE) { @@ -1715,14 +1715,27 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat // } // } - private boolean calculateSeverityForIssuesAndUpdateErrors(List errors, ValidationResult validationResult, Element element, String path, boolean ignoreCantInfer, String vsurl, BindingStrength bindingStrength) { + /** + * For each issue in the validationResult, determine first if it should be ignored, and if not, calculate its severity + * and add it to the errors list. + * + * @param errors a list of validation messages that are errors + * @param validationResult the validation result containing terminology issues to be evaluated + * @param element the element being validated + * @param path the path of the element being validated + * @param ignoreCantInfer if true, the element will be ignored + * @param vsurl the value set url + * @param bindingStrength the binding strength of the code/codeable concept + * @return true if no errors were added to the errors list, false otherwise + */ + private boolean calculateSeverityForTxIssuesAndUpdateErrors(List errors, ValidationResult validationResult, Element element, String path, boolean ignoreCantInfer, String vsurl, BindingStrength bindingStrength) { if (validationResult == null) { return true; } boolean noErrorsFound = true; for (OperationOutcomeIssueComponent issue : validationResult.getIssues()) { if (!isIgnoredTxIssueType(issue, ignoreCantInfer)) { - OperationOutcomeIssueComponent issueWithCalculatedSeverity = getTxIssueWithCalculatedSeverity(issue, ignoreCantInfer, bindingStrength); + OperationOutcomeIssueComponent issueWithCalculatedSeverity = getTxIssueWithCalculatedSeverity(issue, bindingStrength); var validationMessage = buildValidationMessage(validationResult.getTxLink(), element.line(), element.col(), path, issueWithCalculatedSeverity); if (!isSuppressedValidationMessage(path, validationMessage.getMessageId())) { errors.add(validationMessage); @@ -1735,6 +1748,21 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat return noErrorsFound; } + /** + * Check if the issueComponent should not be included when evaluating if terminology issues contain errors. + *

+ * The following tx-issue-types are ignored: + *

+ * Note that cannot-infer is only ignored if ignoreCantInfer is true. + * + * @param issueComponent the issue + * @param ignoreCantInfer if true, ignore + * @return true if the issue should be ignored when evaluating if terminology issues contain errors, false otherwise + */ private boolean isIgnoredTxIssueType(OperationOutcomeIssueComponent issueComponent, boolean ignoreCantInfer) { if (issueComponent.getDetails().hasCoding("http://hl7.org/fhir/tools/CodeSystem/tx-issue-type", "not-in-vs")) { return true; @@ -1742,13 +1770,28 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat if (issueComponent.getDetails().hasCoding("http://hl7.org/fhir/tools/CodeSystem/tx-issue-type", "this-code-not-in-vs")) { return true; } - if (ignoreCantInfer || issueComponent.getDetails().hasCoding("http://hl7.org/fhir/tools/CodeSystem/tx-issue-type", "cannot-infer")) { - return true; + if (issueComponent.getDetails().hasCoding("http://hl7.org/fhir/tools/CodeSystem/tx-issue-type", "cannot-infer") || ignoreCantInfer) { + return true; } return false; } - private OperationOutcomeIssueComponent getTxIssueWithCalculatedSeverity(OperationOutcomeIssueComponent issueComponent, boolean ignoreCantInfer, BindingStrength bindingStrength) { + /** + * Derive a new issue from the passed issueComponent with appropriate severity. + *

+ * If the issueComponent has a tx-issue-type of "not-found", the returned value will have an appropriate severity + * based on bindingStrength. The issueComponent text will also be updated to include the reason for error level + * severity. + *

+ * If the issueComponent has a tx-issue-type of "invalid-display" the returned value will have an appropriate severity + * based on displayWarningMode. + *

+ * All other issues will be returned unchanged. + * @param issueComponent the issue component + * @param bindingStrength the binding strength of the code/codeable concept + * @return the new issue component with appropriate severity + */ + private OperationOutcomeIssueComponent getTxIssueWithCalculatedSeverity(OperationOutcomeIssueComponent issueComponent, BindingStrength bindingStrength) { OperationOutcomeIssueComponent newIssueComponent = issueComponent.copy(); if (newIssueComponent.getDetails().hasCoding("http://hl7.org/fhir/tools/CodeSystem/tx-issue-type", "not-found")) { String text = issueComponent.getDetails().getText(); @@ -1791,7 +1834,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat boolean ok = true; if (isNotBlank(nextCoding.getCode()) && isNotBlank(nextCoding.getSystem()) && context.supportsSystem(nextCoding.getSystem(), baseOptions.getFhirVersion())) { ValidationResult vr = checkCodeOnServer(stack, valueset, nextCoding); - ok = calculateSeverityForIssuesAndUpdateErrors(errors, vr, element, path, false, null, null) && ok; + ok = calculateSeverityForTxIssuesAndUpdateErrors(errors, vr, element, path, false, null, null) && ok; if (vr.getSeverity() != null && !vr.messageIsInIssues()) { if (vr.getSeverity() == IssueSeverity.INFORMATION) { @@ -1922,7 +1965,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat if (strength == BindingStrength.REQUIRED) { removeTrackedMessagesForLocation(errors, element, path); } - ok = calculateSeverityForIssuesAndUpdateErrors(errors, vr, element, path, false, vsRef, strength) && ok; + ok = calculateSeverityForTxIssuesAndUpdateErrors(errors, vr, element, path, false, vsRef, strength) && ok; timeTracker.tx(t, "vc "+system+"#"+code+" '"+display+"'"); if (vr != null && !vr.isOk()) { if (vr.IsNoService()) @@ -2067,7 +2110,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat try { long t = System.nanoTime(); ValidationResult vr = checkCodeOnServer(stack, valueset, cc); - ok = calculateSeverityForIssuesAndUpdateErrors(errors, vr, element, path, false, maxVSUrl, null) && ok; + ok = calculateSeverityForTxIssuesAndUpdateErrors(errors, vr, element, path, false, maxVSUrl, null) && ok; timeTracker.tx(t, "vc "+cc.toString()); if (!vr.isOk()) { if (vr.getErrorClass() != null && vr.getErrorClass().isInfrastructure()) @@ -2106,7 +2149,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat try { long t = System.nanoTime(); ValidationResult vr = checkCodeOnServer(stack, valueset, c); - ok = calculateSeverityForIssuesAndUpdateErrors(errors, vr, element, path, false, maxVSUrl, null) && ok; + ok = calculateSeverityForTxIssuesAndUpdateErrors(errors, vr, element, path, false, maxVSUrl, null) && ok; timeTracker.tx(t, "vc "+c.getSystem()+"#"+c.getCode()+" '"+c.getDisplay()+"'"); if (!vr.isOk()) { @@ -2137,7 +2180,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat try { long t = System.nanoTime(); ValidationResult vr = checkCodeOnServer(stack, valueset, value, baseOptions); - ok = calculateSeverityForIssuesAndUpdateErrors(errors, vr, element, path, false, maxVSUrl, null) && ok; + ok = calculateSeverityForTxIssuesAndUpdateErrors(errors, vr, element, path, false, maxVSUrl, null) && ok; timeTracker.tx(t, "vc "+value); if (!vr.isOk()) { if (vr.getErrorClass() != null && vr.getErrorClass().isInfrastructure()) @@ -2272,7 +2315,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat checked.set(true); vr = checkCodeOnServer(stack, valueset, c); } - ok = calculateSeverityForIssuesAndUpdateErrors(errors, vr, element, path, strength == BindingStrength.EXTENSIBLE, vsRef, strength) && ok; + ok = calculateSeverityForTxIssuesAndUpdateErrors(errors, vr, element, path, strength == BindingStrength.EXTENSIBLE, vsRef, strength) && ok; timeTracker.tx(t, "vc "+c.getSystem()+"#"+c.getCode()+" '"+c.getDisplay()+"'"); if (strength == BindingStrength.REQUIRED) { @@ -3093,7 +3136,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat } if (type.equals("integer") || type.equals("unsignedInt") || type.equals("positiveInt")) { if (rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, Utilities.isInteger(e.primitiveValue()), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_INTEGER_VALID, e.primitiveValue())) { - Integer v = new Integer(e.getValue()).intValue(); + Integer v = Integer.valueOf(e.getValue()); ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, !context.hasMaxValueIntegerType() || !context.getMaxValueIntegerType().hasValue() || (context.getMaxValueIntegerType().getValue() >= v), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_INTEGER_GT, (context.hasMaxValueIntegerType() ? context.getMaxValueIntegerType() : "")) && ok; ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, !context.hasMinValueIntegerType() || !context.getMinValueIntegerType().hasValue() || (context.getMinValueIntegerType().getValue() <= v), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_INTEGER_LT, (context.hasMinValueIntegerType() ? context.getMinValueIntegerType() : "")) && ok; if (type.equals("unsignedInt")) @@ -3106,7 +3149,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat } if (type.equals("integer64")) { if (rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, Utilities.isLong(e.primitiveValue()), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_INTEGER64_VALID, e.primitiveValue())) { - Long v = new Long(e.getValue()).longValue(); + Long v = Long.valueOf(e.getValue()); ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, !context.hasMaxValueInteger64Type() || !context.getMaxValueInteger64Type().hasValue() || (context.getMaxValueInteger64Type().getValue() >= v), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_INTEGER_GT, (context.hasMaxValueInteger64Type() ? context.getMaxValueInteger64Type() : "")) && ok; ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, !context.hasMinValueInteger64Type() || !context.getMinValueInteger64Type().hasValue() || (context.getMinValueInteger64Type().getValue() <= v), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_INTEGER_LT, (context.hasMinValueInteger64Type() ? context.getMinValueInteger64Type() : "")) && ok; if (type.equals("unsignedInt")) @@ -3747,7 +3790,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat } vr = checkCodeOnServer(stack, vs, value, options); } - ok = calculateSeverityForIssuesAndUpdateErrors(errors, vr, element, path, binding.getStrength() != BindingStrength.REQUIRED, binding.getValueSet(), binding.getStrength()) && ok; + ok = calculateSeverityForTxIssuesAndUpdateErrors(errors, vr, element, path, binding.getStrength() != BindingStrength.REQUIRED, binding.getValueSet(), binding.getStrength()) && ok; timeTracker.tx(t, "vc "+value+""); if (binding.getStrength() == BindingStrength.REQUIRED) {