From 2c47234f27581d0caa46e3f6eb5f33778e2dce05 Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Mon, 18 Nov 2024 17:36:59 +1100 Subject: [PATCH 1/7] Auto stash before merge of "master" and "origin/master" --- .../resources40_50/ConceptMap40_50.java | 3 + .../validation/ValueSetValidator.java | 39 +++++- .../validation/IValidationPolicyAdvisor.java | 4 + .../fhir/utilities/i18n/I18nConstants.java | 2 + .../src/main/resources/Messages.properties | 2 + .../DisabledValidationPolicyAdvisor.java | 86 +++++++++++++ .../services/StandAloneValidatorFetcher.java | 3 +- .../cli/services/ValidationService.java | 19 ++- .../validation/codesystem/LoincChecker.java | 6 +- .../BasePolicyAdvisorForFullValidation.java | 8 ++ .../instance/type/CodeSystemValidator.java | 120 ++++++++++-------- .../type/StructureDefinitionValidator.java | 2 +- .../validation/tests/ValidationTests.java | 9 ++ .../4.0.1/cs-externals.json | 1 + 14 files changed, 244 insertions(+), 60 deletions(-) create mode 100644 org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/services/DisabledValidationPolicyAdvisor.java diff --git a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/conv40_50/resources40_50/ConceptMap40_50.java b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/conv40_50/resources40_50/ConceptMap40_50.java index d413d746b9..17fcbd651d 100644 --- a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/conv40_50/resources40_50/ConceptMap40_50.java +++ b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/conv40_50/resources40_50/ConceptMap40_50.java @@ -208,6 +208,9 @@ public static org.hl7.fhir.r5.model.ConceptMap.SourceElementComponent convertSou if (t.getEquivalence() == org.hl7.fhir.r4.model.Enumerations.ConceptMapEquivalence.UNMATCHED) { tgt.setNoMap(true); if (t.hasComment()) { + if (tgt.hasExtension("http://hl7.org/fhir/4.0/StructureDefinition/extension-ConceptMap.group.element.target.comment")) { + throw new FHIRException("A source can only have one 'unmatched' relationship. Consider using 'disjoint' "); + } tgt.addExtension("http://hl7.org/fhir/4.0/StructureDefinition/extension-ConceptMap.group.element.target.comment", ConversionContext40_50.INSTANCE.getVersionConvertor_40_50().convertType(t.getCommentElement())); } } else { diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/validation/ValueSetValidator.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/validation/ValueSetValidator.java index b306e7ee0d..5b6d0c8211 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/validation/ValueSetValidator.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/validation/ValueSetValidator.java @@ -96,6 +96,7 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWIS import org.hl7.fhir.r5.utils.validation.ValidationContextCarrier; import org.hl7.fhir.r5.utils.validation.ValidationContextCarrier.ValidationContextResourceProxy; import org.hl7.fhir.utilities.CommaSeparatedStringBuilder; +import org.hl7.fhir.utilities.DebugUtilities; import org.hl7.fhir.utilities.FhirPublication; import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.VersionUtilities; @@ -183,6 +184,22 @@ private void analyseValueSet() { for (Extension s : valueset.getExtensionsByUrl(ExtensionConstants.EXT_VSSUPPLEMENT)) { requiredSupplements.add(s.getValue().primitiveValue()); } + + if (!requiredSupplements.isEmpty()) { + for (ConceptSetComponent inc : valueset.getCompose().getInclude()) { + if (inc.hasSystem()) { + checkCodeSystemResolves(inc); + } + } + for (ConceptSetComponent inc : valueset.getCompose().getExclude()) { + if (inc.hasSystem()) { + checkCodeSystemResolves(inc); + } + } + if (!requiredSupplements.isEmpty()) { + DebugUtilities.breakpoint(); + } + } } else { opContext.note("vs = null"); } @@ -202,6 +219,15 @@ private void analyseValueSet() { opContext.note("analysed"); } + private void checkCodeSystemResolves(ConceptSetComponent c) { + VersionInfo vi = new VersionInfo(this); + CodeSystem cs = resolveCodeSystem(c.getSystem(), vi.getVersion(c.getSystem(), c.getVersion())); + if (cs == null) { + // well, it doesn't really matter at this point. Mainly we're triggering the supplement analysis to happen + opContext.note("Unable to resolve "+c.getSystem()+"#"+vi.getVersion(c.getSystem(), c.getVersion())); + } + } + private void analyseComponent(ConceptSetComponent i, String name) { opContext.deadCheck("analyse Component "+name); if (i.getSystemElement().hasExtension(ToolingExtensions.EXT_VALUESET_SYSTEM)) { @@ -446,7 +472,7 @@ private int checkValueSetLoad(ConceptSetComponent inc, ValidationProcessInfo inf private boolean checkRequiredSupplements(ValidationProcessInfo info) { if (!requiredSupplements.isEmpty()) { - String msg= context.formatMessagePlural(requiredSupplements.size(), I18nConstants.VALUESET_SUPPLEMENT_MISSING, CommaSeparatedStringBuilder.build(requiredSupplements)); + String msg = context.formatMessagePlural(requiredSupplements.size(), I18nConstants.VALUESET_SUPPLEMENT_MISSING, CommaSeparatedStringBuilder.build(requiredSupplements)); throw new TerminologyServiceProtectionException(msg, TerminologyServiceErrorClass.BUSINESS_RULE, IssueType.NOTFOUND); } return requiredSupplements.isEmpty(); @@ -492,6 +518,17 @@ public CodeSystem resolveCodeSystem(String system, String version) { if (cs == null) { cs = findSpecialCodeSystem(system, version); } + if (cs != null) { + if (cs.hasUserData("supplements.installed")) { + for (String s : cs.getUserString("supplements.installed").split("\\,")) { + requiredSupplements.remove(s); + if (s.contains("|")) { + s = s.substring(0, s.indexOf("|")); + requiredSupplements.remove(s); + } + } + } + } return cs; } diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/validation/IValidationPolicyAdvisor.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/validation/IValidationPolicyAdvisor.java index c55a533bde..6cc79b18fc 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/validation/IValidationPolicyAdvisor.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/validation/IValidationPolicyAdvisor.java @@ -16,6 +16,10 @@ public interface IValidationPolicyAdvisor { + + public IValidationPolicyAdvisor getPolicyAdvisor(); + public IValidationPolicyAdvisor setPolicyAdvisor(IValidationPolicyAdvisor policyAdvisor); + /** * Internal use, for chaining advisors * 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 728dfc86c7..8151d2c104 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 @@ -1142,4 +1142,6 @@ public class I18nConstants { public static final String VIEWDEFINITION_TYPE_MISMATCH = "VIEWDEFINITION_TYPE_MISMATCH"; public static final String VIEWDEFINITION_UNABLE_TO_TYPE = "VIEWDEFINITION_UNABLE_TO_TYPE"; public static final String VIEWDEFINITION_COMPLEX_TYPE = "VIEWDEFINITION_COMPLEX_TYPE"; + public static final String CODESYSTEM_PROPERTY_ABSOLUTE_URI = "CODESYSTEM_PROPERTY_ABSOLUTE_URI"; + public static final String CODESYSTEM_CS_SUPP_HIERARCHY_MEANING = "CODESYSTEM_CS_SUPP_HIERARCHY_MEANING"; } diff --git a/org.hl7.fhir.utilities/src/main/resources/Messages.properties b/org.hl7.fhir.utilities/src/main/resources/Messages.properties index e0cd333259..04dcd11283 100644 --- a/org.hl7.fhir.utilities/src/main/resources/Messages.properties +++ b/org.hl7.fhir.utilities/src/main/resources/Messages.properties @@ -1172,3 +1172,5 @@ VIEWDEFINITION_COLLECTION_NEEDED2 = This column is defined to be not a collectio VIEWDEFINITION_TYPE_MISMATCH = The path expression ''{0}'' does not return a value of the type ''{1}'' - found ''{2}''{3} VIEWDEFINITION_UNABLE_TO_TYPE = Unable to determine a type (found ''{0}''){1} VIEWDEFINITION_COMPLEX_TYPE = Column from path ''{0}'' is a complex type (''{1}''){2}. This is not supported in some Runners +CODESYSTEM_PROPERTY_ABSOLUTE_URI = A property URI must be an absolute URI, but ''{0}'' is not +CODESYSTEM_CS_SUPP_HIERARCHY_MEANING = The supplement declares a heirarchyMeaning of ''{0}'' that doesn''t match that in the base code system ''{1}'' diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/services/DisabledValidationPolicyAdvisor.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/services/DisabledValidationPolicyAdvisor.java new file mode 100644 index 0000000000..30cfa34462 --- /dev/null +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/services/DisabledValidationPolicyAdvisor.java @@ -0,0 +1,86 @@ +package org.hl7.fhir.validation.cli.services; + +import java.util.EnumSet; +import java.util.List; + +import org.hl7.fhir.r5.elementmodel.Element; +import org.hl7.fhir.r5.elementmodel.Element.SpecialElement; +import org.hl7.fhir.r5.model.ElementDefinition; +import org.hl7.fhir.r5.model.StructureDefinition; +import org.hl7.fhir.r5.model.ValueSet; +import org.hl7.fhir.r5.utils.validation.IMessagingServices; +import org.hl7.fhir.r5.utils.validation.IResourceValidator; +import org.hl7.fhir.r5.utils.validation.IValidationPolicyAdvisor; +import org.hl7.fhir.r5.utils.validation.IValidationPolicyAdvisor.AdditionalBindingPurpose; +import org.hl7.fhir.r5.utils.validation.IValidationPolicyAdvisor.CodedContentValidationAction; +import org.hl7.fhir.r5.utils.validation.IValidationPolicyAdvisor.ElementValidationAction; +import org.hl7.fhir.r5.utils.validation.IValidationPolicyAdvisor.ResourceValidationAction; +import org.hl7.fhir.r5.utils.validation.constants.BindingKind; +import org.hl7.fhir.r5.utils.validation.constants.ContainedReferenceValidationPolicy; +import org.hl7.fhir.r5.utils.validation.constants.ReferenceValidationPolicy; +import org.hl7.fhir.utilities.validation.ValidationMessage; + +public class DisabledValidationPolicyAdvisor implements IValidationPolicyAdvisor { + + private IValidationPolicyAdvisor policyAdvisor; + + @Override + public ReferenceValidationPolicy getReferencePolicy() { + return ReferenceValidationPolicy.CHECK_TYPE_IF_EXISTS; + } + + @Override + public boolean isSuppressMessageId(String path, String messageId) { + return policyAdvisor.isSuppressMessageId(path, messageId); + } + + @Override + public ContainedReferenceValidationPolicy policyForContained(IResourceValidator validator, Object appContext, + StructureDefinition structure, ElementDefinition element, String containerType, String containerId, + SpecialElement containingResourceType, String path, String url) { + return policyAdvisor.policyForContained(validator, appContext, structure, element, containerType, containerId, containingResourceType, path, url); + } + + @Override + public EnumSet policyForResource(IResourceValidator validator, Object appContext, + StructureDefinition type, String path) { + return policyAdvisor.policyForResource(validator, appContext, type, path); + } + + @Override + public EnumSet policyForElement(IResourceValidator validator, Object appContext, + StructureDefinition structure, ElementDefinition element, String path) { + return policyAdvisor.policyForElement(validator, appContext, structure, element, path); + } + + @Override + public EnumSet policyForCodedContent(IResourceValidator validator, Object appContext, + String stackPath, ElementDefinition definition, StructureDefinition structure, BindingKind kind, + AdditionalBindingPurpose purpose, ValueSet valueSet, List systems) { + return policyAdvisor.policyForCodedContent(validator, appContext, stackPath, definition, structure, kind, purpose, valueSet, systems); + } + + @Override + public List getImpliedProfilesForResource(IResourceValidator validator, Object appContext, + String stackPath, ElementDefinition definition, StructureDefinition structure, Element resource, boolean valid, + IMessagingServices msgServices, List messages) { + return policyAdvisor.getImpliedProfilesForResource(validator, appContext, stackPath, definition, structure, resource, valid, msgServices, messages); + } + + public IValidationPolicyAdvisor getPolicyAdvisor() { + return policyAdvisor; + } + + public IValidationPolicyAdvisor setPolicyAdvisor(IValidationPolicyAdvisor policyAdvisor) { + this.policyAdvisor = policyAdvisor; + return this; + } + + @Override + public ReferenceValidationPolicy policyForReference(IResourceValidator validator, + Object appContext, + String path, + String url) { + return ReferenceValidationPolicy.IGNORE; + } +} diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/services/StandAloneValidatorFetcher.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/services/StandAloneValidatorFetcher.java index cdf7b13816..8fb1972efe 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/services/StandAloneValidatorFetcher.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/services/StandAloneValidatorFetcher.java @@ -348,8 +348,9 @@ public IValidationPolicyAdvisor getPolicyAdvisor() { return policyAdvisor; } - public void setPolicyAdvisor(IValidationPolicyAdvisor policyAdvisor) { + public IValidationPolicyAdvisor setPolicyAdvisor(IValidationPolicyAdvisor policyAdvisor) { this.policyAdvisor = policyAdvisor; + return this; } } diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/services/ValidationService.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/services/ValidationService.java index 21ffc344a0..98f3d0ac98 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/services/ValidationService.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/services/ValidationService.java @@ -44,6 +44,7 @@ import org.hl7.fhir.r5.terminologies.CodeSystemUtilities; import org.hl7.fhir.r5.terminologies.client.TerminologyClientManager.InternalLogEvent; import org.hl7.fhir.r5.terminologies.utilities.TerminologyCache; +import org.hl7.fhir.utilities.DebugUtilities; import org.hl7.fhir.utilities.FhirPublication; import org.hl7.fhir.utilities.SystemExitManager; import org.hl7.fhir.utilities.TextFile; @@ -72,6 +73,7 @@ import org.hl7.fhir.validation.cli.utils.Common; import org.hl7.fhir.validation.cli.utils.EngineMode; import org.hl7.fhir.validation.cli.utils.VersionSourceInformation; +import org.hl7.fhir.validation.instance.advisor.BasePolicyAdvisorForFullValidation; import org.hl7.fhir.validation.instance.advisor.JsonDrivenPolicyAdvisor; import org.hl7.fhir.validation.instance.advisor.TextDrivenPolicyAdvisor; @@ -609,13 +611,18 @@ protected ValidationEngine buildValidationEngine(CliContext cliContext, String d validationEngine.setFetcher(fetcher); validationEngine.getContext().setLocator(fetcher); validationEngine.setPolicyAdvisor(fetcher); - if (cliContext.getAdvisorFile() != null) { - if (cliContext.getAdvisorFile().endsWith(".json")) { - fetcher.setPolicyAdvisor(new JsonDrivenPolicyAdvisor(fetcher.getPolicyAdvisor(), new File(cliContext.getAdvisorFile()))); - } else { - fetcher.setPolicyAdvisor(new TextDrivenPolicyAdvisor(fetcher.getPolicyAdvisor(), new File(cliContext.getAdvisorFile()))); - } + } else { + DisabledValidationPolicyAdvisor fetcher = new DisabledValidationPolicyAdvisor(); + validationEngine.setPolicyAdvisor(fetcher); + } + if (cliContext.getAdvisorFile() != null) { + if (cliContext.getAdvisorFile().endsWith(".json")) { + validationEngine.getPolicyAdvisor().setPolicyAdvisor(new JsonDrivenPolicyAdvisor(validationEngine.getPolicyAdvisor().getPolicyAdvisor(), new File(cliContext.getAdvisorFile()))); + } else { + validationEngine.getPolicyAdvisor().setPolicyAdvisor(new TextDrivenPolicyAdvisor(validationEngine.getPolicyAdvisor().getPolicyAdvisor(), new File(cliContext.getAdvisorFile()))); } + } else { + validationEngine.getPolicyAdvisor().setPolicyAdvisor(new BasePolicyAdvisorForFullValidation(validationEngine.getPolicyAdvisor().getReferencePolicy())); } validationEngine.getBundleValidationRules().addAll(cliContext.getBundleValidationRules()); validationEngine.setJurisdiction(CodeSystemUtilities.readCoding(cliContext.getJurisdiction())); diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/codesystem/LoincChecker.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/codesystem/LoincChecker.java index c5ffd4415a..df64dc0ab1 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/codesystem/LoincChecker.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/codesystem/LoincChecker.java @@ -214,8 +214,12 @@ public PropertyValidationRules rulesForFilter(String property, EnumSet concepts = cs.getChildrenByName("concept"); int ce = 0; for (Element concept : concepts) { @@ -227,58 +238,66 @@ private boolean checkPropertyDefinition(List errors, Element PropertyDef pd = new PropertyDef(uri, code, type); KnownProperty ukp = null; KnownProperty ckp = null; - + if (uri != null) { - if (rule(errors, "2024-03-06", IssueType.BUSINESSRULE, cs.line(), cs.col(), stack.getLiteralPath(), !properties.containsKey(uri), I18nConstants.CODESYSTEM_PROPERTY_DUPLICATE_URI, uri)) { - properties.put(uri, pd); + if (rule(errors, "2024-03-06", IssueType.BUSINESSRULE, cs.line(), cs.col(), stack.getLiteralPath(), Utilities.isAbsoluteUrl(uri), I18nConstants.CODESYSTEM_PROPERTY_ABSOLUTE_URI, uri)) { + if (rule(errors, "2024-03-06", IssueType.BUSINESSRULE, cs.line(), cs.col(), stack.getLiteralPath(), !properties.containsKey(uri), I18nConstants.CODESYSTEM_PROPERTY_DUPLICATE_URI, uri)) { + properties.put(uri, pd); + } else { + ok = false; + } + if (uri.contains("hl7.org/fhir")) { + switch (uri) { + case "http://hl7.org/fhir/concept-properties#status" : + ukp = KnownProperty.Status; + break; + case "http://hl7.org/fhir/concept-properties#inactive" : + ukp = KnownProperty.Inactive; + break; + case "http://hl7.org/fhir/concept-properties#effectiveDate" : + ukp = KnownProperty.EffectiveDate; + break; + case "http://hl7.org/fhir/concept-properties#deprecationDate" : + ukp = KnownProperty.DeprecationDate; + break; + case "http://hl7.org/fhir/concept-properties#retirementDate" : + ukp = KnownProperty.RetirementDate; + break; + case "http://hl7.org/fhir/concept-properties#notSelectable" : + ukp = KnownProperty.NotSelectable; + break; + case "http://hl7.org/fhir/concept-properties#parent" : + ukp = KnownProperty.Parent; + break; + case "http://hl7.org/fhir/concept-properties#child" : + ukp = KnownProperty.Child; + break; + case "http://hl7.org/fhir/concept-properties#partOf" : + ukp = KnownProperty.PartOf; + break; + case "http://hl7.org/fhir/concept-properties#synonym" : + ukp = KnownProperty.Synonym; + break; + case "http://hl7.org/fhir/concept-properties#comment" : + ukp = KnownProperty.Comment; + break; + case "http://hl7.org/fhir/concept-properties#itemWeight" : + ukp = KnownProperty.ItemWeight; + break; + default: + ok = rule(errors, "2024-03-06", IssueType.BUSINESSRULE, cs.line(), cs.col(), stack.getLiteralPath(), isBaseSpec(cs.getNamedChildValue("url")) || isSelfRef(cs.getNamedChildValue("url"), uri), I18nConstants.CODESYSTEM_PROPERTY_BAD_HL7_URI, uri); + } + } } else { ok = false; } - if (uri.contains("hl7.org/fhir")) { - switch (uri) { - case "http://hl7.org/fhir/concept-properties#status" : - ukp = KnownProperty.Status; - break; - case "http://hl7.org/fhir/concept-properties#inactive" : - ukp = KnownProperty.Inactive; - break; - case "http://hl7.org/fhir/concept-properties#effectiveDate" : - ukp = KnownProperty.EffectiveDate; - break; - case "http://hl7.org/fhir/concept-properties#deprecationDate" : - ukp = KnownProperty.DeprecationDate; - break; - case "http://hl7.org/fhir/concept-properties#retirementDate" : - ukp = KnownProperty.RetirementDate; - break; - case "http://hl7.org/fhir/concept-properties#notSelectable" : - ukp = KnownProperty.NotSelectable; - break; - case "http://hl7.org/fhir/concept-properties#parent" : - ukp = KnownProperty.Parent; - break; - case "http://hl7.org/fhir/concept-properties#child" : - ukp = KnownProperty.Child; - break; - case "http://hl7.org/fhir/concept-properties#partOf" : - ukp = KnownProperty.PartOf; - break; - case "http://hl7.org/fhir/concept-properties#synonym" : - ukp = KnownProperty.Synonym; - break; - case "http://hl7.org/fhir/concept-properties#comment" : - ukp = KnownProperty.Comment; - break; - case "http://hl7.org/fhir/concept-properties#itemWeight" : - ukp = KnownProperty.ItemWeight; - break; - default: - ok = rule(errors, "2024-03-06", IssueType.BUSINESSRULE, cs.line(), cs.col(), stack.getLiteralPath(), isBaseSpec(cs.getNamedChildValue("url")) || isSelfRef(cs.getNamedChildValue("url"), uri), I18nConstants.CODESYSTEM_PROPERTY_BAD_HL7_URI, uri); - } - } } if (code != null) { - if (rule(errors, "2024-03-06", IssueType.BUSINESSRULE, cs.line(), cs.col(), stack.getLiteralPath(), !properties.containsKey(code), I18nConstants.CODESYSTEM_PROPERTY_DUPLICATE_CODE, code)) { + boolean pcok = properties.containsKey(code); + if (pcok) { + DebugUtilities.breakpoint(); + } + if (rule(errors, "2024-03-06", IssueType.BUSINESSRULE, cs.line(), cs.col(), stack.getLiteralPath(), !pcok, I18nConstants.CODESYSTEM_PROPERTY_DUPLICATE_CODE, code)) { properties.put(code, pd); } else { ok = false; @@ -523,10 +542,11 @@ private void metaChecks(List errors, Element cs, NodeStack st NodeStack s = stack.push(cs.getNamedChild("caseSensitive", false), -1, null, null); rule(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, s.getLiteralPath(), false, I18nConstants.CODESYSTEM_CS_HL7_PRESENT_ELEMENT_SUPPL, "caseSensitive"); } - if (!Utilities.noString(hierarchyMeaning)) { - NodeStack s = stack.push(cs.getNamedChild("hierarchyMeaning", false), -1, null, null); - rule(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, s.getLiteralPath(), false, I18nConstants.CODESYSTEM_CS_HL7_PRESENT_ELEMENT_SUPPL, "hierarchyMeaning"); - } + // can't run this test because of csd-2/csd-3 +// if (!Utilities.noString(hierarchyMeaning)) { +// NodeStack s = stack.push(cs.getNamedChild("hierarchyMeaning", false), -1, null, null); +// rule(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, s.getLiteralPath(), false, I18nConstants.CODESYSTEM_CS_HL7_PRESENT_ELEMENT_SUPPL, "hierarchyMeaning"); +// } } else { boolean isHL7 = url != null && (url.contains("hl7.org") || url.contains("fhir.org")); diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/StructureDefinitionValidator.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/StructureDefinitionValidator.java index bbf3af5a9a..f7ba19dc1d 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/StructureDefinitionValidator.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/StructureDefinitionValidator.java @@ -562,7 +562,7 @@ private boolean validateElementDefinition(List errors, List Date: Tue, 19 Nov 2024 06:07:04 +1100 Subject: [PATCH 2/7] fix error setting up policy advisor --- .../hl7/fhir/validation/cli/services/ValidationService.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/services/ValidationService.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/services/ValidationService.java index 98f3d0ac98..489a35efe5 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/services/ValidationService.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/services/ValidationService.java @@ -44,6 +44,7 @@ import org.hl7.fhir.r5.terminologies.CodeSystemUtilities; import org.hl7.fhir.r5.terminologies.client.TerminologyClientManager.InternalLogEvent; import org.hl7.fhir.r5.terminologies.utilities.TerminologyCache; +import org.hl7.fhir.r5.utils.validation.constants.ReferenceValidationPolicy; import org.hl7.fhir.utilities.DebugUtilities; import org.hl7.fhir.utilities.FhirPublication; import org.hl7.fhir.utilities.SystemExitManager; @@ -606,6 +607,7 @@ protected ValidationEngine buildValidationEngine(CliContext cliContext, String d validationEngine.setForPublication(cliContext.isForPublication()); validationEngine.setShowTimes(cliContext.isShowTimes()); validationEngine.setAllowExampleUrls(cliContext.isAllowExampleUrls()); + ReferenceValidationPolicy refpol = ReferenceValidationPolicy.CHECK_VALID; if (!cliContext.isDisableDefaultResourceFetcher()) { StandAloneValidatorFetcher fetcher = new StandAloneValidatorFetcher(validationEngine.getPcm(), validationEngine.getContext(), validationEngine); validationEngine.setFetcher(fetcher); @@ -614,6 +616,7 @@ protected ValidationEngine buildValidationEngine(CliContext cliContext, String d } else { DisabledValidationPolicyAdvisor fetcher = new DisabledValidationPolicyAdvisor(); validationEngine.setPolicyAdvisor(fetcher); + refpol = ReferenceValidationPolicy.CHECK_TYPE_IF_EXISTS; } if (cliContext.getAdvisorFile() != null) { if (cliContext.getAdvisorFile().endsWith(".json")) { @@ -622,7 +625,7 @@ protected ValidationEngine buildValidationEngine(CliContext cliContext, String d validationEngine.getPolicyAdvisor().setPolicyAdvisor(new TextDrivenPolicyAdvisor(validationEngine.getPolicyAdvisor().getPolicyAdvisor(), new File(cliContext.getAdvisorFile()))); } } else { - validationEngine.getPolicyAdvisor().setPolicyAdvisor(new BasePolicyAdvisorForFullValidation(validationEngine.getPolicyAdvisor().getReferencePolicy())); + validationEngine.getPolicyAdvisor().setPolicyAdvisor(new BasePolicyAdvisorForFullValidation(validationEngine.getPolicyAdvisor() == null ? refpol : validationEngine.getPolicyAdvisor().getReferencePolicy())); } validationEngine.getBundleValidationRules().addAll(cliContext.getBundleValidationRules()); validationEngine.setJurisdiction(CodeSystemUtilities.readCoding(cliContext.getJurisdiction())); From 5657bd6261f2368f70cdb1f9bc39e74a66c7404c Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Tue, 19 Nov 2024 06:07:17 +1100 Subject: [PATCH 3/7] Handle search syntax in value set filter --- .../fhir/validation/instance/type/ValueSetValidator.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/ValueSetValidator.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/ValueSetValidator.java index f75d722470..9821cba14f 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/ValueSetValidator.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/ValueSetValidator.java @@ -530,16 +530,25 @@ private boolean checkFilterValue(List errors, NodeStack stack ok = rule(errors, "2024-05-12", IssueType.INVALID, stack.getLiteralPath(), rules.getCodeList().contains(value), I18nConstants.VALUESET_BAD_FILTER_VALUE_DATETIME, property, value) && ok; break; case DateTime: + if (value != null && Utilities.startsWithInList(value, "eq", "ne", "gt", "lt", "ge", "le", "sa", "eb", "ap")) { + value = value.substring(2); + } ok = rule(errors, "2024-03-09", IssueType.INVALID, stack.getLiteralPath(), value.matches("([0-9]([0-9]([0-9][1-9]|[1-9]0)|[1-9]00)|[1-9]000)(-(0[1-9]|1[0-2])(-(0[1-9]|[1-2][0-9]|3[0-1])(T([01][0-9]|2[0-3]):[0-5][0-9]:([0-5][0-9]|60)(\\.[0-9]+)?(Z|(\\+|-)((0[0-9]|1[0-3]):[0-5][0-9]|14:00))?)?)?)?"), I18nConstants.VALUESET_BAD_FILTER_VALUE_DATETIME, property, value) && ok; break; case Decimal: + if (value != null && Utilities.startsWithInList(value, "eq", "ne", "gt", "lt", "ge", "le", "sa", "eb", "ap")) { + value = value.substring(2); + } ok = rule(errors, "2024-03-09", IssueType.INVALID, stack.getLiteralPath(), Utilities.isDecimal(value, true), I18nConstants.VALUESET_BAD_FILTER_VALUE_DECIMAL, property, value) && ok; break; case Integer: + if (value != null && Utilities.startsWithInList(value, "eq", "ne", "gt", "lt", "ge", "le", "sa", "eb", "ap")) { + value = value.substring(2); + } ok = rule(errors, "2024-03-09", IssueType.INVALID, stack.getLiteralPath(), Utilities.isInteger(value), I18nConstants.VALUESET_BAD_FILTER_VALUE_INTEGER, property, value) && ok; From 1a95532924eac4722bc360e700468f1109d1a87c Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Tue, 19 Nov 2024 06:17:27 +1100 Subject: [PATCH 4/7] compile fixes --- .../hl7/fhir/validation/cli/services/ValidationService.java | 1 - .../fhir/validation/instance/type/CodeSystemValidator.java | 4 ---- 2 files changed, 5 deletions(-) diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/services/ValidationService.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/services/ValidationService.java index 489a35efe5..ff29d4b196 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/services/ValidationService.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/services/ValidationService.java @@ -45,7 +45,6 @@ import org.hl7.fhir.r5.terminologies.client.TerminologyClientManager.InternalLogEvent; import org.hl7.fhir.r5.terminologies.utilities.TerminologyCache; import org.hl7.fhir.r5.utils.validation.constants.ReferenceValidationPolicy; -import org.hl7.fhir.utilities.DebugUtilities; import org.hl7.fhir.utilities.FhirPublication; import org.hl7.fhir.utilities.SystemExitManager; import org.hl7.fhir.utilities.TextFile; diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/CodeSystemValidator.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/CodeSystemValidator.java index 7648f88e31..a686192aef 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/CodeSystemValidator.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/CodeSystemValidator.java @@ -14,7 +14,6 @@ import org.hl7.fhir.r5.model.ValueSet; import org.hl7.fhir.r5.terminologies.CodeSystemUtilities; import org.hl7.fhir.utilities.CanonicalPair; -import org.hl7.fhir.utilities.DebugUtilities; import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.VersionUtilities; import org.hl7.fhir.utilities.i18n.I18nConstants; @@ -294,9 +293,6 @@ private boolean checkPropertyDefinition(List errors, Element } if (code != null) { boolean pcok = properties.containsKey(code); - if (pcok) { - DebugUtilities.breakpoint(); - } if (rule(errors, "2024-03-06", IssueType.BUSINESSRULE, cs.line(), cs.col(), stack.getLiteralPath(), !pcok, I18nConstants.CODESYSTEM_PROPERTY_DUPLICATE_CODE, code)) { properties.put(code, pd); } else { From 1321ae421e8e5d08e9a5152874a7d0a8c35875dc Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Tue, 19 Nov 2024 07:42:18 +1100 Subject: [PATCH 5/7] Fix for illegal names in profiles when code generating --- .../java/org/hl7/fhir/r5/profilemodel/gen/PECodeGenerator.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/profilemodel/gen/PECodeGenerator.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/profilemodel/gen/PECodeGenerator.java index 8abcf88f01..a65e62e9da 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/profilemodel/gen/PECodeGenerator.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/profilemodel/gen/PECodeGenerator.java @@ -343,6 +343,7 @@ private String generateEnum(PEDefinition source, PEDefinition field) { } return null; } + private void defineField(PEDefinition source, PEDefinition field) { if (field.types().size() == 1) { StructureDefinition sd = workerContext.fetchTypeDefinition(field.types().get(0).getUrl()); @@ -846,7 +847,7 @@ private void w(StringBuilder b, String line) { private PEGenClass genClass(PEDefinition source) { PEGenClass cls = new PEGenClass(); - cls.name = source.getProfile().getName(); + cls.name = Utilities.javaTokenize(source.getProfile().getName(), true); cls.base = source.getProfile().getType(); cls.doco = source.documentation(); cls.url = source.getProfile().getVersionedUrl(); From d3745e40938b044f8fa9822b3dc92449b909b34f Mon Sep 17 00:00:00 2001 From: Jens Kristian Villadsen Date: Mon, 18 Nov 2024 22:41:03 +0100 Subject: [PATCH 6/7] Update PECodeGenerator.java --- .../java/org/hl7/fhir/r4/profilemodel/gen/PECodeGenerator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/profilemodel/gen/PECodeGenerator.java b/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/profilemodel/gen/PECodeGenerator.java index 0432b3d37f..1e8487740d 100644 --- a/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/profilemodel/gen/PECodeGenerator.java +++ b/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/profilemodel/gen/PECodeGenerator.java @@ -845,7 +845,7 @@ private void w(StringBuilder b, String line) { private PEGenClass genClass(PEDefinition source) { PEGenClass cls = new PEGenClass(); - cls.name = source.getProfile().getName(); + cls.name = Utilities.javaTokenize(source.getProfile().getName(), true); cls.base = source.getProfile().getType(); cls.doco = source.documentation(); cls.url = source.getProfile().getVersionedUrl(); From a26fcf528aa93360653a952931ece65706397fa5 Mon Sep 17 00:00:00 2001 From: dotasek Date: Mon, 18 Nov 2024 18:50:48 -0500 Subject: [PATCH 7/7] Fix test failure. --- .../fhir/validation/cli/services/ValidationServiceTests.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/validation/cli/services/ValidationServiceTests.java b/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/validation/cli/services/ValidationServiceTests.java index 628f493c8e..68129861b5 100644 --- a/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/validation/cli/services/ValidationServiceTests.java +++ b/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/validation/cli/services/ValidationServiceTests.java @@ -30,6 +30,7 @@ import org.hl7.fhir.r5.elementmodel.Manager; import org.hl7.fhir.r5.model.StructureDefinition; import org.hl7.fhir.r5.test.utils.TestingUtilities; +import org.hl7.fhir.r5.utils.validation.IValidationPolicyAdvisor; import org.hl7.fhir.utilities.TimeTracker; import org.hl7.fhir.utilities.VersionUtil; import org.hl7.fhir.utilities.settings.FhirSettings; @@ -273,6 +274,7 @@ public void buildValidationEngineTest() throws IOException, URISyntaxException { final ValidationEngine mockValidationEngine = mock(ValidationEngine.class); when(mockValidationEngine.getContext()).thenReturn(workerContext); + when(mockValidationEngine.getPolicyAdvisor()).thenReturn(mock(IValidationPolicyAdvisor.class)); final ValidationEngine.ValidationEngineBuilder mockValidationEngineBuilder = mock(ValidationEngine.ValidationEngineBuilder.class); final ValidationService validationService = createFakeValidationService(mockValidationEngineBuilder, mockValidationEngine); @@ -291,7 +293,7 @@ public void buildValidationEngineDisableDefaultResourceFetcherTest() throws IOEx final ValidationEngine mockValidationEngine = mock(ValidationEngine.class); when(mockValidationEngine.getContext()).thenReturn(workerContext); - + when(mockValidationEngine.getPolicyAdvisor()).thenReturn(mock(IValidationPolicyAdvisor.class)); final ValidationEngine.ValidationEngineBuilder mockValidationEngineBuilder = mock(ValidationEngine.ValidationEngineBuilder.class); final ValidationService validationService = createFakeValidationService(mockValidationEngineBuilder, mockValidationEngine);