From 3ba81328cc53448d2d09e9f4d8e0cddb411edd88 Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Thu, 24 Dec 2020 13:21:30 +1100 Subject: [PATCH 1/2] * More rules around URL validation, instead of just marking them as errors * Don't report errors for extensible bindings when profiles apply required bindings * fix rendering issue with profile references * only use c:\temp if it's writeable --- RELEASE_NOTES.md | 7 ++ .../fhir/r5/conformance/ProfileUtilities.java | 2 +- .../org/hl7/fhir/utilities/Utilities.java | 2 +- .../fhir/utilities/i18n/I18nConstants.java | 2 + .../src/main/resources/Messages.properties | 4 +- .../hl7/fhir/validation/BaseValidator.java | 55 ++++++++- .../hl7/fhir/validation/ValidationEngine.java | 10 +- .../instance/InstanceValidator.java | 111 ++++++++++++++++-- 8 files changed, 177 insertions(+), 16 deletions(-) diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index e69de29bb..fc435e94d 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -0,0 +1,7 @@ +Validator: +* More rules around URL validation, instead of just marking them as errors +* Don't report errors for extensible bindings when profiles apply required bindings + +Other code changes: +* fix rendering issue with profile references +* only use c:\temp for logs if it's writeable \ No newline at end of file diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/ProfileUtilities.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/ProfileUtilities.java index 7999bf032..70610135f 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/ProfileUtilities.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/ProfileUtilities.java @@ -3313,7 +3313,7 @@ public class ProfileUtilities extends TranslatingUtilities { c.getPieces().add(gen.new Piece("#"+ed.getElement().getPath(), tail(ed.getElement().getPath()), ed.getElement().getPath())); } else { c.getPieces().add(gen.new Piece(null, translate("sd.table", "See ", ed.getElement().getPath()), null)); - c.getPieces().add(gen.new Piece(ed.getSource().getUserString("path")+"#"+ed.getElement().getPath(), tail(ed.getElement().getPath())+" ("+ed.getSource().getType()+")", ed.getElement().getPath())); + c.getPieces().add(gen.new Piece(corePath+ed.getSource().getUserString("path")+"#"+ed.getElement().getPath(), tail(ed.getElement().getPath())+" ("+ed.getSource().getType()+")", ed.getElement().getPath())); } } return c; diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/Utilities.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/Utilities.java index ce5e66516..ebe1dfdaa 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/Utilities.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/Utilities.java @@ -639,7 +639,7 @@ public class Utilities { return false; } File tmp = new File("c:\\temp"); - return tmp.exists() && tmp.isDirectory(); + return tmp.exists() && tmp.isDirectory() && tmp.canWrite(); } public static String pathURL(String... args) { diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/i18n/I18nConstants.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/i18n/I18nConstants.java index df6d04c43..e8f2fdd1a 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/i18n/I18nConstants.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/i18n/I18nConstants.java @@ -493,6 +493,8 @@ public class I18nConstants { public static final String TYPE_SPECIFIC_CHECKS_DT_URI_UUID = "Type_Specific_Checks_DT_URI_UUID"; public static final String TYPE_SPECIFIC_CHECKS_DT_URI_WS = "Type_Specific_Checks_DT_URI_WS"; public static final String TYPE_SPECIFIC_CHECKS_DT_URL_RESOLVE = "Type_Specific_Checks_DT_URL_Resolve"; + public static final String TYPE_SPECIFIC_CHECKS_DT_CANONICAL_TYPE = "TYPE_SPECIFIC_CHECKS_DT_CANONICAL_TYPE"; + public static final String TYPE_SPECIFIC_CHECKS_DT_CANONICAL_RESOLVE = "TYPE_SPECIFIC_CHECKS_DT_CANONICAL_RESOLVE"; public static final String TYPE_SPECIFIC_CHECKS_DT_UUID_STRAT = "Type_Specific_Checks_DT_UUID_Strat"; public static final String TYPE_SPECIFIC_CHECKS_DT_UUID_VAID = "Type_Specific_Checks_DT_UUID_Vaid"; public static final String UNABLE_TO_CONNECT_TO_TERMINOLOGY_SERVER = "Unable_to_connect_to_terminology_server"; diff --git a/org.hl7.fhir.utilities/src/main/resources/Messages.properties b/org.hl7.fhir.utilities/src/main/resources/Messages.properties index b4759aa2e..e36bdac34 100644 --- a/org.hl7.fhir.utilities/src/main/resources/Messages.properties +++ b/org.hl7.fhir.utilities/src/main/resources/Messages.properties @@ -153,7 +153,7 @@ Terminology_TX_NoValid_13 = The Coding provided ({2}) is not in the value set {0 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 and the validator cannot judge what is suitable){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 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}) @@ -634,3 +634,5 @@ SD_ED_BIND_NOT_VS = The valueSet reference {1} on element {0} points to somethin SD_ED_BIND_NO_BINDABLE = The element {0} has a binding, but no bindable types are present {1} DISCRIMINATOR_BAD_PATH = Error processing path expression for disciminator: {0} (src = ''{1}'') SLICING_CANNOT_BE_EVALUATED = Slicing cannot be evaluated: {0} +TYPE_SPECIFIC_CHECKS_DT_CANONICAL_RESOLVE = Canonical URL ''{0}'' does not resolve +TYPE_SPECIFIC_CHECKS_DT_CANONICAL_TYPE = Canonical URL ''{0}'' refers to a resource that has the wrong type. Found {1} expecting one of {2} diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/BaseValidator.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/BaseValidator.java index 2c4391d0a..0b0ac7f16 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/BaseValidator.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/BaseValidator.java @@ -84,10 +84,28 @@ import org.hl7.fhir.utilities.validation.ValidationMessage; import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity; import org.hl7.fhir.utilities.validation.ValidationMessage.IssueType; import org.hl7.fhir.utilities.validation.ValidationMessage.Source; +import org.hl7.fhir.validation.BaseValidator.TrackedLocationRelatedMessage; import org.hl7.fhir.validation.instance.utils.IndexedElement; public class BaseValidator { + public class TrackedLocationRelatedMessage { + private Object location; + private ValidationMessage vmsg; + public TrackedLocationRelatedMessage(Object location, ValidationMessage vmsg) { + super(); + this.location = location; + this.vmsg = vmsg; + } + public Object getLocation() { + return location; + } + public ValidationMessage getVmsg() { + return vmsg; + } + + } + public class ValidationControl { private boolean allowed; private IssueSeverity level; @@ -122,8 +140,10 @@ public class BaseValidator { protected IWorkerContext context; protected TimeTracker timeTracker = new TimeTracker(); protected XVerExtensionManager xverManager; - - public BaseValidator(IWorkerContext context, XVerExtensionManager xverManager) { + protected List trackedMessages = new ArrayList<>(); + protected List messagesToRemove = new ArrayList<>(); + + public BaseValidator(IWorkerContext context, XVerExtensionManager xverManager) { super(); this.context = context; this.xverManager = xverManager; @@ -493,7 +513,38 @@ public class BaseValidator { return thePass; } + + /** + * Test a rule and add a {@link IssueSeverity#WARNING} validation message if the validation fails. Also, keep track of it later in case we want to remove it if we find a required binding for this element later + * + * @param thePass + * Set this parameter to false if the validation does not pass + * @return Returns thePass (in other words, returns true if the rule did not fail validation) + */ + protected boolean txWarningForLaterRemoval(Object location, List errors, String txLink, IssueType type, int line, int col, String path, boolean thePass, String msg, Object... theMessageArguments) { + if (!thePass) { + String nmsg = context.formatMessage(msg, theMessageArguments); + ValidationMessage vmsg = new ValidationMessage(Source.TerminologyEngine, type, line, col, path, nmsg, IssueSeverity.WARNING).setTxLink(txLink).setMessageId(msg); + if (checkMsgId(msg, vmsg)) { + errors.add(vmsg); + } + trackedMessages.add(new TrackedLocationRelatedMessage(location, vmsg)); + } + return thePass; + } + + protected void removeTrackedMessagesForLocation(List errors, Object location, String path) { + List messages = new ArrayList<>(); + for (TrackedLocationRelatedMessage m : trackedMessages) { + if (m.getLocation() == location) { + messages.add(m); + messagesToRemove.add(m.getVmsg()); + } + } + trackedMessages.removeAll(messages); + } + protected boolean warningOrError(boolean isError, List errors, IssueType type, int line, int col, String path, boolean thePass, String msg, Object... theMessageArguments) { if (!thePass) { String nmsg = context.formatMessage(msg, theMessageArguments); diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/ValidationEngine.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/ValidationEngine.java index eb6b833a1..122404cc4 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/ValidationEngine.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/ValidationEngine.java @@ -1710,7 +1710,7 @@ public class ValidationEngine implements IValidatorResourceFetcher, IPackageInst if (resource != null) { return ReferenceValidationPolicy.CHECK_VALID; } - if (!url.startsWith("http://hl7.org/fhir")) { + if (!(url.contains("hl7.org") || url.contains("fhir.org"))) { return ReferenceValidationPolicy.IGNORE; } else if (fetcher != null) { return fetcher.validationPolicy(appContext, path, url); @@ -1748,6 +1748,14 @@ public class ValidationEngine implements IValidatorResourceFetcher, IPackageInst @Override public CanonicalResource fetchCanonicalResource(String url) throws URISyntaxException { + Resource res = context.fetchResource(Resource.class, url); + if (res != null) { + if (res instanceof CanonicalResource) { + return (CanonicalResource) res; + } else { + return null; + } + } return fetcher != null ? fetcher.fetchCanonicalResource(url) : null; } 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 1327345f5..2ebae0d89 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 @@ -691,6 +691,8 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat fetchCache.clear(); fetchCache.put(element.fhirType() + "/" + element.getIdBase(), element); resourceTracker.clear(); + trackedMessages.clear(); + messagesToRemove.clear(); executionId = UUID.randomUUID().toString(); baseOnly = profiles.isEmpty(); setParents(element); @@ -706,6 +708,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat if (hintAboutNonMustSupport) { checkElementUsage(errors, element, new NodeStack(context, element, validationLanguage)); } + errors.removeAll(messagesToRemove); timeTracker.overall(t); } @@ -990,6 +993,9 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat // Check whether the codes are appropriate for the type of binding we have boolean bindingsOk = true; if (binding.getStrength() != BindingStrength.EXAMPLE) { + if (binding.getStrength() == BindingStrength.REQUIRED) { + removeTrackedMessagesForLocation(errors, element, path); + } boolean atLeastOneSystemIsSupported = false; for (Coding nextCoding : cc.getCoding()) { String nextSystem = nextCoding.getSystem(); @@ -1018,7 +1024,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat if (binding.hasExtension("http://hl7.org/fhir/StructureDefinition/elementdefinition-maxValueSet")) checkMaxValueSet(errors, path, element, profile, ToolingExtensions.readStringExtension(binding, "http://hl7.org/fhir/StructureDefinition/elementdefinition-maxValueSet"), cc, stack); else if (!noExtensibleWarnings) - txWarning(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_CONFIRM_2, describeReference(binding.getValueSet()), vr.getErrorClass().toString()); + txWarningForLaterRemoval(element, errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_CONFIRM_2, describeReference(binding.getValueSet()), vr.getErrorClass().toString()); } else if (binding.getStrength() == BindingStrength.PREFERRED) { if (baseOnly) { txHint(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_CONFIRM_3, describeReference(binding.getValueSet()), vr.getErrorClass().toString()); @@ -1031,7 +1037,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat if (binding.hasExtension("http://hl7.org/fhir/StructureDefinition/elementdefinition-maxValueSet")) checkMaxValueSet(errors, path, element, profile, ToolingExtensions.readStringExtension(binding, "http://hl7.org/fhir/StructureDefinition/elementdefinition-maxValueSet"), cc, stack); if (!noExtensibleWarnings) - txWarning(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_2, describeReference(binding.getValueSet()), valueset.getUrl(), ccSummary(cc)); + txWarningForLaterRemoval(element, errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_2, describeReference(binding.getValueSet()), valueset.getUrl(), ccSummary(cc)); } else if (binding.getStrength() == BindingStrength.PREFERRED) { if (baseOnly) { txHint(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_3, describeReference(binding.getValueSet()), valueset.getUrl(), ccSummary(cc)); @@ -1080,6 +1086,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat return res; } + private boolean checkTerminologyCodeableConcept(List errors, String path, Element element, StructureDefinition profile, ElementDefinition theElementCntext, NodeStack stack, StructureDefinition logical) { boolean res = true; if (!noTerminologyChecks && theElementCntext != null && theElementCntext.hasBinding()) { @@ -1105,6 +1112,10 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat // Check whether the codes are appropriate for the type of binding we have boolean bindingsOk = true; if (binding.getStrength() != BindingStrength.EXAMPLE) { + if (binding.getStrength() == BindingStrength.REQUIRED) { + removeTrackedMessagesForLocation(errors, element, path); + } + boolean atLeastOneSystemIsSupported = false; for (Coding nextCoding : cc.getCoding()) { String nextSystem = nextCoding.getSystem(); @@ -1127,7 +1138,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat if (binding.hasExtension("http://hl7.org/fhir/StructureDefinition/elementdefinition-maxValueSet")) checkMaxValueSet(errors, path, element, profile, ToolingExtensions.readStringExtension(binding, "http://hl7.org/fhir/StructureDefinition/elementdefinition-maxValueSet"), cc, stack); else if (!noExtensibleWarnings) - txWarning(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_CONFIRM_2, describeReference(binding.getValueSet()), vr.getErrorClass().toString()); + txWarningForLaterRemoval(element, errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_CONFIRM_2, describeReference(binding.getValueSet()), vr.getErrorClass().toString()); } else if (binding.getStrength() == BindingStrength.PREFERRED) { if (baseOnly) { txHint(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_CONFIRM_3, describeReference(binding.getValueSet()), vr.getErrorClass().toString()); @@ -1140,7 +1151,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat if (binding.hasExtension("http://hl7.org/fhir/StructureDefinition/elementdefinition-maxValueSet")) checkMaxValueSet(errors, path, element, profile, ToolingExtensions.readStringExtension(binding, "http://hl7.org/fhir/StructureDefinition/elementdefinition-maxValueSet"), cc, stack); if (!noExtensibleWarnings) - txWarning(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_2, describeReference(binding.getValueSet()), valueset.getUrl(), ccSummary(cc)); + txWarningForLaterRemoval(element, errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_2, describeReference(binding.getValueSet()), valueset.getUrl(), ccSummary(cc)); } else if (binding.getStrength() == BindingStrength.PREFERRED) { if (baseOnly) { txHint(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_3, describeReference(binding.getValueSet()), valueset.getUrl(), ccSummary(cc)); @@ -1212,6 +1223,10 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat if (binding.getStrength() != BindingStrength.EXAMPLE) { vr = checkCodeOnServer(stack, valueset, c, true); } + if (binding.getStrength() == BindingStrength.REQUIRED) { + removeTrackedMessagesForLocation(errors, element, path); + } + timeTracker.tx(t); if (vr != null && !vr.isOk()) { if (vr.IsNoService()) @@ -1223,7 +1238,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat if (binding.hasExtension("http://hl7.org/fhir/StructureDefinition/elementdefinition-maxValueSet")) checkMaxValueSet(errors, path, element, profile, ToolingExtensions.readStringExtension(binding, "http://hl7.org/fhir/StructureDefinition/elementdefinition-maxValueSet"), c, stack); else if (!noExtensibleWarnings) - txWarning(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_CONFIRM_5, describeReference(binding.getValueSet(), valueset)); + txWarningForLaterRemoval(element, errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_CONFIRM_5, describeReference(binding.getValueSet(), valueset)); } else if (binding.getStrength() == BindingStrength.PREFERRED) { if (baseOnly) { txHint(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_CONFIRM_6, describeReference(binding.getValueSet(), valueset)); @@ -1432,6 +1447,10 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat vr = checkCodeOnServer(stack, valueset, c, true); } timeTracker.tx(t); + if (binding.getStrength() == BindingStrength.REQUIRED) { + removeTrackedMessagesForLocation(errors, element, path); + } + if (vr != null && !vr.isOk()) { if (vr.IsNoService()) txHint(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_BINDING_NOSERVER); @@ -1442,7 +1461,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat if (binding.hasExtension("http://hl7.org/fhir/StructureDefinition/elementdefinition-maxValueSet")) checkMaxValueSet(errors, path, element, profile, ToolingExtensions.readStringExtension(binding, "http://hl7.org/fhir/StructureDefinition/elementdefinition-maxValueSet"), c, stack); else if (!noExtensibleWarnings) - txWarning(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_CONFIRM_5, describeReference(binding.getValueSet(), valueset)); + txWarningForLaterRemoval(element, errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_CONFIRM_5, describeReference(binding.getValueSet(), valueset)); } else if (binding.getStrength() == BindingStrength.PREFERRED) { if (baseOnly) { txHint(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_CONFIRM_6, describeReference(binding.getValueSet(), valueset)); @@ -1453,8 +1472,9 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat else if (binding.getStrength() == BindingStrength.EXTENSIBLE) { if (binding.hasExtension("http://hl7.org/fhir/StructureDefinition/elementdefinition-maxValueSet")) checkMaxValueSet(errors, path, element, profile, ToolingExtensions.readStringExtension(binding, "http://hl7.org/fhir/StructureDefinition/elementdefinition-maxValueSet"), c, stack); - else - txWarning(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_13, describeReference(binding.getValueSet(), valueset), getErrorMessage(vr.getMessage()), c.getSystem()+"#"+c.getCode()); + else if (!noExtensibleWarnings) { + txWarningForLaterRemoval(element, errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_13, describeReference(binding.getValueSet(), valueset), getErrorMessage(vr.getMessage()), c.getSystem()+"#"+c.getCode()); + } } else if (binding.getStrength() == BindingStrength.PREFERRED) { if (baseOnly) { txHint(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_14, describeReference(binding.getValueSet(), valueset), getErrorMessage(vr.getMessage()), theSystem+"#"+theCode); @@ -1935,7 +1955,40 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat } catch (IOException e1) { found = false; } - rule(errors, IssueType.INVALID, e.line(), e.col(), path, found, I18nConstants.TYPE_SPECIFIC_CHECKS_DT_URL_RESOLVE, url); + if (!found) { + if (type.equals("canonical")) { + ReferenceValidationPolicy rp = fetcher.validationPolicy(appContext, path, url); + if (rp == ReferenceValidationPolicy.CHECK_EXISTS || rp == ReferenceValidationPolicy.CHECK_EXISTS_AND_TYPE) { + rule(errors, IssueType.INVALID, e.line(), e.col(), path, found, I18nConstants.TYPE_SPECIFIC_CHECKS_DT_CANONICAL_RESOLVE, url); + } else { + hint(errors, IssueType.INVALID, e.line(), e.col(), path, found, I18nConstants.TYPE_SPECIFIC_CHECKS_DT_CANONICAL_RESOLVE, url); + } + } else { + if (url.contains("hl7.org") || url.contains("fhir.org")) { + rule(errors, IssueType.INVALID, e.line(), e.col(), path, found, I18nConstants.TYPE_SPECIFIC_CHECKS_DT_URL_RESOLVE, url); + } else { + warning(errors, IssueType.INVALID, e.line(), e.col(), path, found, I18nConstants.TYPE_SPECIFIC_CHECKS_DT_URL_RESOLVE, url); + } + } + } else { + if (type.equals("canonical")) { + ReferenceValidationPolicy rp = fetcher.validationPolicy(appContext, path, url); + if (rp == ReferenceValidationPolicy.CHECK_EXISTS_AND_TYPE || rp == ReferenceValidationPolicy.CHECK_TYPE_IF_EXISTS || rp == ReferenceValidationPolicy.CHECK_VALID) { + try { + Resource r = fetcher.fetchCanonicalResource(url); + if (r == null) { + rule(errors, IssueType.INVALID, e.line(), e.col(), path, found, I18nConstants.TYPE_SPECIFIC_CHECKS_DT_CANONICAL_RESOLVE, url); + } else if (rule(errors, IssueType.INVALID, e.line(), e.col(), path, isCorrectCanonicalType(r, context), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_CANONICAL_TYPE, url, r.fhirType(), listExpectedCanonicalTypes(context))) { + if (rp == ReferenceValidationPolicy.CHECK_VALID) { + // todo.... + } + } + } catch (Exception ex) { + // won't happen + } + } + } + } } } } @@ -2083,6 +2136,41 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat // for nothing to check } + private List listExpectedCanonicalTypes(ElementDefinition context) { + List res = new ArrayList<>(); + TypeRefComponent tr = context.getType("canonical"); + if (tr != null) { + for (CanonicalType p : tr.getTargetProfile()) { + String url = p.getValue(); + if (url != null && url.startsWith("http://hl7.org/fhir/StructureDefinition/")) { + res.add(url.substring("http://hl7.org/fhir/StructureDefinition/".length())); + } + } + } + return res; + } + + private boolean isCorrectCanonicalType(Resource r, ElementDefinition context) { + TypeRefComponent tr = context.getType("canonical"); + if (tr != null) { + for (CanonicalType p : tr.getTargetProfile()) { + if (isCorrectCanonicalType(r, p)) { + return true; + } + } + } + return false; + } + + private boolean isCorrectCanonicalType(Resource r, CanonicalType p) { + String url = p.getValue(); + if (url != null && url.startsWith("http://hl7.org/fhir/StructureDefinition/")) { + url = url.substring("http://hl7.org/fhir/StructureDefinition/".length()); + return Utilities.existsInList(url, "Resource", "CanonicalResource") || url.equals(r.fhirType()); + } + return false; + } + private boolean isCanonicalURLElement(Element e) { if (e.getProperty() == null || e.getProperty().getDefinition() == null) { return false; @@ -2301,6 +2389,9 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat vr = checkCodeOnServer(stack, vs, value, options); } timeTracker.tx(t); + if (binding.getStrength() == BindingStrength.REQUIRED) { + removeTrackedMessagesForLocation(errors, element, path); + } if (vr != null && !vr.isOk()) { if (vr.IsNoService()) txHint(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_15, value); @@ -2310,7 +2401,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat if (binding.hasExtension("http://hl7.org/fhir/StructureDefinition/elementdefinition-maxValueSet")) checkMaxValueSet(errors, path, element, profile, ToolingExtensions.readStringExtension(binding, "http://hl7.org/fhir/StructureDefinition/elementdefinition-maxValueSet"), value, stack); else if (!noExtensibleWarnings) - txWarning(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_17, value, describeReference(binding.getValueSet()), vs.getUrl(), getErrorMessage(vr.getMessage())); + txWarningForLaterRemoval(element, errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_17, value, describeReference(binding.getValueSet()), vs.getUrl(), getErrorMessage(vr.getMessage())); } else if (binding.getStrength() == BindingStrength.PREFERRED) { if (baseOnly) { txHint(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_18, value, describeReference(binding.getValueSet()), vs.getUrl(), getErrorMessage(vr.getMessage())); From 8e62a16eb6b71d123ba801afca1279e2981aa249 Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Thu, 24 Dec 2020 14:29:17 +1100 Subject: [PATCH 2/2] update test case version --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index aa00d94d9..42fcff4ae 100644 --- a/pom.xml +++ b/pom.xml @@ -19,7 +19,7 @@ 5.1.0 - 1.1.56-SNAPSHOT + 1.1.56 5.6.2 3.0.0-M4 0.8.5