diff --git a/i18n-coverage-table.png b/i18n-coverage-table.png index 612370aec..e3f25dc2d 100644 Binary files a/i18n-coverage-table.png and b/i18n-coverage-table.png differ diff --git a/i18n-coverage.csv b/i18n-coverage.csv index 49cf39ece..bf44bb436 100644 --- a/i18n-coverage.csv +++ b/i18n-coverage.csv @@ -1,5 +1,5 @@ Locale,Coverage #,Coverage % -de,831,41% +de,831,40% es,714,35% ja,902,44% nl,1989,98% diff --git a/master-branch-pipeline.yml b/master-branch-pipeline.yml index 6b94ef18d..bdafd4688 100644 --- a/master-branch-pipeline.yml +++ b/master-branch-pipeline.yml @@ -82,7 +82,7 @@ jobs: # Deploy the SNAPSHOT artifact to sonatype nexus. # This is done for the master branch merges only. - - task: Maven@3 + - task: Maven@4 displayName: 'Deploy to Sonatype staging' inputs: mavenPomFile: '$(System.DefaultWorkingDirectory)/pom.xml' @@ -115,7 +115,7 @@ jobs: # Deploy the SNAPSHOT artifact to GitHub packages. # This is done for the master branch merges only. - - task: Maven@3 + - task: Maven@4 displayName: 'Deploy to GitHub packages' inputs: mavenPomFile: '$(System.DefaultWorkingDirectory)/pom.xml' @@ -164,7 +164,7 @@ jobs: pip3 install pandas displayName: 'Set up python packages' - - task: Maven@3 + - task: Maven@4 inputs: mavenPomFile: '$(System.DefaultWorkingDirectory)/pom.xml' options: '-Dmaven.repo.local=$(MAVEN_CACHE_FOLDER) -pl org.hl7.fhir.utilities ' diff --git a/org.hl7.fhir.convertors/pom.xml b/org.hl7.fhir.convertors/pom.xml index a0a3869df..954879875 100644 --- a/org.hl7.fhir.convertors/pom.xml +++ b/org.hl7.fhir.convertors/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir org.hl7.fhir.core - 6.3.24-SNAPSHOT + 6.3.27-SNAPSHOT ../pom.xml diff --git a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/conv30_40/resources30_40/Consent30_40.java b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/conv30_40/resources30_40/Consent30_40.java index 1c783f74c..41dec2516 100644 --- a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/conv30_40/resources30_40/Consent30_40.java +++ b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/conv30_40/resources30_40/Consent30_40.java @@ -47,7 +47,7 @@ public class Consent30_40 { tgt.setPolicyRule(new CodeableConcept(c)); } if (src.hasSecurityLabel() || src.hasPeriod() || src.hasActor() || src.hasAction() || src.hasPurpose() || src.hasDataPeriod() || src.hasData() || src.hasExcept()) { - org.hl7.fhir.r4.model.Consent.provisionComponent pc = new org.hl7.fhir.r4.model.Consent.provisionComponent(); + org.hl7.fhir.r4.model.Consent.ProvisionComponent pc = new org.hl7.fhir.r4.model.Consent.ProvisionComponent(); if (src.hasPeriod()) pc.setPeriod(Period30_40.convertPeriod(src.getPeriod())); for (org.hl7.fhir.dstu3.model.Consent.ConsentActorComponent t : src.getActor()) @@ -104,7 +104,7 @@ public class Consent30_40 { } } if (src.hasProvision()) { - org.hl7.fhir.r4.model.Consent.provisionComponent p = src.getProvision(); + org.hl7.fhir.r4.model.Consent.ProvisionComponent p = src.getProvision(); if (p.hasPeriod()) tgt.setPeriod(Period30_40.convertPeriod(p.getPeriod())); for (org.hl7.fhir.r4.model.Consent.provisionActorComponent t : p.getActor()) @@ -117,7 +117,7 @@ public class Consent30_40 { tgt.setDataPeriod(Period30_40.convertPeriod(p.getDataPeriod())); for (org.hl7.fhir.r4.model.Consent.provisionDataComponent t : p.getData()) tgt.addData(convertConsentDataComponent(t)); - for (org.hl7.fhir.r4.model.Consent.provisionComponent t : p.getProvision()) + for (org.hl7.fhir.r4.model.Consent.ProvisionComponent t : p.getProvision()) tgt.addExcept(convertExceptComponent(t)); } return tgt; @@ -369,7 +369,7 @@ public class Consent30_40 { return tgt; } - static public org.hl7.fhir.dstu3.model.Consent.ExceptComponent convertExceptComponent(org.hl7.fhir.r4.model.Consent.provisionComponent src) throws FHIRException { + static public org.hl7.fhir.dstu3.model.Consent.ExceptComponent convertExceptComponent(org.hl7.fhir.r4.model.Consent.ProvisionComponent src) throws FHIRException { if (src == null) return null; org.hl7.fhir.dstu3.model.Consent.ExceptComponent tgt = new org.hl7.fhir.dstu3.model.Consent.ExceptComponent(); @@ -393,10 +393,10 @@ public class Consent30_40 { return tgt; } - static public org.hl7.fhir.r4.model.Consent.provisionComponent convertExceptComponent(org.hl7.fhir.dstu3.model.Consent.ExceptComponent src) throws FHIRException { + static public org.hl7.fhir.r4.model.Consent.ProvisionComponent convertExceptComponent(org.hl7.fhir.dstu3.model.Consent.ExceptComponent src) throws FHIRException { if (src == null) return null; - org.hl7.fhir.r4.model.Consent.provisionComponent tgt = new org.hl7.fhir.r4.model.Consent.provisionComponent(); + org.hl7.fhir.r4.model.Consent.ProvisionComponent tgt = new org.hl7.fhir.r4.model.Consent.ProvisionComponent(); ConversionContext30_40.INSTANCE.getVersionConvertor_30_40().copyBackboneElement(src,tgt); if (src.hasType()) tgt.setTypeElement(convertConsentExceptType(src.getTypeElement())); diff --git a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/conv40_50/resources40_50/Consent40_50.java b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/conv40_50/resources40_50/Consent40_50.java index 0fe389de5..727efa673 100644 --- a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/conv40_50/resources40_50/Consent40_50.java +++ b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/conv40_50/resources40_50/Consent40_50.java @@ -220,7 +220,7 @@ public class Consent40_50 { return tgt; } - public static org.hl7.fhir.r5.model.Consent.ProvisionComponent convertprovisionComponent(org.hl7.fhir.r4.model.Consent.provisionComponent src) throws FHIRException { + public static org.hl7.fhir.r5.model.Consent.ProvisionComponent convertprovisionComponent(org.hl7.fhir.r4.model.Consent.ProvisionComponent src) throws FHIRException { if (src == null) return null; org.hl7.fhir.r5.model.Consent.ProvisionComponent tgt = new org.hl7.fhir.r5.model.Consent.ProvisionComponent(); @@ -242,15 +242,15 @@ public class Consent40_50 { tgt.setDataPeriod(Period40_50.convertPeriod(src.getDataPeriod())); for (org.hl7.fhir.r4.model.Consent.provisionDataComponent t : src.getData()) tgt.addData(convertprovisionDataComponent(t)); - for (org.hl7.fhir.r4.model.Consent.provisionComponent t : src.getProvision()) + for (org.hl7.fhir.r4.model.Consent.ProvisionComponent t : src.getProvision()) tgt.addProvision(convertprovisionComponent(t)); return tgt; } - public static org.hl7.fhir.r4.model.Consent.provisionComponent convertprovisionComponent(org.hl7.fhir.r5.model.Consent.ProvisionComponent src) throws FHIRException { + public static org.hl7.fhir.r4.model.Consent.ProvisionComponent convertprovisionComponent(org.hl7.fhir.r5.model.Consent.ProvisionComponent src) throws FHIRException { if (src == null) return null; - org.hl7.fhir.r4.model.Consent.provisionComponent tgt = new org.hl7.fhir.r4.model.Consent.provisionComponent(); + org.hl7.fhir.r4.model.Consent.ProvisionComponent tgt = new org.hl7.fhir.r4.model.Consent.ProvisionComponent(); ConversionContext40_50.INSTANCE.getVersionConvertor_40_50().copyBackboneElement(src, tgt); // if (src.hasType()) // tgt.setTypeElement(convertConsentProvisionType(src.getTypeElement())); diff --git a/org.hl7.fhir.dstu2/pom.xml b/org.hl7.fhir.dstu2/pom.xml index 8055af71e..0f35fa8bd 100644 --- a/org.hl7.fhir.dstu2/pom.xml +++ b/org.hl7.fhir.dstu2/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir org.hl7.fhir.core - 6.3.24-SNAPSHOT + 6.3.27-SNAPSHOT ../pom.xml diff --git a/org.hl7.fhir.dstu2016may/pom.xml b/org.hl7.fhir.dstu2016may/pom.xml index da50ebb03..73f375a3b 100644 --- a/org.hl7.fhir.dstu2016may/pom.xml +++ b/org.hl7.fhir.dstu2016may/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir org.hl7.fhir.core - 6.3.24-SNAPSHOT + 6.3.27-SNAPSHOT ../pom.xml diff --git a/org.hl7.fhir.dstu3/pom.xml b/org.hl7.fhir.dstu3/pom.xml index 0a6da6acf..cf607fb20 100644 --- a/org.hl7.fhir.dstu3/pom.xml +++ b/org.hl7.fhir.dstu3/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir org.hl7.fhir.core - 6.3.24-SNAPSHOT + 6.3.27-SNAPSHOT ../pom.xml diff --git a/org.hl7.fhir.dstu3/src/main/java/org/hl7/fhir/dstu3/model/Quantity.java b/org.hl7.fhir.dstu3/src/main/java/org/hl7/fhir/dstu3/model/Quantity.java index fd3912594..1fe0a11e0 100644 --- a/org.hl7.fhir.dstu3/src/main/java/org/hl7/fhir/dstu3/model/Quantity.java +++ b/org.hl7.fhir.dstu3/src/main/java/org/hl7/fhir/dstu3/model/Quantity.java @@ -1,6 +1,7 @@ package org.hl7.fhir.dstu3.model; import java.math.BigDecimal; +import java.util.ArrayList; /* Copyright (c) 2011+, HL7, Inc. @@ -668,12 +669,16 @@ public class Quantity extends Type implements ICompositeType { public Quantity copy() { Quantity dst = new Quantity(); copyValues(dst); + return dst; + } + + public void copyValues(Quantity dst) { + super.copyValues(dst); dst.value = value == null ? null : value.copy(); dst.comparator = comparator == null ? null : comparator.copy(); dst.unit = unit == null ? null : unit.copy(); dst.system = system == null ? null : system.copy(); dst.code = code == null ? null : code.copy(); - return dst; } protected Quantity typedCopy() { diff --git a/org.hl7.fhir.dstu3/src/test/java/org/hl7/fhir/dstu3/model/MedicationAdministrationCopyTest.java b/org.hl7.fhir.dstu3/src/test/java/org/hl7/fhir/dstu3/model/MedicationAdministrationCopyTest.java new file mode 100644 index 000000000..a1adeb216 --- /dev/null +++ b/org.hl7.fhir.dstu3/src/test/java/org/hl7/fhir/dstu3/model/MedicationAdministrationCopyTest.java @@ -0,0 +1,40 @@ +package org.hl7.fhir.dstu3.model; + +import static org.junit.Assert.assertTrue; + +import java.io.IOException; + +import org.hl7.fhir.dstu3.formats.JsonParser; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +public class MedicationAdministrationCopyTest { + + @DisplayName("Test MedicationAdministration copy") + @Test + public void test() throws IOException { + MedicationAdministration beforeCopy = createMedAdminWithDosageDurationExtension(); + MedicationAdministration afterCopy = beforeCopy.copy(); + + System.out.println("---- BEFORE COPY (BEGIN)"); + System.out.println(new JsonParser().composeString(beforeCopy)); + System.out.println("---- BEFORE COPY (END)"); + System.out.println(); + System.out.println("---- AFTER COPY (BEGIN)"); + System.out.println(new JsonParser().composeString(afterCopy)); + System.out.println("---- AFTER COPY (END)"); + assertTrue(beforeCopy.equalsDeep(afterCopy)); + } + + private static MedicationAdministration createMedAdminWithDosageDurationExtension() { + MedicationAdministration resource = new MedicationAdministration(); + resource.setId("12345"); + var dosage = new MedicationAdministration.MedicationAdministrationDosageComponent(); + dosage.setDose((SimpleQuantity) new SimpleQuantity().setValue(40)) + .addExtension(new Extension() + .setUrl("http://duration") + .setValue(new Duration().setValue(5340000))); + resource.setDosage(dosage); + return resource; + } +} diff --git a/org.hl7.fhir.r4/pom.xml b/org.hl7.fhir.r4/pom.xml index 9fa2bbaa8..5dcc8666b 100644 --- a/org.hl7.fhir.r4/pom.xml +++ b/org.hl7.fhir.r4/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir org.hl7.fhir.core - 6.3.24-SNAPSHOT + 6.3.27-SNAPSHOT ../pom.xml diff --git a/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/formats/JsonParser.java b/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/formats/JsonParser.java index 06ee27a94..49eff1638 100644 --- a/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/formats/JsonParser.java +++ b/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/formats/JsonParser.java @@ -8400,15 +8400,15 @@ public class JsonParser extends JsonParserBase { parseElementProperties(getJObject(json, "_verificationDate"), res.getVerificationDateElement()); } - protected Consent.provisionComponent parseConsentprovisionComponent(JsonObject json, Consent owner) + protected Consent.ProvisionComponent parseConsentprovisionComponent(JsonObject json, Consent owner) throws IOException, FHIRFormatError { - Consent.provisionComponent res = new Consent.provisionComponent(); + Consent.ProvisionComponent res = new Consent.ProvisionComponent(); parseConsentprovisionComponentProperties(json, owner, res); return res; } protected void parseConsentprovisionComponentProperties(JsonObject json, Consent owner, - Consent.provisionComponent res) throws IOException, FHIRFormatError { + Consent.ProvisionComponent res) throws IOException, FHIRFormatError { parseBackboneElementProperties(json, res); if (json.has("type")) res.setTypeElement(parseEnumeration(json.get("type").getAsString(), Consent.ConsentProvisionType.NULL, @@ -41383,7 +41383,7 @@ public class JsonParser extends JsonParserBase { } } - protected void composeConsentprovisionComponent(String name, Consent.provisionComponent element) throws IOException { + protected void composeConsentprovisionComponent(String name, Consent.ProvisionComponent element) throws IOException { if (element != null) { open(name); composeConsentprovisionComponentInner(element); @@ -41391,7 +41391,7 @@ public class JsonParser extends JsonParserBase { } } - protected void composeConsentprovisionComponentInner(Consent.provisionComponent element) throws IOException { + protected void composeConsentprovisionComponentInner(Consent.ProvisionComponent element) throws IOException { composeBackbone(element); if (element.hasTypeElement()) { composeEnumerationCore("type", element.getTypeElement(), new Consent.ConsentProvisionTypeEnumFactory(), false); @@ -41454,7 +41454,7 @@ public class JsonParser extends JsonParserBase { ; if (element.hasProvision()) { openArray("provision"); - for (Consent.provisionComponent e : element.getProvision()) + for (Consent.ProvisionComponent e : element.getProvision()) composeConsentprovisionComponent(null, e); closeArray(); } diff --git a/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/formats/RdfParser.java b/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/formats/RdfParser.java index e09127adc..76ffee7e9 100644 --- a/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/formats/RdfParser.java +++ b/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/formats/RdfParser.java @@ -4917,7 +4917,7 @@ public class RdfParser extends RdfParserBase { } protected void composeConsentprovisionComponent(Complex parent, String parentType, String name, - Consent.provisionComponent element, int index) { + Consent.ProvisionComponent element, int index) { if (element == null) return; Complex t; diff --git a/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/formats/XmlParser.java b/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/formats/XmlParser.java index 7ccf6fdd6..6c46487ea 100644 --- a/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/formats/XmlParser.java +++ b/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/formats/XmlParser.java @@ -6924,9 +6924,9 @@ public class XmlParser extends XmlParserBase { return true; } - protected Consent.provisionComponent parseConsentprovisionComponent(XmlPullParser xpp, Consent owner) + protected Consent.ProvisionComponent parseConsentprovisionComponent(XmlPullParser xpp, Consent owner) throws XmlPullParserException, IOException, FHIRFormatError { - Consent.provisionComponent res = new Consent.provisionComponent(); + Consent.ProvisionComponent res = new Consent.ProvisionComponent(); parseBackboneAttributes(xpp, res); next(xpp); int eventType = nextNoWhitespace(xpp); @@ -6941,7 +6941,7 @@ public class XmlParser extends XmlParserBase { } protected boolean parseConsentprovisionComponentContent(int eventType, XmlPullParser xpp, Consent owner, - Consent.provisionComponent res) throws XmlPullParserException, IOException, FHIRFormatError { + Consent.ProvisionComponent res) throws XmlPullParserException, IOException, FHIRFormatError { if (eventType == XmlPullParser.START_TAG && xpp.getName().equals("type")) { res.setTypeElement( parseEnumeration(xpp, Consent.ConsentProvisionType.NULL, new Consent.ConsentProvisionTypeEnumFactory())); @@ -34008,7 +34008,7 @@ public class XmlParser extends XmlParserBase { } } - protected void composeConsentprovisionComponent(String name, Consent.provisionComponent element) throws IOException { + protected void composeConsentprovisionComponent(String name, Consent.ProvisionComponent element) throws IOException { if (element != null) { composeElementAttributes(element); xml.enter(FHIR_NS, name); @@ -34018,7 +34018,7 @@ public class XmlParser extends XmlParserBase { } } - protected void composeConsentprovisionComponentElements(Consent.provisionComponent element) throws IOException { + protected void composeConsentprovisionComponentElements(Consent.ProvisionComponent element) throws IOException { composeBackboneElementElements(element); if (element.hasTypeElement()) composeEnumeration("type", element.getTypeElement(), new Consent.ConsentProvisionTypeEnumFactory()); @@ -34057,7 +34057,7 @@ public class XmlParser extends XmlParserBase { composeConsentprovisionDataComponent("data", e); } if (element.hasProvision()) { - for (Consent.provisionComponent e : element.getProvision()) + for (Consent.ProvisionComponent e : element.getProvision()) composeConsentprovisionComponent("provision", e); } } diff --git a/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/model/Consent.java b/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/model/Consent.java index 1560c3f27..eb2e25345 100644 --- a/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/model/Consent.java +++ b/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/model/Consent.java @@ -1221,7 +1221,7 @@ public class Consent extends DomainResource { } @Block() - public static class provisionComponent extends BackboneElement implements IBaseBackboneElement { + public static class ProvisionComponent extends BackboneElement implements IBaseBackboneElement { /** * Action to take - permit or deny - when the rule conditions are met. Not * permitted in root rule, required in all nested rules. @@ -1314,16 +1314,16 @@ public class Consent extends DomainResource { * Rules which provide exceptions to the base rule or subrules. */ @Child(name = "provision", type = { - provisionComponent.class }, order = 11, min = 0, max = Child.MAX_UNLIMITED, modifier = false, summary = false) + ProvisionComponent.class }, order = 11, min = 0, max = Child.MAX_UNLIMITED, modifier = false, summary = false) @Description(shortDefinition = "Nested Exception Rules", formalDefinition = "Rules which provide exceptions to the base rule or subrules.") - protected List provision; + protected List provision; private static final long serialVersionUID = -1280172451L; /** * Constructor */ - public provisionComponent() { + public ProvisionComponent() { super(); } @@ -1357,7 +1357,7 @@ public class Consent extends DomainResource { * extensions. The accessor "getType" gives direct access to the * value */ - public provisionComponent setTypeElement(Enumeration value) { + public ProvisionComponent setTypeElement(Enumeration value) { this.type = value; return this; } @@ -1374,7 +1374,7 @@ public class Consent extends DomainResource { * @param value Action to take - permit or deny - when the rule conditions are * met. Not permitted in root rule, required in all nested rules. */ - public provisionComponent setType(ConsentProvisionType value) { + public ProvisionComponent setType(ConsentProvisionType value) { if (value == null) this.type = null; else { @@ -1404,7 +1404,7 @@ public class Consent extends DomainResource { /** * @param value {@link #period} (The timeframe in this rule is valid.) */ - public provisionComponent setPeriod(Period value) { + public ProvisionComponent setPeriod(Period value) { this.period = value; return this; } @@ -1423,7 +1423,7 @@ public class Consent extends DomainResource { /** * @return Returns a reference to this for easy method chaining */ - public provisionComponent setActor(List theActor) { + public ProvisionComponent setActor(List theActor) { this.actor = theActor; return this; } @@ -1445,7 +1445,7 @@ public class Consent extends DomainResource { return t; } - public provisionComponent addActor(provisionActorComponent t) { // 3 + public ProvisionComponent addActor(provisionActorComponent t) { // 3 if (t == null) return this; if (this.actor == null) @@ -1477,7 +1477,7 @@ public class Consent extends DomainResource { /** * @return Returns a reference to this for easy method chaining */ - public provisionComponent setAction(List theAction) { + public ProvisionComponent setAction(List theAction) { this.action = theAction; return this; } @@ -1499,7 +1499,7 @@ public class Consent extends DomainResource { return t; } - public provisionComponent addAction(CodeableConcept t) { // 3 + public ProvisionComponent addAction(CodeableConcept t) { // 3 if (t == null) return this; if (this.action == null) @@ -1533,7 +1533,7 @@ public class Consent extends DomainResource { /** * @return Returns a reference to this for easy method chaining */ - public provisionComponent setSecurityLabel(List theSecurityLabel) { + public ProvisionComponent setSecurityLabel(List theSecurityLabel) { this.securityLabel = theSecurityLabel; return this; } @@ -1555,7 +1555,7 @@ public class Consent extends DomainResource { return t; } - public provisionComponent addSecurityLabel(Coding t) { // 3 + public ProvisionComponent addSecurityLabel(Coding t) { // 3 if (t == null) return this; if (this.securityLabel == null) @@ -1589,7 +1589,7 @@ public class Consent extends DomainResource { /** * @return Returns a reference to this for easy method chaining */ - public provisionComponent setPurpose(List thePurpose) { + public ProvisionComponent setPurpose(List thePurpose) { this.purpose = thePurpose; return this; } @@ -1611,7 +1611,7 @@ public class Consent extends DomainResource { return t; } - public provisionComponent addPurpose(Coding t) { // 3 + public ProvisionComponent addPurpose(Coding t) { // 3 if (t == null) return this; if (this.purpose == null) @@ -1646,7 +1646,7 @@ public class Consent extends DomainResource { /** * @return Returns a reference to this for easy method chaining */ - public provisionComponent setClass_(List theClass_) { + public ProvisionComponent setClass_(List theClass_) { this.class_ = theClass_; return this; } @@ -1668,7 +1668,7 @@ public class Consent extends DomainResource { return t; } - public provisionComponent addClass_(Coding t) { // 3 + public ProvisionComponent addClass_(Coding t) { // 3 if (t == null) return this; if (this.class_ == null) @@ -1701,7 +1701,7 @@ public class Consent extends DomainResource { /** * @return Returns a reference to this for easy method chaining */ - public provisionComponent setCode(List theCode) { + public ProvisionComponent setCode(List theCode) { this.code = theCode; return this; } @@ -1723,7 +1723,7 @@ public class Consent extends DomainResource { return t; } - public provisionComponent addCode(CodeableConcept t) { // 3 + public ProvisionComponent addCode(CodeableConcept t) { // 3 if (t == null) return this; if (this.code == null) @@ -1764,7 +1764,7 @@ public class Consent extends DomainResource { * @param value {@link #dataPeriod} (Clinical or Operational Relevant period of * time that bounds the data controlled by this rule.) */ - public provisionComponent setDataPeriod(Period value) { + public ProvisionComponent setDataPeriod(Period value) { this.dataPeriod = value; return this; } @@ -1782,7 +1782,7 @@ public class Consent extends DomainResource { /** * @return Returns a reference to this for easy method chaining */ - public provisionComponent setData(List theData) { + public ProvisionComponent setData(List theData) { this.data = theData; return this; } @@ -1804,7 +1804,7 @@ public class Consent extends DomainResource { return t; } - public provisionComponent addData(provisionDataComponent t) { // 3 + public ProvisionComponent addData(provisionDataComponent t) { // 3 if (t == null) return this; if (this.data == null) @@ -1828,16 +1828,16 @@ public class Consent extends DomainResource { * @return {@link #provision} (Rules which provide exceptions to the base rule * or subrules.) */ - public List getProvision() { + public List getProvision() { if (this.provision == null) - this.provision = new ArrayList(); + this.provision = new ArrayList(); return this.provision; } /** * @return Returns a reference to this for easy method chaining */ - public provisionComponent setProvision(List theProvision) { + public ProvisionComponent setProvision(List theProvision) { this.provision = theProvision; return this; } @@ -1845,25 +1845,25 @@ public class Consent extends DomainResource { public boolean hasProvision() { if (this.provision == null) return false; - for (provisionComponent item : this.provision) + for (ProvisionComponent item : this.provision) if (!item.isEmpty()) return true; return false; } - public provisionComponent addProvision() { // 3 - provisionComponent t = new provisionComponent(); + public ProvisionComponent addProvision() { // 3 + ProvisionComponent t = new ProvisionComponent(); if (this.provision == null) - this.provision = new ArrayList(); + this.provision = new ArrayList(); this.provision.add(t); return t; } - public provisionComponent addProvision(provisionComponent t) { // 3 + public ProvisionComponent addProvision(ProvisionComponent t) { // 3 if (t == null) return this; if (this.provision == null) - this.provision = new ArrayList(); + this.provision = new ArrayList(); this.provision.add(t); return this; } @@ -1872,7 +1872,7 @@ public class Consent extends DomainResource { * @return The first repetition of repeating field {@link #provision}, creating * it if it does not already exist */ - public provisionComponent getProvisionFirstRep() { + public ProvisionComponent getProvisionFirstRep() { if (getProvision().isEmpty()) { addProvision(); } @@ -2027,7 +2027,7 @@ public class Consent extends DomainResource { this.getData().add((provisionDataComponent) value); // provisionDataComponent return value; case -547120939: // provision - this.getProvision().add((provisionComponent) value); // provisionComponent + this.getProvision().add((ProvisionComponent) value); // provisionComponent return value; default: return super.setProperty(hash, name, value); @@ -2059,7 +2059,7 @@ public class Consent extends DomainResource { } else if (name.equals("data")) { this.getData().add((provisionDataComponent) value); } else if (name.equals("provision")) { - this.getProvision().add((provisionComponent) value); + this.getProvision().add((ProvisionComponent) value); } else return super.setProperty(name, value); return value; @@ -2088,7 +2088,7 @@ public class Consent extends DomainResource { } else if (name.equals("data")) { this.getData().remove((provisionDataComponent) value); } else if (name.equals("provision")) { - this.getProvision().remove((provisionComponent) value); + this.getProvision().remove((ProvisionComponent) value); } else super.removeChild(name, value); @@ -2186,13 +2186,13 @@ public class Consent extends DomainResource { return super.addChild(name); } - public provisionComponent copy() { - provisionComponent dst = new provisionComponent(); + public ProvisionComponent copy() { + ProvisionComponent dst = new ProvisionComponent(); copyValues(dst); return dst; } - public void copyValues(provisionComponent dst) { + public void copyValues(ProvisionComponent dst) { super.copyValues(dst); dst.type = type == null ? null : type.copy(); dst.period = period == null ? null : period.copy(); @@ -2240,8 +2240,8 @@ public class Consent extends DomainResource { } ; if (provision != null) { - dst.provision = new ArrayList(); - for (provisionComponent i : provision) + dst.provision = new ArrayList(); + for (ProvisionComponent i : provision) dst.provision.add(i.copy()); } ; @@ -2251,9 +2251,9 @@ public class Consent extends DomainResource { public boolean equalsDeep(Base other_) { if (!super.equalsDeep(other_)) return false; - if (!(other_ instanceof provisionComponent)) + if (!(other_ instanceof ProvisionComponent)) return false; - provisionComponent o = (provisionComponent) other_; + ProvisionComponent o = (ProvisionComponent) other_; return compareDeep(type, o.type, true) && compareDeep(period, o.period, true) && compareDeep(actor, o.actor, true) && compareDeep(action, o.action, true) && compareDeep(securityLabel, o.securityLabel, true) && compareDeep(purpose, o.purpose, true) && compareDeep(class_, o.class_, true) @@ -2265,9 +2265,9 @@ public class Consent extends DomainResource { public boolean equalsShallow(Base other_) { if (!super.equalsShallow(other_)) return false; - if (!(other_ instanceof provisionComponent)) + if (!(other_ instanceof ProvisionComponent)) return false; - provisionComponent o = (provisionComponent) other_; + ProvisionComponent o = (ProvisionComponent) other_; return compareValues(type, o.type, true); } @@ -3002,7 +3002,7 @@ public class Consent extends DomainResource { */ @Child(name = "provision", type = {}, order = 12, min = 0, max = 1, modifier = false, summary = true) @Description(shortDefinition = "Constraints to the base Consent.policyRule", formalDefinition = "An exception to the base policy of this consent. An exception can be an addition or removal of access permissions.") - protected provisionComponent provision; + protected ProvisionComponent provision; private static final long serialVersionUID = 206528051L; @@ -3669,12 +3669,12 @@ public class Consent extends DomainResource { * @return {@link #provision} (An exception to the base policy of this consent. * An exception can be an addition or removal of access permissions.) */ - public provisionComponent getProvision() { + public ProvisionComponent getProvision() { if (this.provision == null) if (Configuration.errorOnAutoCreate()) throw new Error("Attempt to auto-create Consent.provision"); else if (Configuration.doAutoCreate()) - this.provision = new provisionComponent(); // cc + this.provision = new ProvisionComponent(); // cc return this.provision; } @@ -3687,7 +3687,7 @@ public class Consent extends DomainResource { * consent. An exception can be an addition or removal of access * permissions.) */ - public Consent setProvision(provisionComponent value) { + public Consent setProvision(ProvisionComponent value) { this.provision = value; return this; } @@ -3883,7 +3883,7 @@ public class Consent extends DomainResource { this.getVerification().add((ConsentVerificationComponent) value); // ConsentVerificationComponent return value; case -547120939: // provision - this.provision = (provisionComponent) value; // provisionComponent + this.provision = (ProvisionComponent) value; // provisionComponent return value; default: return super.setProperty(hash, name, value); @@ -3919,7 +3919,7 @@ public class Consent extends DomainResource { } else if (name.equals("verification")) { this.getVerification().add((ConsentVerificationComponent) value); } else if (name.equals("provision")) { - this.provision = (provisionComponent) value; // provisionComponent + this.provision = (ProvisionComponent) value; // provisionComponent } else return super.setProperty(name, value); return value; @@ -3952,7 +3952,7 @@ public class Consent extends DomainResource { } else if (name.equals("verification")) { this.getVerification().remove((ConsentVerificationComponent) value); } else if (name.equals("provision")) { - this.provision = (provisionComponent) value; // provisionComponent + this.provision = (ProvisionComponent) value; // provisionComponent } else super.removeChild(name, value); @@ -4064,7 +4064,7 @@ public class Consent extends DomainResource { } else if (name.equals("verification")) { return addVerification(); } else if (name.equals("provision")) { - this.provision = new provisionComponent(); + this.provision = new ProvisionComponent(); return this.provision; } else return super.addChild(name); diff --git a/org.hl7.fhir.r4b/pom.xml b/org.hl7.fhir.r4b/pom.xml index 25f7e8516..aec9ce8e4 100644 --- a/org.hl7.fhir.r4b/pom.xml +++ b/org.hl7.fhir.r4b/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir org.hl7.fhir.core - 6.3.24-SNAPSHOT + 6.3.27-SNAPSHOT ../pom.xml diff --git a/org.hl7.fhir.r5/pom.xml b/org.hl7.fhir.r5/pom.xml index 9c76d955d..b196a2821 100644 --- a/org.hl7.fhir.r5/pom.xml +++ b/org.hl7.fhir.r5/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir org.hl7.fhir.core - 6.3.24-SNAPSHOT + 6.3.27-SNAPSHOT ../pom.xml diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/profile/ProfilePathProcessor.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/profile/ProfilePathProcessor.java index 6a939f95a..a26d81569 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/profile/ProfilePathProcessor.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/profile/ProfilePathProcessor.java @@ -289,7 +289,7 @@ public class ProfilePathProcessor { start++; } else { // we're just going to accept the differential slicing at face value - ElementDefinition outcome = profileUtilities.updateURLs(getUrl(), getWebUrl(), currentBase.copy()); + ElementDefinition outcome = profileUtilities.updateURLs(getUrl(), getWebUrl(), currentBase.copy(), true); outcome.setPath(profileUtilities.fixedPathDest(getContextPathTarget(), outcome.getPath(), getRedirector(), getContextPathSource())); profileUtilities.updateFromBase(outcome, currentBase, getSourceStructureDefinition().getUrl()); @@ -667,14 +667,14 @@ public class ProfilePathProcessor { // some of what's in currentBase overrides template template = profileUtilities.fillOutFromBase(template, currentBase); - ElementDefinition outcome = profileUtilities.updateURLs(getUrl(), getWebUrl(), template); + ElementDefinition outcome = profileUtilities.updateURLs(getUrl(), getWebUrl(), template, true); outcome.setPath(profileUtilities.fixedPathDest(getContextPathTarget(), outcome.getPath(), getRedirector(), getContextPathSource())); res = outcome; profileUtilities.updateFromBase(outcome, currentBase, getSourceStructureDefinition().getUrl()); if (diffMatches.get(0).hasSliceName()) { template = currentBase.copy(); - template = profileUtilities.updateURLs(getUrl(), getWebUrl(), template); + template = profileUtilities.updateURLs(getUrl(), getWebUrl(), template, true); template.setPath(profileUtilities.fixedPathDest(getContextPathTarget(), template.getPath(), getRedirector(), getContextPathSource())); checkToSeeIfSlicingExists(diffMatches.get(0), template); @@ -866,13 +866,13 @@ public class ProfilePathProcessor { private void processSimplePathWithEmptyDiffMatches(ElementDefinition currentBase, String currentBasePath, List diffMatches, ProfilePathProcessorState cursors, MappingAssistant mapHelper) { - ElementDefinition outcome = profileUtilities.updateURLs(getUrl(), getWebUrl(), currentBase.copy()); + ElementDefinition outcome = profileUtilities.updateURLs(getUrl(), getWebUrl(), currentBase.copy(), true); outcome.setPath(profileUtilities.fixedPathDest(getContextPathTarget(), outcome.getPath(), getRedirector(), getContextPathSource())); profileUtilities.updateFromBase(outcome, currentBase, getSourceStructureDefinition().getUrl()); profileUtilities.updateConstraintSources(outcome, getSourceStructureDefinition().getUrl()); profileUtilities.checkExtensions(outcome); profileUtilities.updateFromObligationProfiles(outcome); - profileUtilities.updateURLs(url, webUrl, outcome); + profileUtilities.updateURLs(url, webUrl, outcome, true); profileUtilities.markDerived(outcome); if (cursors.resultPathBase == null) cursors.resultPathBase = outcome.getPath(); @@ -1033,7 +1033,7 @@ public class ProfilePathProcessor { if (!currentBase.isChoice() && !profileUtilities.ruleMatches(dSlice.getRules(), bSlice.getRules())) throw new DefinitionException(profileUtilities.getContext().formatMessage(I18nConstants.SLICING_RULES_ON_DIFFERENTIAL__DO_NOT_MATCH_THOSE_ON_BASE___RULE___, profileUtilities.summarizeSlicing(dSlice), profileUtilities.summarizeSlicing(bSlice), path, cursors.contextName)); } - ElementDefinition outcome = profileUtilities.updateURLs(getUrl(), getWebUrl(), currentBase.copy()); + ElementDefinition outcome = profileUtilities.updateURLs(getUrl(), getWebUrl(), currentBase.copy(), true); outcome.setPath(profileUtilities.fixedPathDest(getContextPathTarget(), outcome.getPath(), getRedirector(), getContextPathSource())); profileUtilities.updateFromBase(outcome, currentBase, getSourceStructureDefinition().getUrl()); if (diffMatches.get(0).hasSlicing() || !diffMatches.get(0).hasSliceName()) { @@ -1095,7 +1095,7 @@ public class ProfilePathProcessor { // We need to copy children of the backbone element before we start messing around with slices int newBaseLimit = profileUtilities.findEndOfElement(cursors.base, cursors.baseCursor); for (int i = cursors.baseCursor + 1; i <= newBaseLimit; i++) { - outcome = profileUtilities.updateURLs(getUrl(), getWebUrl(), cursors.base.getElement().get(i).copy()); + outcome = profileUtilities.updateURLs(getUrl(), getWebUrl(), cursors.base.getElement().get(i).copy(), true); outcome.setPath(profileUtilities.fixedPathDest(getContextPathTarget(), outcome.getPath(), getRedirector(), getContextPathSource())); debugCheck(outcome); getResult().getElement().add(outcome); @@ -1106,7 +1106,7 @@ public class ProfilePathProcessor { List baseMatches = profileUtilities.getSiblings(cursors.base.getElement(), currentBase); for (ElementDefinition baseItem : baseMatches) { cursors.baseCursor = cursors.base.getElement().indexOf(baseItem); - outcome = profileUtilities.updateURLs(getUrl(), getWebUrl(), baseItem.copy()); + outcome = profileUtilities.updateURLs(getUrl(), getWebUrl(), baseItem.copy(), true); profileUtilities.updateFromBase(outcome, currentBase, getSourceStructureDefinition().getUrl()); outcome.setPath(profileUtilities.fixedPathDest(getContextPathTarget(), outcome.getPath(), getRedirector(), getContextPathSource())); outcome.setSlicing(null); @@ -1139,7 +1139,7 @@ public class ProfilePathProcessor { cursors.baseCursor++; // just copy any children on the base while (cursors.baseCursor < cursors.base.getElement().size() && cursors.base.getElement().get(cursors.baseCursor).getPath().startsWith(path) && !cursors.base.getElement().get(cursors.baseCursor).getPath().equals(path)) { - outcome = profileUtilities.updateURLs(getUrl(), getWebUrl(), cursors.base.getElement().get(cursors.baseCursor).copy()); + outcome = profileUtilities.updateURLs(getUrl(), getWebUrl(), cursors.base.getElement().get(cursors.baseCursor).copy(), true); outcome.setPath(profileUtilities.fixedPathDest(getContextPathTarget(), outcome.getPath(), getRedirector(), getContextPathSource())); if (!outcome.getPath().startsWith(cursors.resultPathBase)) throw new DefinitionException(profileUtilities.getContext().formatMessage(I18nConstants.ADDING_WRONG_PATH)); @@ -1166,7 +1166,7 @@ public class ProfilePathProcessor { for (ElementDefinition baseItem : baseMatches) if (baseItem.getSliceName().equals(diffItem.getSliceName())) throw new DefinitionException(profileUtilities.getContext().formatMessage(I18nConstants.NAMED_ITEMS_ARE_OUT_OF_ORDER_IN_THE_SLICE)); - outcome = profileUtilities.updateURLs(getUrl(), getWebUrl(), currentBase.copy()); + outcome = profileUtilities.updateURLs(getUrl(), getWebUrl(), currentBase.copy(), true); // outcome = updateURLs(url, diffItem.copy()); outcome.setPath(profileUtilities.fixedPathDest(getContextPathTarget(), outcome.getPath(), getRedirector(), getContextPathSource())); profileUtilities.updateFromBase(outcome, currentBase, getSourceStructureDefinition().getUrl()); @@ -1409,7 +1409,7 @@ public class ProfilePathProcessor { private void processPathWithSlicedBaseAndEmptyDiffMatches(ElementDefinition currentBase, String currentBasePath, List diffMatches, ProfilePathProcessorState cursors, String path, MappingAssistant mapHelper) { if (profileUtilities.hasInnerDiffMatches(getDifferential(), path, cursors.diffCursor, getDiffLimit(), cursors.base.getElement(), true)) { // so we just copy it in - ElementDefinition outcome = profileUtilities.updateURLs(getUrl(), getWebUrl(), currentBase.copy()); + ElementDefinition outcome = profileUtilities.updateURLs(getUrl(), getWebUrl(), currentBase.copy(), true); outcome.setPath(profileUtilities.fixedPathDest(getContextPathTarget(), outcome.getPath(), getRedirector(), getContextPathSource())); profileUtilities.updateFromBase(outcome, currentBase, getSourceStructureDefinition().getUrl()); profileUtilities.markDerived(outcome); @@ -1457,7 +1457,7 @@ public class ProfilePathProcessor { // the differential doesn't say anything about this item // copy across the currentbase, and all of its children and siblings while (cursors.baseCursor < cursors.base.getElement().size() && cursors.base.getElement().get(cursors.baseCursor).getPath().startsWith(path)) { - ElementDefinition outcome = profileUtilities.updateURLs(getUrl(), getWebUrl(), cursors.base.getElement().get(cursors.baseCursor).copy()); + ElementDefinition outcome = profileUtilities.updateURLs(getUrl(), getWebUrl(), cursors.base.getElement().get(cursors.baseCursor).copy(), true); outcome.setPath(profileUtilities.fixedPathDest(getContextPathTarget(), outcome.getPath(), getRedirector(), getContextPathSource())); if (!outcome.getPath().startsWith(cursors.resultPathBase)) throw new DefinitionException(profileUtilities.getContext().formatMessage(I18nConstants.ADDING_WRONG_PATH_IN_PROFILE___VS_, getProfileName(), outcome.getPath(), cursors.resultPathBase)); diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/profile/ProfileUtilities.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/profile/ProfileUtilities.java index 468430552..bc8d243a2 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/profile/ProfileUtilities.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/profile/ProfileUtilities.java @@ -413,11 +413,10 @@ public class ProfileUtilities { // note that ProfileUtilities are used re-entrantly internally, so nothing with process state can be here private final IWorkerContext context; private FHIRPathEngine fpe; - private List messages; + private List messages = new ArrayList(); private List snapshotStack = new ArrayList(); private ProfileKnowledgeProvider pkp; // private boolean igmode; - private boolean exception; private ValidationOptions terminologyServiceOptions = new ValidationOptions(FhirPublication.R5); private boolean newSlicingProcessing; private String defWebRoot; @@ -431,11 +430,16 @@ public class ProfileUtilities { private MappingMergeModeOption mappingMergeMode = MappingMergeModeOption.APPEND; private boolean forPublication; private List obligationProfiles = new ArrayList<>(); + private boolean wantThrowExceptions; public ProfileUtilities(IWorkerContext context, List messages, ProfileKnowledgeProvider pkp, FHIRPathEngine fpe) { super(); this.context = context; - this.messages = messages; + if (messages != null) { + this.messages = messages; + } else { + wantThrowExceptions = true; + } this.pkp = pkp; this.fpe = fpe; @@ -447,7 +451,11 @@ public class ProfileUtilities { public ProfileUtilities(IWorkerContext context, List messages, ProfileKnowledgeProvider pkp) { super(); this.context = context; - this.messages = messages; + if (messages != null) { + this.messages = messages; + } else { + wantThrowExceptions = true; + } this.pkp = pkp; if (context != null) { this.fpe = new FHIRPathEngine(context, this); @@ -739,7 +747,7 @@ public class ProfileUtilities { if (existing != null) { updateFromDefinition(existing, e, profileName, false, url, base, derived, "StructureDefinition.differential.element["+i+"]", mappingDetails); } else { - ElementDefinition outcome = updateURLs(url, webUrl, e.copy()); + ElementDefinition outcome = updateURLs(url, webUrl, e.copy(), true); e.setUserData(UD_GENERATED_IN_SNAPSHOT, outcome); derived.getSnapshot().addElement(outcome); if (walksInto(diff.getElement(), e)) { @@ -789,7 +797,7 @@ public class ProfileUtilities { ce++; if (e.hasId()) { String msg = "No match found for "+e.getId()+" in the generated snapshot: check that the path and definitions are legal in the differential (including order)"; - messages.add(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.VALUE, "StructureDefinition.differential.element["+i+"]", msg, ValidationMessage.IssueSeverity.ERROR)); + addMessage(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.VALUE, "StructureDefinition.differential.element["+i+"]", msg, ValidationMessage.IssueSeverity.ERROR)); } } i++; @@ -862,19 +870,19 @@ public class ProfileUtilities { slice.getFocus().setMin(count); } else { String msg = "The slice definition for "+slice.getFocus().getId()+" has a minimum of "+slice.getFocus().getMin()+" but the slices add up to a minimum of "+count; - messages.add(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.VALUE, + addMessage(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.VALUE, "StructureDefinition.snapshot.element["+slice.getIndex()+"]", msg, forPublication ? ValidationMessage.IssueSeverity.ERROR : ValidationMessage.IssueSeverity.INFORMATION).setIgnorableError(true)); } } count = slice.checkMax(); if (count > -1 && repeats) { String msg = "The slice definition for "+slice.getFocus().getId()+" has a maximum of "+slice.getFocus().getMax()+" but the slices add up to a maximum of "+count+". Check that this is what is intended"; - messages.add(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.VALUE, + addMessage(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.VALUE, "StructureDefinition.snapshot.element["+slice.getIndex()+"]", msg, ValidationMessage.IssueSeverity.INFORMATION)); } if (!slice.checkMinMax()) { String msg = "The slice definition for "+slice.getFocus().getId()+" has a maximum of "+slice.getFocus().getMax()+" which is less than the minimum of "+slice.getFocus().getMin(); - messages.add(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.VALUE, + addMessage(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.VALUE, "StructureDefinition.snapshot.element["+slice.getIndex()+"]", msg, ValidationMessage.IssueSeverity.WARNING)); } slices.remove(s); @@ -885,13 +893,13 @@ public class ProfileUtilities { } if (ed.hasSliceName() && !slices.containsKey(ed.getPath())) { String msg = "The element "+ed.getId()+" launches straight into slicing without the slicing being set up properly first"; - messages.add(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.VALUE, + addMessage(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.VALUE, "StructureDefinition.snapshot.element["+i+"]", msg, ValidationMessage.IssueSeverity.ERROR).setIgnorableError(true)); } if (ed.hasSliceName() && slices.containsKey(ed.getPath())) { if (!slices.get(ed.getPath()).count(ed, ed.getSliceName())) { String msg = "Duplicate slice name "+ed.getSliceName()+" on "+ed.getId()+" (["+i+"])"; - messages.add(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.VALUE, + addMessage(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.VALUE, "StructureDefinition.snapshot.element["+i+"]", msg, ValidationMessage.IssueSeverity.ERROR).setIgnorableError(true)); } } @@ -910,10 +918,8 @@ public class ProfileUtilities { } } if (sd == null) { - if (messages != null) { - messages.add(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.VALUE, + addMessage(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.VALUE, "StructureDefinition.snapshot.element["+i+"]", "The type of profile "+u.getValue()+" cannot be checked as the profile is not known", IssueSeverity.WARNING)); - } } else { String wt = t.getWorkingCode(); if (ed.getPath().equals("Bundle.entry.response.outcome")) { @@ -1012,13 +1018,15 @@ public class ProfileUtilities { } private void handleError(String url, String msg) { - if (exception) - throw new DefinitionException(msg); - else - messages.add(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.VALUE, url, msg, ValidationMessage.IssueSeverity.ERROR)); + addMessage(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.VALUE, url, msg, ValidationMessage.IssueSeverity.ERROR)); } - + private void addMessage(ValidationMessage msg) { + messages.add(msg); + if (msg.getLevel() == IssueSeverity.ERROR && wantThrowExceptions) { + throw new DefinitionException(msg.getMessage()); + } + } private void copyInheritedExtensions(StructureDefinition base, StructureDefinition derived, String webUrl) { @@ -1042,7 +1050,7 @@ public class ProfileUtilities { // don't do this. should already be in snapshot ... addInheritedElementsForSpecialization(snapshot, focus, sd.getBaseDefinition(), path, url, weburl); for (ElementDefinition ed : sd.getSnapshot().getElement()) { if (ed.getPath().contains(".")) { - ElementDefinition outcome = updateURLs(url, weburl, ed.copy()); + ElementDefinition outcome = updateURLs(url, weburl, ed.copy(), true); outcome.setPath(outcome.getPath().replace(sd.getTypeName(), path)); snapshot.getElement().add(outcome); } else { @@ -1548,7 +1556,6 @@ public class ProfileUtilities { protected void removeStatusExtensions(ElementDefinition outcome) { outcome.removeExtension(ToolingExtensions.EXT_FMM_LEVEL); outcome.removeExtension(ToolingExtensions.EXT_FMM_SUPPORT); - outcome.removeExtension(ToolingExtensions.EXT_FMM_DERIVED); outcome.removeExtension(ToolingExtensions.EXT_STANDARDS_STATUS); outcome.removeExtension(ToolingExtensions.EXT_NORMATIVE_VERSION); outcome.removeExtension(ToolingExtensions.EXT_WORKGROUP); @@ -1911,7 +1918,7 @@ public class ProfileUtilities { * @param element - the Element to update * @return - the updated Element */ - public ElementDefinition updateURLs(String url, String webUrl, ElementDefinition element) { + public ElementDefinition updateURLs(String url, String webUrl, ElementDefinition element, boolean processRelatives) { if (element != null) { ElementDefinition defn = element; if (defn.hasBinding() && defn.getBinding().hasValueSet() && defn.getBinding().getValueSet().startsWith("#")) @@ -1929,24 +1936,24 @@ public class ProfileUtilities { if (webUrl != null) { // also, must touch up the markdown if (element.hasDefinition()) { - element.setDefinition(processRelativeUrls(element.getDefinition(), webUrl, context.getSpecUrl(), context.getResourceNames(), masterSourceFileNames, localFileNames, false)); + element.setDefinition(processRelativeUrls(element.getDefinition(), webUrl, context.getSpecUrl(), context.getResourceNames(), masterSourceFileNames, localFileNames, processRelatives)); } if (element.hasComment()) { - element.setComment(processRelativeUrls(element.getComment(), webUrl, context.getSpecUrl(), context.getResourceNames(), masterSourceFileNames, localFileNames, false)); + element.setComment(processRelativeUrls(element.getComment(), webUrl, context.getSpecUrl(), context.getResourceNames(), masterSourceFileNames, localFileNames, processRelatives)); } if (element.hasRequirements()) { - element.setRequirements(processRelativeUrls(element.getRequirements(), webUrl, context.getSpecUrl(), context.getResourceNames(), masterSourceFileNames, localFileNames, false)); + element.setRequirements(processRelativeUrls(element.getRequirements(), webUrl, context.getSpecUrl(), context.getResourceNames(), masterSourceFileNames, localFileNames, processRelatives)); } if (element.hasMeaningWhenMissing()) { - element.setMeaningWhenMissing(processRelativeUrls(element.getMeaningWhenMissing(), webUrl, context.getSpecUrl(), context.getResourceNames(), masterSourceFileNames, localFileNames, false)); + element.setMeaningWhenMissing(processRelativeUrls(element.getMeaningWhenMissing(), webUrl, context.getSpecUrl(), context.getResourceNames(), masterSourceFileNames, localFileNames, processRelatives)); } if (element.hasBinding() && element.getBinding().hasDescription()) { - element.getBinding().setDescription(processRelativeUrls(element.getBinding().getDescription(), webUrl, context.getSpecUrl(), context.getResourceNames(), masterSourceFileNames, localFileNames, false)); + element.getBinding().setDescription(processRelativeUrls(element.getBinding().getDescription(), webUrl, context.getSpecUrl(), context.getResourceNames(), masterSourceFileNames, localFileNames, processRelatives)); } for (Extension ext : element.getExtension()) { if (ext.hasValueMarkdownType()) { MarkdownType md = ext.getValueMarkdownType(); - md.setValue(processRelativeUrls(md.getValue(), webUrl, context.getSpecUrl(), context.getResourceNames(), masterSourceFileNames, localFileNames, false)); + md.setValue(processRelativeUrls(md.getValue(), webUrl, context.getSpecUrl(), context.getResourceNames(), masterSourceFileNames, localFileNames, processRelatives)); } } } @@ -2250,7 +2257,7 @@ public class ProfileUtilities { * Not sure we have enough information here to do the check properly. Might be better done when we're sorting the profile? if (i != start && result.isEmpty() && !path.startsWith(context.getElement().get(start).getPath())) - messages.add(new ValidationMessage(Source.ProfileValidator, IssueType.VALUE, "StructureDefinition.differential.element["+Integer.toString(start)+"]", "Error: unknown element '"+context.getElement().get(start).getPath()+"' (or it is out of order) in profile '"+url+"' (looking for '"+path+"')", IssueSeverity.WARNING)); + addMessage(new ValidationMessage(Source.ProfileValidator, IssueType.VALUE, "StructureDefinition.differential.element["+Integer.toString(start)+"]", "Error: unknown element '"+context.getElement().get(start).getPath()+"' (or it is out of order) in profile '"+url+"' (looking for '"+path+"')", IssueSeverity.WARNING)); */ result.add(context.getElement().get(i)); @@ -2371,7 +2378,6 @@ public class ProfileUtilities { if (elist.size() == 2) { dest.getExtension().remove(elist.get(1)); } - updateExtensionsFromDefinition(dest, source); for (ElementDefinition ed : obligationProfileElements) { @@ -2423,6 +2429,9 @@ public class ProfileUtilities { if (e.hasDefinition()) { base.setDefinition(processRelativeUrls(e.getDefinition(), webroot, context.getSpecUrl(), context.getResourceNames(), masterSourceFileNames, localFileNames, true)); } + if (e.getBinding().hasDescription()) { + base.getBinding().setDescription(processRelativeUrls(e.getBinding().getDescription(), webroot, context.getSpecUrl(), context.getResourceNames(), masterSourceFileNames, localFileNames, true)); + } base.setShort(e.getShort()); if (e.hasCommentElement()) base.setCommentElement(e.getCommentElement()); @@ -2466,9 +2475,9 @@ public class ProfileUtilities { if (derived.hasDefinitionElement()) { if (derived.getDefinition().startsWith("...")) base.setDefinition(Utilities.appendDerivedTextToBase(base.getDefinition(), derived.getDefinition())); - else if (!Base.compareDeep(derived.getDefinitionElement(), base.getDefinitionElement(), false)) + else if (!Base.compareDeep(derived.getDefinitionElement(), base.getDefinitionElement(), false)) { base.setDefinitionElement(derived.getDefinitionElement().copy()); - else if (trimDifferential) + } else if (trimDifferential) derived.setDefinitionElement(null); else if (derived.hasDefinitionElement()) derived.getDefinitionElement().setUserData(UD_DERIVATION_EQUALS, true); @@ -2528,7 +2537,7 @@ public class ProfileUtilities { if (derived.hasMinElement()) { if (!Base.compareDeep(derived.getMinElement(), base.getMinElement(), false)) { if (derived.getMin() < base.getMin() && !derived.hasSliceName()) // in a slice, minimum cardinality rules do not apply - messages.add(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.BUSINESSRULE, pn+"."+source.getPath(), "Element "+base.getPath()+": derived min ("+Integer.toString(derived.getMin())+") cannot be less than the base min ("+Integer.toString(base.getMin())+") in "+srcSD.getVersionedUrl(), ValidationMessage.IssueSeverity.ERROR)); + addMessage(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.BUSINESSRULE, pn+"."+source.getPath(), "Element "+base.getPath()+": derived min ("+Integer.toString(derived.getMin())+") cannot be less than the base min ("+Integer.toString(base.getMin())+") in "+srcSD.getVersionedUrl(), ValidationMessage.IssueSeverity.ERROR)); base.setMinElement(derived.getMinElement().copy()); } else if (trimDifferential) derived.setMinElement(null); @@ -2539,7 +2548,7 @@ public class ProfileUtilities { if (derived.hasMaxElement()) { if (!Base.compareDeep(derived.getMaxElement(), base.getMaxElement(), false)) { if (isLargerMax(derived.getMax(), base.getMax())) - messages.add(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.BUSINESSRULE, pn+"."+source.getPath(), "Element "+base.getPath()+": derived max ("+derived.getMax()+") cannot be greater than the base max ("+base.getMax()+")", ValidationMessage.IssueSeverity.ERROR)); + addMessage(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.BUSINESSRULE, pn+"."+source.getPath(), "Element "+base.getPath()+": derived max ("+derived.getMax()+") cannot be greater than the base max ("+base.getMax()+")", ValidationMessage.IssueSeverity.ERROR)); base.setMaxElement(derived.getMaxElement().copy()); } else if (trimDifferential) derived.setMaxElement(null); @@ -2641,7 +2650,7 @@ public class ProfileUtilities { } if (!(base.hasMustSupportElement() && Base.compareDeep(base.getMustSupportElement(), mse, false))) { if (base.hasMustSupport() && base.getMustSupport() && !derived.getMustSupport()) { - messages.add(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.BUSINESSRULE, pn+"."+derived.getPath(), "Illegal constraint [must-support = false] when [must-support = true] in the base profile", ValidationMessage.IssueSeverity.ERROR)); + addMessage(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.BUSINESSRULE, pn+"."+derived.getPath(), "Illegal constraint [must-support = false] when [must-support = true] in the base profile", ValidationMessage.IssueSeverity.ERROR)); } base.setMustSupportElement(mse); } else if (trimDifferential) @@ -2653,7 +2662,7 @@ public class ProfileUtilities { if (derived.hasMustHaveValueElement()) { if (!(base.hasMustHaveValueElement() && Base.compareDeep(derived.getMustHaveValueElement(), base.getMustHaveValueElement(), false))) { if (base.hasMustHaveValue() && base.getMustHaveValue() && !derived.getMustHaveValue()) { - messages.add(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.BUSINESSRULE, pn+"."+derived.getPath(), "Illegal constraint [must-have-value = false] when [must-have-value = true] in the base profile", ValidationMessage.IssueSeverity.ERROR)); + addMessage(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.BUSINESSRULE, pn+"."+derived.getPath(), "Illegal constraint [must-have-value = false] when [must-have-value = true] in the base profile", ValidationMessage.IssueSeverity.ERROR)); } base.setMustHaveValueElement(derived.getMustHaveValueElement().copy()); } else if (trimDifferential) @@ -2720,25 +2729,25 @@ public class ProfileUtilities { if (!base.hasBinding() || !Base.compareDeep(derived.getBinding(), base.getBinding(), false)) { if (base.hasBinding() && base.getBinding().getStrength() == BindingStrength.REQUIRED && derived.getBinding().getStrength() != BindingStrength.REQUIRED) - messages.add(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.BUSINESSRULE, pn+"."+derived.getPath(), "illegal attempt to change the binding on "+derived.getPath()+" from "+base.getBinding().getStrength().toCode()+" to "+derived.getBinding().getStrength().toCode(), ValidationMessage.IssueSeverity.ERROR)); + addMessage(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.BUSINESSRULE, pn+"."+derived.getPath(), "illegal attempt to change the binding on "+derived.getPath()+" from "+base.getBinding().getStrength().toCode()+" to "+derived.getBinding().getStrength().toCode(), ValidationMessage.IssueSeverity.ERROR)); // throw new DefinitionException("StructureDefinition "+pn+" at "+derived.getPath()+": illegal attempt to change a binding from "+base.getBinding().getStrength().toCode()+" to "+derived.getBinding().getStrength().toCode()); else if (base.hasBinding() && derived.hasBinding() && base.getBinding().getStrength() == BindingStrength.REQUIRED && base.getBinding().hasValueSet() && derived.getBinding().hasValueSet()) { ValueSet baseVs = context.findTxResource(ValueSet.class, base.getBinding().getValueSet(), srcSD); ValueSet contextVs = context.findTxResource(ValueSet.class, derived.getBinding().getValueSet(), derivedSrc); if (baseVs == null) { - messages.add(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.BUSINESSRULE, pn+"."+base.getPath(), "Binding "+base.getBinding().getValueSet()+" could not be located", ValidationMessage.IssueSeverity.WARNING)); + addMessage(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.BUSINESSRULE, pn+"."+base.getPath(), "Binding "+base.getBinding().getValueSet()+" could not be located", ValidationMessage.IssueSeverity.WARNING)); } else if (contextVs == null) { - messages.add(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.BUSINESSRULE, pn+"."+derived.getPath(), "Binding "+derived.getBinding().getValueSet()+" could not be located", ValidationMessage.IssueSeverity.WARNING)); + addMessage(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.BUSINESSRULE, pn+"."+derived.getPath(), "Binding "+derived.getBinding().getValueSet()+" could not be located", ValidationMessage.IssueSeverity.WARNING)); } else { ValueSetExpansionOutcome expBase = context.expandVS(baseVs, true, false); ValueSetExpansionOutcome expDerived = context.expandVS(contextVs, true, false); if (expBase.getValueset() == null) - messages.add(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.BUSINESSRULE, pn+"."+base.getPath(), "Binding "+base.getBinding().getValueSet()+" could not be expanded", ValidationMessage.IssueSeverity.WARNING)); + addMessage(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)); + addMessage(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)) { 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)); + addMessage(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()) { @@ -2749,11 +2758,11 @@ public class ProfileUtilities { } } 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)); + addMessage(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)); + addMessage(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)); } } ElementDefinitionBindingComponent d = derived.getBinding(); @@ -2964,11 +2973,7 @@ public class ProfileUtilities { if (tgtOk) { ok = true; } else { - if (messages == null) { - throw new FHIRException(context.formatMessage(I18nConstants.ERROR_AT__THE_TARGET_PROFILE__IS_NOT__VALID_CONSTRAINT_ON_THE_BASE_, purl, derived.getPath(), url, td.getTargetProfile())); - } else { - messages.add(new ValidationMessage(Source.InstanceValidator, IssueType.BUSINESSRULE, derived.getPath(), "The target profile " + u.getValue() + " is not a valid constraint on the base (" + td.getTargetProfile() + ") at " + derived.getPath(), IssueSeverity.ERROR)); - } + addMessage(new ValidationMessage(Source.InstanceValidator, IssueType.BUSINESSRULE, derived.getPath(), context.formatMessage(I18nConstants.ERROR_AT__THE_TARGET_PROFILE__IS_NOT__VALID_CONSTRAINT_ON_THE_BASE_, purl, derived.getPath(), url, td.getTargetProfile()), IssueSeverity.ERROR)); } } } else { @@ -2988,9 +2993,7 @@ public class ProfileUtilities { } StructureDefinition sd = context.fetchResource(StructureDefinition.class, url); if (sd == null) { - if (messages != null) { - messages.add(new ValidationMessage(Source.InstanceValidator, IssueType.BUSINESSRULE, path, "Cannot check whether the target profile " + url + " on "+dPath+" is valid constraint on the base because it is not known", IssueSeverity.WARNING)); - } + addMessage(new ValidationMessage(Source.InstanceValidator, IssueType.BUSINESSRULE, path, "Cannot check whether the target profile " + url + " on "+dPath+" is valid constraint on the base because it is not known", IssueSeverity.WARNING)); return true; } else { if (sd.hasBaseDefinition() && sdConformsToTargets(path, dPath, sd.getBaseDefinition(), td)) { @@ -3021,7 +3024,7 @@ public class ProfileUtilities { } if (!ok) { - messages.add(new ValidationMessage(Source.InstanceValidator, IssueType.CONFLICT, dest.getId(), "The "+fieldName+" value has type '"+ft+"' which is not valid (valid "+Utilities.pluralize("type", dest.getType().size())+": "+types.toString()+")", IssueSeverity.ERROR)); + addMessage(new ValidationMessage(Source.InstanceValidator, IssueType.CONFLICT, dest.getId(), "The "+fieldName+" value has type '"+ft+"' which is not valid (valid "+Utilities.pluralize("type", dest.getType().size())+": "+types.toString()+")", IssueSeverity.ERROR)); } } @@ -3463,6 +3466,11 @@ public class ProfileUtilities { public void sortDifferential(StructureDefinition base, StructureDefinition diff, String name, List errors, boolean errorIfChanges) throws FHIRException { + int index = 0; + for (ElementDefinition ed : diff.getDifferential().getElement()) { + ed.setUserData("ed.index", Integer.toString(index)); + index++; + } List original = new ArrayList<>(); original.addAll(diff.getDifferential().getElement()); final List diffList = diff.getDifferential().getElement(); @@ -3520,7 +3528,7 @@ public class ProfileUtilities { ElementDefinition e = diffList.get(i); ElementDefinition n = newDiff.get(i); if (!n.getPath().equals(e.getPath())) { - errors.add("The element "+e.getPath()+" is out of order (and maybe others after it)"); + errors.add("The element "+(e.hasId() ? e.getId() : e.getPath())+" @diff["+e.getUserString("ed.index")+"] is out of order (and maybe others after it)"); return; } } @@ -3930,10 +3938,7 @@ public class ProfileUtilities { } ed.setId(bs); if (idList.containsKey(bs)) { - if (exception || messages == null) { - throw new DefinitionException(context.formatMessage(I18nConstants.SAME_ID_ON_MULTIPLE_ELEMENTS__IN_, bs, idList.get(bs), ed.getPath(), name)); - } else - messages.add(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.BUSINESSRULE, name+"."+bs, "Duplicate Element id "+bs, ValidationMessage.IssueSeverity.ERROR)); + addMessage(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.BUSINESSRULE, name+"."+bs, context.formatMessage(I18nConstants.SAME_ID_ON_MULTIPLE_ELEMENTS__IN_, bs, idList.get(bs), ed.getPath(), name), ValidationMessage.IssueSeverity.ERROR)); } idList.put(bs, ed.getPath()); if (ed.hasContentReference() && ed.getContentReference().startsWith("#")) { @@ -4309,12 +4314,12 @@ public class ProfileUtilities { public boolean isThrowException() { - return exception; + return wantThrowExceptions; } public void setThrowException(boolean exception) { - this.exception = exception; + this.wantThrowExceptions = exception; } @@ -4572,7 +4577,9 @@ public class ProfileUtilities { } public void setMessages(List messages) { - this.messages = messages; + if (messages != null) { + this.messages = messages; + } } private Map> propertyCache = new HashMap<>(); diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/BaseWorkerContext.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/BaseWorkerContext.java index e517398be..e33cc0bfa 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/BaseWorkerContext.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/BaseWorkerContext.java @@ -934,10 +934,14 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte throw new Error(formatMessage(I18nConstants.NO_VALUE_SET_IN_URL)); } for (ConceptSetComponent inc : vs.getCompose().getInclude()) { - codeSystemsUsed.add(inc.getSystem()); + if (inc.hasSystem()) { + codeSystemsUsed.add(inc.getSystem()); + } } for (ConceptSetComponent inc : vs.getCompose().getExclude()) { - codeSystemsUsed.add(inc.getSystem()); + if (inc.hasSystem()) { + codeSystemsUsed.add(inc.getSystem()); + } } CacheToken cacheToken = txCache.generateExpandToken(vs, hierarchical); diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/ContextUtilities.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/ContextUtilities.java index 02890a037..12bc847a2 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/ContextUtilities.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/ContextUtilities.java @@ -366,7 +366,11 @@ public class ContextUtilities implements ProfileKnowledgeProvider { public StructureDefinition fetchByJsonName(String key) { for (StructureDefinition sd : context.fetchResourcesByType(StructureDefinition.class)) { ElementDefinition ed = sd.getSnapshot().getElementFirstRep(); - if (sd.getKind() == StructureDefinitionKind.LOGICAL && ed != null && ed.hasExtension(ToolingExtensions.EXT_JSON_NAME, ToolingExtensions.EXT_JSON_NAME_DEPRECATED) && + if (/*sd.getKind() == StructureDefinitionKind.LOGICAL && */ + // this is turned off because it's valid to use a FHIR type directly in + // an extension of this kind, and that can't be a logical model. Any profile on + // a type is acceptable as long as it has the json name on it + ed != null && ed.hasExtension(ToolingExtensions.EXT_JSON_NAME, ToolingExtensions.EXT_JSON_NAME_DEPRECATED) && key.equals(ToolingExtensions.readStringExtension(ed, ToolingExtensions.EXT_JSON_NAME, ToolingExtensions.EXT_JSON_NAME_DEPRECATED))) { return sd; } diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/LanguageUtils.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/LanguageUtils.java index fa957c861..59598312c 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/LanguageUtils.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/LanguageUtils.java @@ -166,7 +166,9 @@ public class LanguageUtils { } for (TranslationUnit t : translations) { if (!usedUnits.contains(t)) { - messages.add(new ValidationMessage(Source.Publisher, IssueType.INFORMATIONAL, t.getId(), "Unused '"+t.getLanguage()+"' translation '"+t.getSrcText()+"' -> '"+t.getTgtText()+"'", IssueSeverity.INFORMATION)); + if (messages != null) { + messages.add(new ValidationMessage(Source.Publisher, IssueType.INFORMATIONAL, t.getId(), "Unused '"+t.getLanguage()+"' translation '"+t.getSrcText()+"' -> '"+t.getTgtText()+"'", IssueSeverity.INFORMATION)); + } } } return r; @@ -182,7 +184,9 @@ public class LanguageUtils { } for (TranslationUnit t : translations) { if (!usedUnits.contains(t)) { - messages.add(new ValidationMessage(Source.Publisher, IssueType.INFORMATIONAL, t.getId(), "Unused '"+t.getLanguage()+"' translation '"+t.getSrcText()+"' -> '"+t.getTgtText()+"'", IssueSeverity.INFORMATION)); + if (messages != null) { + messages.add(new ValidationMessage(Source.Publisher, IssueType.INFORMATIONAL, t.getId(), "Unused '"+t.getLanguage()+"' translation '"+t.getSrcText()+"' -> '"+t.getTgtText()+"'", IssueSeverity.INFORMATION)); + } } } return r; @@ -296,7 +300,9 @@ public class LanguageUtils { } } } - for (Element c : element.getChildren()) { + // Create a copy of the children collection before iterating + List childrenCopy = List.copyOf(element.getChildren()); + for (Element c : childrenCopy) { if (!c.getName().equals("designation")) { t = t + importFromTranslations(element, c, translations, usedUnits); } diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/fhirpath/FHIRLexer.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/fhirpath/FHIRLexer.java index b0d101cdc..080600c69 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/fhirpath/FHIRLexer.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/fhirpath/FHIRLexer.java @@ -187,7 +187,7 @@ public class FHIRLexer { cursor++; } else while (cursor < source.length() && ((source.charAt(cursor) >= 'A' && source.charAt(cursor) <= 'Z') || (source.charAt(cursor) >= 'a' && source.charAt(cursor) <= 'z') || - (source.charAt(cursor) >= '0' && source.charAt(cursor) <= '9') || source.charAt(cursor) == ':' || source.charAt(cursor) == '-')) + (source.charAt(cursor) >= '0' && source.charAt(cursor) <= '9') || source.charAt(cursor) == ':' || source.charAt(cursor) == '-' || source.charAt(cursor) == '_')) cursor++; current = source.substring(currentStart, cursor); } else if (ch == '/') { diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/fhirpath/FHIRPathEngine.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/fhirpath/FHIRPathEngine.java index 5d1efdcec..7a63e0c59 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/fhirpath/FHIRPathEngine.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/fhirpath/FHIRPathEngine.java @@ -773,6 +773,25 @@ public class FHIRPathEngine { return execute(new ExecutionContext(null, base != null && base.isResource() ? base : null, base != null && base.isResource() ? base : null, base, base), list, ExpressionNode, true); } + + /** + * evaluate a path and return the matching elements + * + * @param base - the object against which the path is being evaluated + * @param ExpressionNode - the parsed ExpressionNode statement to use + * @return + * @throws FHIRException + * @ + */ + public List evaluate(Object appContext, Base base, ExpressionNode ExpressionNode) throws FHIRException { + List list = new ArrayList(); + if (base != null) { + list.add(base); + } + log = new StringBuilder(); + return execute(new ExecutionContext(appContext, base != null && base.isResource() ? base : null, base != null && base.isResource() ? base : null, base, base), list, ExpressionNode, true); + } + /** * evaluate a path and return the matching elements * @@ -3741,6 +3760,8 @@ public class FHIRPathEngine { } if ((focus.hasType("date") || focus.hasType("datetime") || focus.hasType("instant"))) { return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Decimal, TypeDetails.FP_DateTime); + } else if ((focus.hasType("time"))) { + return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Time, TypeDetails.FP_Time); } else if (focus.hasType("decimal") || focus.hasType("integer")) { return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Decimal); } else { @@ -6351,7 +6372,7 @@ public class FHIRPathEngine { } result.addTypes(worker.getResourceNames()); } else { - pt = new ProfiledType(t.getCode()); + pt = new ProfiledType(t.getWorkingCode()); } if (pt != null) { if (t.hasProfile()) { diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/StructureDefinitionRenderer.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/StructureDefinitionRenderer.java index e2276d692..5e7b63d20 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/StructureDefinitionRenderer.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/StructureDefinitionRenderer.java @@ -897,7 +897,7 @@ public class StructureDefinitionRenderer extends ResourceRenderer { Row parent = null; if (child.hasSliceName()) { // ok, we're a slice - if (slicer == null || !slicer.getId().equals(child.getPath())) { + if (slicer == null || !noTail(slicer.getId()).equals(child.getPath())) { parent = gen.new Row(); String anchorE = child.getPath(); anchorE = makeAnchorUnique(anchorE); @@ -906,7 +906,7 @@ public class StructureDefinitionRenderer extends ResourceRenderer { parent.setColor(context.getProfileUtilities().getRowColor(child, isConstraintMode)); parent.setLineColor(1); parent.setIcon("icon_slice.png", context.formatPhrase(RenderingContext.TEXT_ICON_SLICE)); - parent.getCells().add(gen.new Cell(null, null, "Slices for "+ child.getName(), "", null)); + parent.getCells().add(gen.new Cell(null, null, context.formatPhrase(RenderingContext.STRUC_DEF_SLICE_FOR, child.getName()), "", null)); switch (context.getStructureMode()) { case BINDINGS: case OBLIGATIONS: @@ -947,6 +947,16 @@ public class StructureDefinitionRenderer extends ResourceRenderer { return slicingRow; } + private String noTail(String id) { + if (id.contains(".")) { + String t = id.substring(id.lastIndexOf(".")+1); + if (Utilities.isInteger(t)) { + return id.substring(0, id.lastIndexOf(".")); + } + } + return id; + } + private String makeAnchorUnique(String anchor) { if (anchors.containsKey(anchor)) { int c = anchors.get(anchor)+1; @@ -1063,7 +1073,7 @@ public class StructureDefinitionRenderer extends ResourceRenderer { hint = checkAdd(hint, !hasDef ? null : gt(element.getDefinitionElement())); } if (element.hasSlicing() && slicesExist(elements, element)) { // some elements set up slicing but don't actually slice, so we don't augment the name - sName = context.formatPhrase(RenderingContext.STRUC_DEF_SLICE_FOR, sName); + sName = context.formatPhrase(RenderingContext.STRUC_DEF_SLICE_FOR, sName); } Cell left = gen.new Cell(null, ref, sName, hint, null); row.getCells().add(left); @@ -3421,7 +3431,7 @@ public class StructureDefinitionRenderer extends ResourceRenderer { sdMapCache.put(url, sdCache); String webroot = sd.getUserString("webroot"); for (ElementDefinition e : sd.getSnapshot().getElement()) { - context.getProfileUtilities().updateURLs(sd.getUrl(), webroot, e); + context.getProfileUtilities().updateURLs(sd.getUrl(), webroot, e, false); sdCache.put(e.getId(), e); } } diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ValueSetRenderer.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ValueSetRenderer.java index eb303d742..16adae09a 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ValueSetRenderer.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ValueSetRenderer.java @@ -750,20 +750,11 @@ public class ValueSetRenderer extends TerminologyRenderer { if (cs == null) { return "?cs-n?"; } - String ref = (String) cs.getUserData("filename"); + String ref = cs.getWebPath(); if (ref == null) { - ref = (String) cs.getWebPath(); + ref = cs.getUserString("filename"); } - if (ref == null && cs.hasUserData("webroot")) { - ref = (String) cs.getUserData("webroot"); - } - if (ref == null) { - return "?ngen-14?.html"; - } - if (!ref.contains(".html")) { - ref = ref + ".html"; - } - return ref.replace("\\", "/"); + return ref == null ? null : ref.replace("\\", "/"); } private void scanForDesignations(ValueSetExpansionContainsComponent c, List langs, Map designations) { @@ -922,14 +913,18 @@ public class ValueSetRenderer extends TerminologyRenderer { td.addText(code); } else { String href = context.fixReference(getCsRef(e)); - if (href.contains("#")) - href = href + "-"+Utilities.nmtokenize(code); - else - href = href + "#"+e.getId()+"-"+Utilities.nmtokenize(code); - if (isAbstract) - td.ah(context.prefixLocalHref(href)).setAttribute("title", context.formatPhrase(RenderingContext.VS_ABSTRACT_CODE_HINT)).i().addText(code); - else - td.ah(context.prefixLocalHref(href)).addText(code); + if (href == null) { + td.code().tx(code); + } else { + if (href.contains("#")) + href = href + "-"+Utilities.nmtokenize(code); + else + href = href + "#"+e.getId()+"-"+Utilities.nmtokenize(code); + if (isAbstract) + td.ah(context.prefixLocalHref(href)).setAttribute("title", context.formatPhrase(RenderingContext.VS_ABSTRACT_CODE_HINT)).i().addText(code); + else + td.ah(context.prefixLocalHref(href)).addText(code); + } } } @@ -1247,11 +1242,15 @@ public class ValueSetRenderer extends TerminologyRenderer { wli.tx(f.getProperty()+" "+describe(f.getOp())+" "); if (e != null && codeExistsInValueSet(e, f.getValue())) { String href = getContext().fixReference(getCsRef(e)); - if (href.contains("#")) - href = href + "-"+Utilities.nmtokenize(f.getValue()); - else - href = href + "#"+e.getId()+"-"+Utilities.nmtokenize(f.getValue()); - wli.ah(context.prefixLocalHref(href)).addText(f.getValue()); + if (href == null) { + wli.code().tx(f.getValue()); + } else { + if (href.contains("#")) + href = href + "-"+Utilities.nmtokenize(f.getValue()); + else + href = href + "#"+e.getId()+"-"+Utilities.nmtokenize(f.getValue()); + wli.ah(context.prefixLocalHref(href)).addText(f.getValue()); + } } else if (inc.hasSystem()) { wli.addText(f.getValue()); ValidationResult vr = getContext().getWorker().validateCode(getContext().getTerminologyServiceOptions(), inc.getSystem(), inc.getVersion(), f.getValue(), null); diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/spreadsheets/SpreadsheetGenerator.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/spreadsheets/SpreadsheetGenerator.java index 18a7e22cf..ab82995d8 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/spreadsheets/SpreadsheetGenerator.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/spreadsheets/SpreadsheetGenerator.java @@ -100,7 +100,8 @@ public class SpreadsheetGenerator { if (name.length() > MAX_SENSITIVE_SHEET_NAME_LEN - 2) { name = name.substring(0, MAX_SENSITIVE_SHEET_NAME_LEN - 2); } - String s = fixSheetNameChars(name); + name = fixSheetNameChars(name); + String s = name; if (sheetNames.containsKey(s)) { int i = 1; do { diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/spreadsheets/ValueSetSpreadsheetGenerator.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/spreadsheets/ValueSetSpreadsheetGenerator.java index 106a581e2..942c43eb6 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/spreadsheets/ValueSetSpreadsheetGenerator.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/spreadsheets/ValueSetSpreadsheetGenerator.java @@ -1,25 +1,17 @@ package org.hl7.fhir.r5.renderers.spreadsheets; -import java.io.FileOutputStream; import java.io.IOException; -import java.io.OutputStream; import java.util.List; -import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Sheet; -import org.hl7.fhir.exceptions.DefinitionException; import org.hl7.fhir.r5.context.IWorkerContext; -import org.hl7.fhir.r5.context.SimpleWorkerContext; import org.hl7.fhir.r5.model.CanonicalType; -import org.hl7.fhir.r5.model.ElementDefinition; import org.hl7.fhir.r5.model.ValueSet; import org.hl7.fhir.r5.model.ValueSet.ConceptReferenceComponent; import org.hl7.fhir.r5.model.ValueSet.ConceptSetComponent; import org.hl7.fhir.r5.model.ValueSet.ConceptSetFilterComponent; import org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionContainsComponent; import org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionParameterComponent; -import org.hl7.fhir.r5.model.StructureDefinition.StructureDefinitionMappingComponent; -import org.hl7.fhir.utilities.i18n.I18nConstants; public class ValueSetSpreadsheetGenerator extends CanonicalSpreadsheetGenerator { @@ -36,11 +28,12 @@ public class ValueSetSpreadsheetGenerator extends CanonicalSpreadsheetGenerator System.out.println("no valueset!"); } addValueSetMetadata(renderCanonicalResource(vs, false), vs); + int i = 0; for (ConceptSetComponent inc : vs.getCompose().getInclude()) { - genInclude(vs, inc, "Include"); + genInclude(vs, inc, "Include", i++); } for (ConceptSetComponent exc : vs.getCompose().getExclude()) { - genInclude(vs, exc, "Exclude"); + genInclude(vs, exc, "Exclude", i++); } if (vs.hasExpansion()) { if (vs.getExpansion().hasParameter()) { @@ -82,11 +75,11 @@ public class ValueSetSpreadsheetGenerator extends CanonicalSpreadsheetGenerator return value ? "" : "false"; } - private void genInclude(ValueSet vs, ConceptSetComponent inc, String mode) { + private void genInclude(ValueSet vs, ConceptSetComponent inc, String mode, int count) { if (inc.hasSystem()) { - genIncludeSystem(vs, inc, mode); + genIncludeSystem(vs, inc, mode, count); } else { - genIncludeValueSets(vs, inc, mode); + genIncludeValueSets(vs, inc, mode, count); } // String subname = inc.hasSystem() ? : "ValueSets"; // @@ -107,14 +100,14 @@ public class ValueSetSpreadsheetGenerator extends CanonicalSpreadsheetGenerator // configureSheet(sheet, sd); } - private void genIncludeValueSets(ValueSet vs, ConceptSetComponent inc, String mode) { - Sheet sheet = makeSheet(mode+" ValueSets"); + private void genIncludeValueSets(ValueSet vs, ConceptSetComponent inc, String mode, int count) { + Sheet sheet = makeSheet(mode+" ValueSet #"+count); addValueSets(sheet, inc.getValueSet()); configureSheet(sheet); } - private void genIncludeSystem(ValueSet vs, ConceptSetComponent inc, String mode) { - Sheet sheet = makeSheet(mode+" from "+dr.displaySystem(inc.getSystem())); + private void genIncludeSystem(ValueSet vs, ConceptSetComponent inc, String mode, int count) { + Sheet sheet = makeSheet(mode+" #"+count); if (inc.hasValueSet()) { addValueSets(sheet, inc.getValueSet()); } diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/utils/RenderingContext.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/utils/RenderingContext.java index 572523a1e..687d7c672 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/utils/RenderingContext.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/utils/RenderingContext.java @@ -554,6 +554,9 @@ public class RenderingContext extends RenderingI18nContext { } public String fixReference(String ref) { + if (ref == null) { + return null; + } if (!Utilities.isAbsoluteUrl(ref)) { return (localPrefix == null ? "" : localPrefix)+ref; } diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/expansion/ValueSetExpander.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/expansion/ValueSetExpander.java index 28058becb..7e1cfbbf7 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/expansion/ValueSetExpander.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/expansion/ValueSetExpander.java @@ -606,33 +606,35 @@ public class ValueSetExpander extends ValueSetProcessBase { excludeCodes(wc, importValueSetForExclude(wc, imp.getValue(), exp, expParams, false, vs).getExpansion()); } - CodeSystem cs = context.fetchSupplementedCodeSystem(exc.getSystem()); - if ((cs == null || cs.getContent() != CodeSystemContentMode.COMPLETE) && context.supportsSystem(exc.getSystem(), opContext.getOptions().getFhirVersion())) { - ValueSetExpansionOutcome vse = context.expandVS(exc, false, false); - ValueSet valueset = vse.getValueset(); - if (valueset == null) - throw failTSE("Error Expanding ValueSet: "+vse.getError()); - excludeCodes(wc, valueset.getExpansion()); - return; - } - - for (ConceptReferenceComponent c : exc.getConcept()) { - excludeCode(wc, exc.getSystem(), c.getCode()); - } - - if (exc.getFilter().size() > 0) { - if (cs.getContent() == CodeSystemContentMode.FRAGMENT) { - addFragmentWarning(exp, cs); + if (exc.hasSystem()) { + CodeSystem cs = context.fetchSupplementedCodeSystem(exc.getSystem()); + if ((cs == null || cs.getContent() != CodeSystemContentMode.COMPLETE) && context.supportsSystem(exc.getSystem(), opContext.getOptions().getFhirVersion())) { + ValueSetExpansionOutcome vse = context.expandVS(exc, false, false); + ValueSet valueset = vse.getValueset(); + if (valueset == null) + throw failTSE("Error Expanding ValueSet: "+vse.getError()); + excludeCodes(wc, valueset.getExpansion()); + return; } - List filters = new ArrayList<>(); - for (int i = 1; i < exc.getFilter().size(); i++) { - WorkingContext wc1 = new WorkingContext(); - filters.add(wc1); - processFilter(exc, exp, expParams, null, cs, false, exc.getFilter().get(i), wc1, null, true); + + for (ConceptReferenceComponent c : exc.getConcept()) { + excludeCode(wc, exc.getSystem(), c.getCode()); + } + + if (exc.getFilter().size() > 0) { + if (cs.getContent() == CodeSystemContentMode.FRAGMENT) { + addFragmentWarning(exp, cs); + } + List filters = new ArrayList<>(); + for (int i = 1; i < exc.getFilter().size(); i++) { + WorkingContext wc1 = new WorkingContext(); + filters.add(wc1); + processFilter(exc, exp, expParams, null, cs, false, exc.getFilter().get(i), wc1, null, true); + } + ConceptSetFilterComponent fc = exc.getFilter().get(0); + WorkingContext wc1 = dwc; + processFilter(exc, exp, expParams, null, cs, false, fc, wc1, filters, true); } - ConceptSetFilterComponent fc = exc.getFilter().get(0); - WorkingContext wc1 = dwc; - processFilter(exc, exp, expParams, null, cs, false, fc, wc1, filters, true); } } @@ -728,7 +730,6 @@ public class ValueSetExpander extends ValueSetProcessBase { expParams = makeDefaultExpansion(); altCodeParams.seeParameters(expParams); altCodeParams.seeValueSet(source); - source.checkNoModifiers("ValueSet", "expanding"); focus = source.copy(); focus.setIdBase(null); 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 9315b55ab..dd8b9733a 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 @@ -124,11 +124,9 @@ public class ValueSetValidator extends ValueSetProcessBase { } public String getMessage() { return message; - } - + } } - private ValueSet valueset; private Map inner = new HashMap<>(); private ValidationOptions options; diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/sql/Runner.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/sql/Runner.java index 432fff492..aa5d8b4e1 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/sql/Runner.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/sql/Runner.java @@ -103,7 +103,7 @@ public class Runner implements IEvaluationContext { for (JsonObject w : vd.getJsonObjects("where")) { String expr = w.asString("path"); ExpressionNode node = fpe.parse(expr); - boolean pass = fpe.evaluateToBoolean(null, b, b, b, node); + boolean pass = fpe.evaluateToBoolean(vd, b, b, b, node); if (!pass) { ok = false; break; @@ -114,7 +114,7 @@ public class Runner implements IEvaluationContext { rows.add(new ArrayList()); for (JsonObject select : vd.getJsonObjects("select")) { - executeSelect(select, b, rows); + executeSelect(vd, select, b, rows); } for (List row : rows) { storage.addRow(store, row); @@ -124,14 +124,14 @@ public class Runner implements IEvaluationContext { storage.finish(store); } - private void executeSelect(JsonObject select, Base b, List> rows) { + private void executeSelect(JsonObject vd, JsonObject select, Base b, List> rows) { List focus = new ArrayList<>(); if (select.has("forEach")) { - focus.addAll(executeForEach(select, b)); + focus.addAll(executeForEach(vd, select, b)); } else if (select.has("forEachOrNull")) { - focus.addAll(executeForEachOrNull(select, b)); + focus.addAll(executeForEachOrNull(vd, select, b)); if (focus.isEmpty()) { List columns = (List) select.getUserData("columns"); for (List row : rows) { @@ -159,20 +159,20 @@ public class Runner implements IEvaluationContext { List> rowsToAdd = cloneRows(tempRows); for (JsonObject column : select.getJsonObjects("column")) { - executeColumn(column, f, rowsToAdd); + executeColumn(vd, column, f, rowsToAdd); } for (JsonObject sub : select.getJsonObjects("select")) { - executeSelect(sub, f, rowsToAdd); + executeSelect(vd, sub, f, rowsToAdd); } - executeUnionAll(select.getJsonObjects("unionAll"), f, rowsToAdd); + executeUnionAll(vd, select.getJsonObjects("unionAll"), f, rowsToAdd); rows.addAll(rowsToAdd); } } - private void executeUnionAll(List unionList, Base b, List> rows) { + private void executeUnionAll(JsonObject vd, List unionList, Base b, List> rows) { if (unionList.isEmpty()) { return; } @@ -183,7 +183,7 @@ public class Runner implements IEvaluationContext { for (JsonObject union : unionList) { List> tempRows = new ArrayList<>(); tempRows.addAll(sourceRows); - executeSelect(union, b, tempRows); + executeSelect(vd, union, b, tempRows); rows.addAll(tempRows); } } @@ -204,25 +204,25 @@ public class Runner implements IEvaluationContext { return list; } - private List executeForEach(JsonObject focus, Base b) { + private List executeForEach(JsonObject vd, JsonObject focus, Base b) { ExpressionNode n = (ExpressionNode) focus.getUserData("forEach"); List result = new ArrayList<>(); - result.addAll(fpe.evaluate(b, n)); + result.addAll(fpe.evaluate(vd, b, n)); return result; } - private List executeForEachOrNull(JsonObject focus, Base b) { + private List executeForEachOrNull(JsonObject vd, JsonObject focus, Base b) { ExpressionNode n = (ExpressionNode) focus.getUserData("forEachOrNull"); List result = new ArrayList<>(); - result.addAll(fpe.evaluate(b, n)); + result.addAll(fpe.evaluate(vd, b, n)); return result; } - private void executeColumn(JsonObject column, Base b, List> rows) { + private void executeColumn(JsonObject vd, JsonObject column, Base b, List> rows) { ExpressionNode n = (ExpressionNode) column.getUserData("path"); List bl2 = new ArrayList<>(); if (b != null) { - bl2.addAll(fpe.evaluate(b, n)); + bl2.addAll(fpe.evaluate(vd, b, n)); } Column col = (Column) column.getUserData("column"); if (col == null) { @@ -344,14 +344,43 @@ public class Runner implements IEvaluationContext { @Override public List resolveConstant(FHIRPathEngine engine, Object appContext, String name, boolean beforeContext, boolean explicitConstant) throws PathEngineException { - throw new Error("Not implemented yet: resolveConstant"); + List list = new ArrayList(); + if (explicitConstant) { + JsonObject vd = (JsonObject) appContext; + JsonObject constant = findConstant(vd, name); + if (constant != null) { + Base b = (Base) constant.getUserData("value"); + if (b != null) { + list.add(b); + } + } + } + return list; } @Override public TypeDetails resolveConstantType(FHIRPathEngine engine, Object appContext, String name, boolean explicitConstant) throws PathEngineException { - throw new Error("Not implemented yet: resolveConstantType"); + if (explicitConstant) { + JsonObject vd = (JsonObject) appContext; + JsonObject constant = findConstant(vd, name.substring(1)); + if (constant != null) { + Base b = (Base) constant.getUserData("value"); + if (b != null) { + return new TypeDetails(CollectionStatus.SINGLETON, b.fhirType()); + } + } + } + return null; } + private JsonObject findConstant(JsonObject vd, String name) { + for (JsonObject o : vd.getJsonObjects("constant")) { + if (name.equals(o.asString("name"))) { + return o; + } + } + return null; + } @Override public boolean log(String argument, List focus) { throw new Error("Not implemented yet: log"); diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/sql/StorageJson.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/sql/StorageJson.java index d0e3aaeed..d76404c03 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/sql/StorageJson.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/sql/StorageJson.java @@ -2,6 +2,7 @@ package org.hl7.fhir.r5.utils.sql; import java.util.List; +import org.hl7.fhir.exceptions.FHIRException; import org.hl7.fhir.r5.model.Base; import org.hl7.fhir.utilities.json.model.JsonArray; import org.hl7.fhir.utilities.json.model.JsonBoolean; @@ -33,16 +34,16 @@ public class StorageJson implements Storage { JsonObject row = new JsonObject(); rows.add(row); for (Cell cell : cells) { - if (cell.getValues().size() == 0) { - row.add(cell.getColumn().getName(), new JsonNull()); - } else if (cell.getValues().size() == 1) { - row.add(cell.getColumn().getName(), makeJsonNode(cell.getValues().get(0))); - } else { + if (cell.getColumn().isColl() || cell.getValues().size() > 1) { JsonArray arr = new JsonArray(); - row.add(cell.getColumn().getName(), arr); + row.add(cell.getColumn().getName(), arr); for (Value value : cell.getValues()) { arr.add(makeJsonNode(value)); - } + } + } else if (cell.getValues().size() == 0) { + row.add(cell.getColumn().getName(), new JsonNull()); + } else { + row.add(cell.getColumn().getName(), makeJsonNode(cell.getValues().get(0))); } } } @@ -87,7 +88,7 @@ public class StorageJson implements Storage { @Override public String getKeyForSourceResource(Base res) { - return res.getIdBase(); + return res.fhirType()+"/"+res.getIdBase(); } @Override diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/sql/Validator.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/sql/Validator.java index 669fa32de..00c862b5d 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/sql/Validator.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/sql/Validator.java @@ -11,6 +11,27 @@ import org.hl7.fhir.r5.context.IWorkerContext; import org.hl7.fhir.r5.fhirpath.ExpressionNode; import org.hl7.fhir.r5.fhirpath.FHIRPathEngine; import org.hl7.fhir.r5.fhirpath.TypeDetails; +import org.hl7.fhir.r5.formats.JsonParser; +import org.hl7.fhir.r5.model.Base64BinaryType; +import org.hl7.fhir.r5.model.BooleanType; +import org.hl7.fhir.r5.model.CanonicalType; +import org.hl7.fhir.r5.model.CodeType; +import org.hl7.fhir.r5.model.DateTimeType; +import org.hl7.fhir.r5.model.DateType; +import org.hl7.fhir.r5.model.DecimalType; +import org.hl7.fhir.r5.model.IdType; +import org.hl7.fhir.r5.model.InstantType; +import org.hl7.fhir.r5.model.Integer64Type; +import org.hl7.fhir.r5.model.IntegerType; +import org.hl7.fhir.r5.model.OidType; +import org.hl7.fhir.r5.model.PositiveIntType; +import org.hl7.fhir.r5.model.PrimitiveType; +import org.hl7.fhir.r5.model.StringType; +import org.hl7.fhir.r5.model.TimeType; +import org.hl7.fhir.r5.model.UnsignedIntType; +import org.hl7.fhir.r5.model.UriType; +import org.hl7.fhir.r5.model.UrlType; +import org.hl7.fhir.r5.model.UuidType; import org.hl7.fhir.r5.fhirpath.ExpressionNode.CollectionStatus; import org.hl7.fhir.r5.fhirpath.FHIRPathEngine.IssueMessage; import org.hl7.fhir.utilities.Utilities; @@ -99,7 +120,7 @@ public class Validator { i = 0; if (checkAllObjects(path, viewDefinition, "where")) { for (JsonObject where : viewDefinition.getJsonObjects("where")) { - checkWhere(path+".where["+i+"]", where); + checkWhere(viewDefinition, path+".where["+i+"]", where); i++; } } @@ -108,7 +129,7 @@ public class Validator { i = 0; if (checkAllObjects(path, viewDefinition, "select")) { for (JsonObject select : viewDefinition.getJsonObjects("select")) { - columns.addAll(checkSelect(path+".select["+i+"]", select, t)); + columns.addAll(checkSelect(viewDefinition, path+".select["+i+"]", select, t)); i++; } if (i == 0) { @@ -119,15 +140,15 @@ public class Validator { } } - private List checkSelect(String path, JsonObject select, TypeDetails t) { + private List checkSelect(JsonObject vd, String path, JsonObject select, TypeDetails t) { List columns = new ArrayList<>(); select.setUserData("columns", columns); checkProperties(select, path, "column", "select", "forEach", "forEachOrNull", "unionAll"); if (select.has("forEach")) { - t = checkForEach(path, select, select.get("forEach"), t); + t = checkForEach(vd, path, select, select.get("forEach"), t); } else if (select.has("forEachOrNull")) { - t = checkForEachOrNull(path, select, select.get("forEachOrNull"), t); + t = checkForEachOrNull(vd, path, select, select.get("forEachOrNull"), t); } if (t != null) { @@ -142,7 +163,7 @@ public class Validator { if (!(e instanceof JsonObject)) { error(path+".column["+i+"]", a, "column["+i+"] is a "+e.type().toName()+" not an object", IssueType.INVALID); } else { - columns.add(checkColumn(path+".column["+i+"]", (JsonObject) e, t)); + columns.add(checkColumn(vd, path+".column["+i+"]", (JsonObject) e, t)); } } } @@ -158,14 +179,14 @@ public class Validator { if (!(e instanceof JsonObject)) { error(path+".select["+i+"]", e, "select["+i+"] is not an object", IssueType.INVALID); } else { - columns.addAll(checkSelect(path+".select["+i+"]", (JsonObject) e, t)); + columns.addAll(checkSelect(vd, path+".select["+i+"]", (JsonObject) e, t)); } } } } if (select.has("unionAll")) { - columns.addAll(checkUnion(path, select, select.get("unionAll"), t)); + columns.addAll(checkUnion(vd, path, select, select.get("unionAll"), t)); } if (columns.isEmpty()) { error(path, select, "The select has no columns or selects", IssueType.REQUIRED); @@ -191,7 +212,7 @@ public class Validator { } } - private List checkUnion(String path, JsonObject focus, JsonElement expression, TypeDetails t) { + private List checkUnion(JsonObject vd, String path, JsonObject focus, JsonElement expression, TypeDetails t) { JsonElement a = focus.get("unionAll"); if (!(a instanceof JsonArray)) { error(path+".unionAll", a, "union is not an array", IssueType.INVALID); @@ -203,7 +224,7 @@ public class Validator { if (!(e instanceof JsonObject)) { error(path+".unionAll["+i+"]", e, "unionAll["+i+"] is not an object", IssueType.INVALID); } else { - unionColumns.add(checkSelect(path+".unionAll["+i+"]", (JsonObject) e, t)); + unionColumns.add(checkSelect(vd, path+".unionAll["+i+"]", (JsonObject) e, t)); } i++; } @@ -242,7 +263,7 @@ public class Validator { } } - private Column checkColumn(String path, JsonObject column, TypeDetails t) { + private Column checkColumn(JsonObject vd, String path, JsonObject column, TypeDetails t) { checkProperties(column, path, "path", "name", "description", "collection", "type", "tag"); if (!column.has("path")) { @@ -260,7 +281,7 @@ public class Validator { try { node = fpe.parse(expr); column.setUserData("path", node); - td = fpe.checkOnTypes(null, resourceName, t, node, warnings); + td = fpe.checkOnTypes(vd, resourceName, t, node, warnings); } catch (Exception e) { error(path, expression, e.getMessage(), IssueType.INVALID); } @@ -296,25 +317,31 @@ public class Validator { // ok, name is sorted! if (columnName != null) { column.setUserData("name", columnName); - boolean isColl = (td.getCollectionStatus() != CollectionStatus.SINGLETON); + boolean isColl = false; if (column.has("collection")) { JsonElement collectionJ = column.get("collection"); if (!(collectionJ instanceof JsonBoolean)) { error(path+".collection", collectionJ, "collection is not a boolean", IssueType.INVALID); } else { boolean collection = collectionJ.asJsonBoolean().asBoolean(); - if (!collection && isColl) { - isColl = false; - warning(path, column, "collection is false, but the path statement(s) might return multiple values for the column '"+columnName+"' some inputs"); + if (collection) { + isColl = true; } } } if (isColl) { + if (td.getCollectionStatus() == CollectionStatus.SINGLETON) { + hint(path, column, "collection is true, but the path statement(s) can only return single values for the column '"+columnName+"'"); + } + } else { if (arrays == null) { warning(path, expression, "The column '"+columnName+"' appears to be a collection based on it's path. Collections are not supported in all execution contexts"); } else if (!arrays) { warning(path, expression, "The column '"+columnName+"' appears to be a collection based on it's path, but this is not allowed in the current execution context"); } + if (td.getCollectionStatus() != CollectionStatus.SINGLETON) { + warning(path, column, "collection is not true, but the path statement(s) might return multiple values for the column '"+columnName+"' for some inputs"); + } } Set types = new HashSet<>(); if (node.isNullSet()) { @@ -330,7 +357,7 @@ public class Validator { if (typeJ instanceof JsonString) { String type = typeJ.asString(); if (!td.hasType(type)) { - error(path+".type", typeJ, "The path expression does not return a value of the type '"+type, IssueType.VALUE); + error(path+".type", typeJ, "The path expression does not return a value of the type '"+type+"' - found "+td.describe(), IssueType.VALUE); } else { types.clear(); types.add(simpleType(type)); @@ -377,6 +404,8 @@ public class Validator { case "integer": return ColumnKind.Integer; case "decimal": return ColumnKind.Decimal; case "string": return ColumnKind.String; + case "id": return ColumnKind.String; + case "code": return ColumnKind.String; case "base64Binary": return ColumnKind.Binary; case "time": return ColumnKind.Time; default: return ColumnKind.Complex; @@ -384,7 +413,7 @@ public class Validator { } private boolean isSimpleType(String type) { - return Utilities.existsInList(type, "dateTime", "boolean", "integer", "decimal", "string", "base64Binary"); + return Utilities.existsInList(type, "dateTime", "boolean", "integer", "decimal", "string", "base64Binary", "id", "code", "date", "time"); } private String simpleType(String type) { @@ -413,7 +442,7 @@ public class Validator { return type; } - private TypeDetails checkForEach(String path, JsonObject focus, JsonElement expression, TypeDetails t) { + private TypeDetails checkForEach(JsonObject vd, String path, JsonObject focus, JsonElement expression, TypeDetails t) { if (!(expression instanceof JsonString)) { error(path+".forEach", expression, "forEach is not a string", IssueType.INVALID); return null; @@ -425,7 +454,7 @@ public class Validator { try { ExpressionNode n = fpe.parse(expr); focus.setUserData("forEach", n); - td = fpe.checkOnTypes(null, resourceName, t, n, warnings); + td = fpe.checkOnTypes(vd, resourceName, t, n, warnings); } catch (Exception e) { error(path, expression, e.getMessage(), IssueType.INVALID); } @@ -438,7 +467,7 @@ public class Validator { } } - private TypeDetails checkForEachOrNull(String path, JsonObject focus, JsonElement expression, TypeDetails t) { + private TypeDetails checkForEachOrNull(JsonObject vd, String path, JsonObject focus, JsonElement expression, TypeDetails t) { if (!(expression instanceof JsonString)) { error(path+".forEachOrNull", expression, "forEachOrNull is not a string", IssueType.INVALID); return null; @@ -450,7 +479,7 @@ public class Validator { try { ExpressionNode n = fpe.parse(expr); focus.setUserData("forEachOrNull", n); - td = fpe.checkOnTypes(null, resourceName, t, n, warnings); + td = fpe.checkOnTypes(vd, resourceName, t, n, warnings); } catch (Exception e) { error(path, expression, e.getMessage(), IssueType.INVALID); } @@ -477,69 +506,79 @@ public class Validator { } } if (constant.has("valueBase64Binary")) { - checkIsString(path, constant, "valueBase64Binary"); + checkIsString(path, constant, "valueBase64Binary", new Base64BinaryType()); } else if (constant.has("valueBoolean")) { - checkIsBoolean(path, constant, "valueBoolean"); + checkIsBoolean(path, constant, "valueBoolean", new BooleanType()); } else if (constant.has("valueCanonical")) { - checkIsString(path, constant, "valueCanonical"); + checkIsString(path, constant, "valueCanonical", new CanonicalType()); } else if (constant.has("valueCode")) { - checkIsString(path, constant, "valueCode"); + checkIsString(path, constant, "valueCode", new CodeType()); } else if (constant.has("valueDate")) { - checkIsString(path, constant, "valueDate"); + checkIsString(path, constant, "valueDate", new DateType()); } else if (constant.has("valueDateTime")) { - checkIsString(path, constant, "valueDateTime"); + checkIsString(path, constant, "valueDateTime", new DateTimeType()); } else if (constant.has("valueDecimal")) { - checkIsNumber(path, constant, "valueDecimal"); + checkIsNumber(path, constant, "valueDecimal", new DecimalType()); } else if (constant.has("valueId")) { - checkIsString(path, constant, "valueId"); + checkIsString(path, constant, "valueId", new IdType()); } else if (constant.has("valueInstant")) { - checkIsString(path, constant, "valueInstant"); + checkIsString(path, constant, "valueInstant", new InstantType()); } else if (constant.has("valueInteger")) { - checkIsNumber(path, constant, "valueInteger"); + checkIsNumber(path, constant, "valueInteger", new IntegerType()); } else if (constant.has("valueInteger64")) { - checkIsNumber(path, constant, "valueInteger64"); + checkIsNumber(path, constant, "valueInteger64", new Integer64Type()); } else if (constant.has("valueOid")) { - checkIsString(path, constant, "valueOid"); + checkIsString(path, constant, "valueOid", new OidType()); } else if (constant.has("valueString")) { - checkIsString(path, constant, "valueString"); + checkIsString(path, constant, "valueString", new StringType()); } else if (constant.has("valuePositiveInt")) { - checkIsNumber(path, constant, "valuePositiveInt"); + checkIsNumber(path, constant, "valuePositiveInt", new PositiveIntType()); } else if (constant.has("valueTime")) { - checkIsString(path, constant, "valueTime"); + checkIsString(path, constant, "valueTime", new TimeType()); } else if (constant.has("valueUnsignedInt")) { - checkIsNumber(path, constant, "valueUnsignedInt"); + checkIsNumber(path, constant, "valueUnsignedInt", new UnsignedIntType()); } else if (constant.has("valueUri")) { - checkIsString(path, constant, "valueUri"); + checkIsString(path, constant, "valueUri", new UriType()); } else if (constant.has("valueUrl")) { - checkIsString(path, constant, "valueUrl"); + checkIsString(path, constant, "valueUrl", new UrlType()); } else if (constant.has("valueUuid")) { - checkIsString(path, constant, "valueUuid"); + checkIsString(path, constant, "valueUuid", new UuidType()); } else { error(path, constant, "No value found", IssueType.REQUIRED); } } - private void checkIsString(String path, JsonObject constant, String name) { + private void checkIsString(String path, JsonObject constant, String name, PrimitiveType value) { JsonElement j = constant.get(name); if (!(j instanceof JsonString)) { error(path+"."+name, j, name+" must be a string", IssueType.INVALID); + } else { + value.setValueAsString(j.asString()); + constant.setUserData("value", value); } } - private void checkIsBoolean(String path, JsonObject constant, String name) { + private void checkIsBoolean(String path, JsonObject constant, String name, PrimitiveType value) { JsonElement j = constant.get(name); if (!(j instanceof JsonBoolean)) { error(path+"."+name, j, name+" must be a boolean", IssueType.INVALID); + } else { + value.setValueAsString(j.asString()); + constant.setUserData("value", value); } } - private void checkIsNumber(String path, JsonObject constant, String name) { + private void checkIsNumber(String path, JsonObject constant, String name, PrimitiveType value) { JsonElement j = constant.get(name); if (!(j instanceof JsonNumber)) { error(path+"."+name, j, name+" must be a number", IssueType.INVALID); + } else { + value.setValueAsString(j.asString()); + constant.setUserData("value", value); } } - private void checkWhere(String path, JsonObject where) { + + private void checkWhere(JsonObject vd, String path, JsonObject where) { checkProperties(where, path, "path", "description"); String expr = where.asString("path"); @@ -553,7 +592,7 @@ public class Validator { try { ExpressionNode n = fpe.parse(expr); where.setUserData("path", n); - td = fpe.checkOnTypes(null, resourceName, types, n, warnings); + td = fpe.checkOnTypes(vd, resourceName, types, n, warnings); } catch (Exception e) { error(path, where.get("path"), e.getMessage(), IssueType.INVALID); } diff --git a/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/elementmodel/LanguageUtilsTest.java b/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/elementmodel/LanguageUtilsTest.java new file mode 100644 index 000000000..631731b27 --- /dev/null +++ b/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/elementmodel/LanguageUtilsTest.java @@ -0,0 +1,55 @@ +package org.hl7.fhir.r5.elementmodel; + +import org.hl7.fhir.r5.context.IWorkerContext; +import org.hl7.fhir.r5.formats.JsonCreatorDirect; +import org.hl7.fhir.r5.test.utils.CompareUtilities; +import org.hl7.fhir.r5.test.utils.TestingUtilities; +import org.hl7.fhir.utilities.i18n.LanguageFileProducer; +import org.hl7.fhir.utilities.i18n.PoGetTextProducer; +import org.hl7.fhir.utilities.tests.ResourceLoaderTests; +import org.hl7.fhir.utilities.validation.ValidationMessage; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.io.*; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + + +class LanguageUtilsTest implements ResourceLoaderTests { + + @Test + void importFromTranslations() throws Exception { + + IWorkerContext context = TestingUtilities.getSharedWorkerContext(); + + org.hl7.fhir.r5.elementmodel.JsonParser jp = new org.hl7.fhir.r5.elementmodel.JsonParser(context); + InputStream resource = getResourceAsInputStream("languageUtils", "CodeSystem-answer.json"); + Element element = jp.parseSingle(resource, null); + + PoGetTextProducer lp = new PoGetTextProducer(); + List res = new ArrayList<>(); + res.addAll(lp.loadSource(getResourceAsInputStream("languageUtils", "CodeSystem-answer.po"))); + + List lvm = new ArrayList<>(); + lvm.add(new ValidationMessage()); + LanguageUtils languageUtils = new LanguageUtils(context); + int result = languageUtils.importFromTranslations(element, res, lvm); + + Writer generatedResource = new StringWriter(); + jp.compose(element, new JsonCreatorDirect(generatedResource, false, false)); + + assert result == 3; + + InputStream translatedResource = getResourceAsInputStream("languageUtils", "CodeSystem-answer-translated.json"); + String text = new BufferedReader(new InputStreamReader(translatedResource)) + .lines() + .collect(Collectors.joining("\n")); + + String msg = CompareUtilities.checkJsonSrcIsSame("", generatedResource.toString(),text, null); + Assertions.assertNull(msg); + + } + +} \ No newline at end of file diff --git a/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/sql/SQLOnFhirTests.java b/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/sql/SQLOnFhirTests.java index 9dba811a8..d650980fb 100644 --- a/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/sql/SQLOnFhirTests.java +++ b/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/sql/SQLOnFhirTests.java @@ -83,23 +83,21 @@ public class SQLOnFhirTests { this.resources = resources; this.testCase = testCase; } - } public static Stream data() throws ParserConfigurationException, SAXException, IOException { List objects = new ArrayList<>(); - File dir = ManagedFileAccess.file("/Users/grahamegrieve/work/sql-on-fhir-v2/tests/content"); - for (File f : dir.listFiles()) { - if (f.getName().endsWith(".json")) { - JsonObject json = JsonParser.parseObject(f); - String name1 = f.getName().replace(".json", ""); - List resources = json.getJsonObjects("resources"); - int i = 0; - for (JsonObject test : json.getJsonObjects("tests")) { - String name2 = test.asString("title"); - objects.add(Arguments.of(name1+":"+name2, new TestDetails(name1+":"+name2, "$.tests["+i+"]", resources, test))); - i++; - } + JsonArray testFiles = (JsonArray) JsonParser.parse(TestingUtilities.loadTestResourceStream("sql-on-fhir", "manifest.json")); + + for (String s : testFiles.asStrings()) { + JsonObject json = JsonParser.parseObject(TestingUtilities.loadTestResourceStream("sql-on-fhir", s)); + String name1 = s.replace(".json", ""); + List resources = json.getJsonObjects("resources"); + int i = 0; + for (JsonObject test : json.getJsonObjects("tests")) { + String name2 = test.asString("title"); + objects.add(Arguments.of(name1+":"+name2, new TestDetails(name1+":"+name2, "$.tests["+i+"]", resources, test))); + i++; } } return objects.stream(); @@ -110,7 +108,6 @@ public class SQLOnFhirTests { @SuppressWarnings("deprecation") @ParameterizedTest(name = "{index}: file {0}") @MethodSource("data") - @Disabled public void test(String name, TestDetails test) throws FileNotFoundException, IOException, FHIRException, org.hl7.fhir.exceptions.FHIRException, UcumException { this.details = test; Runner runner = new Runner(); @@ -137,8 +134,8 @@ public class SQLOnFhirTests { rows.add("rows", results); JsonObject exp = new JsonObject(); exp.add("rows", test.testCase.getJsonArray("expect")); - sortResults(exp); - sortResults(rows); +// sortResults(exp); +// sortResults(rows); String expS = JsonParser.compose(exp, true); String rowS = JsonParser.compose(rows, true); String c = CompareUtilities.checkJsonSrcIsSame(name, expS, rowS, null); diff --git a/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/NarrativeGenerationTests.java b/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/NarrativeGenerationTests.java index 2372a130d..cab59327e 100644 --- a/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/NarrativeGenerationTests.java +++ b/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/NarrativeGenerationTests.java @@ -84,12 +84,12 @@ public class NarrativeGenerationTests { @Override public String getLinkFor(String corePath, String typeSimple) { - throw new NotImplementedException(); + return "http://test/link"; } @Override public BindingResolution resolveBinding(StructureDefinition def, ElementDefinitionBindingComponent binding, String path) throws FHIRException { - throw new NotImplementedException(); + return new BindingResolution("test", "http://test"); } @Override @@ -102,7 +102,7 @@ public class NarrativeGenerationTests { return new BindingResolution(vs.present(), "valueset-"+vs.getIdBase()+".html"); } } - throw new NotImplementedException(); + return new BindingResolution("test", "http://test/ns"); } @Override @@ -120,7 +120,7 @@ public class NarrativeGenerationTests { @Override public String getLinkForUrl(String corePath, String s) { - throw new NotImplementedException(); + return "http://test/link/url"; } @Override diff --git a/org.hl7.fhir.r5/src/test/resources/languageUtils/CodeSystem-answer-translated.json b/org.hl7.fhir.r5/src/test/resources/languageUtils/CodeSystem-answer-translated.json new file mode 100644 index 000000000..06f059bde --- /dev/null +++ b/org.hl7.fhir.r5/src/test/resources/languageUtils/CodeSystem-answer-translated.json @@ -0,0 +1,38 @@ +{ + "resourceType" : "CodeSystem", + "id" : "basic-answer", + "language" : "en", + "url" : "https://example.com/CodeSystem/basic-answer", + "version" : "0.1.0", + "name" : "BasicAnswer", + "title" : "Administration-Method", + "status" : "active", + "date" : "2024-04-07", + "publisher" : "Sample", + "description" : "Basic answers for any kind of questions.", + "caseSensitive" : false, + "content" : "complete", + "count" : 3, + "concept" : [ { + "code" : "ok", + "display" : "OK", + "designation" : [ { + "language" : "it", + "value" : "OK" + } ] + }, { + "code" : "yes", + "display" : "Yes", + "designation" : [ { + "language" : "it", + "value" : "Si" + } ] + }, { + "code" : "no", + "display" : "No", + "designation" : [ { + "language" : "it", + "value" : "No" + } ] + } ] +} \ No newline at end of file diff --git a/org.hl7.fhir.r5/src/test/resources/languageUtils/CodeSystem-answer.json b/org.hl7.fhir.r5/src/test/resources/languageUtils/CodeSystem-answer.json new file mode 100644 index 000000000..fe6f0d690 --- /dev/null +++ b/org.hl7.fhir.r5/src/test/resources/languageUtils/CodeSystem-answer.json @@ -0,0 +1,30 @@ +{ + "resourceType": "CodeSystem", + "status": "active", + "content": "complete", + "name": "BasicAnswer", + "id": "basic-answer", + "title": "Administration-Method", + "description": "Basic answers for any kind of questions.", + "url": "https://example.com/CodeSystem/basic-answer", + "concept": [ + { + "code": "ok", + "display": "OK" + }, + { + "code": "yes", + "display": "Yes" + }, + { + "code": "no", + "display": "No" + } + ], + "language": "en", + "version": "0.1.0", + "date": "2024-04-07", + "publisher": "Sample", + "caseSensitive": false, + "count": 3 +} diff --git a/org.hl7.fhir.r5/src/test/resources/languageUtils/CodeSystem-answer.po b/org.hl7.fhir.r5/src/test/resources/languageUtils/CodeSystem-answer.po new file mode 100644 index 000000000..becb6026b --- /dev/null +++ b/org.hl7.fhir.r5/src/test/resources/languageUtils/CodeSystem-answer.po @@ -0,0 +1,37 @@ +# en -> it + +#: CanonicalResource.name +#. A natural language name identifying the code system. This name should be usable as an identifier for the module by machine processing applications such as code generation. +msgid "BasicAnswer" +msgstr "" + +#: CanonicalResource.title +#. A short, descriptive, user-friendly title for the code system. +msgid "Administration-Method" +msgstr "" + +#: CanonicalResource.publisher +#. The name of the organization or individual that published the code system. +msgid "Example Publisher" +msgstr "" + +#: CanonicalResource.description +#. A free text natural language description of the code system from a consumer's perspective. +msgid "Basic answers for any kind of questions." +msgstr "" + +#: CodeSystem.concept.display +#. A human readable string that is the recommended default way to present this concept to a user. +msgid "OK" +msgstr "OK" + +#: CodeSystem.concept.display +#. A human readable string that is the recommended default way to present this concept to a user. +msgid "Yes" +msgstr "Si" + +#: CodeSystem.concept.display +#. A human readable string that is the recommended default way to present this concept to a user. +msgid "No" +msgstr "No" + diff --git a/org.hl7.fhir.report/pom.xml b/org.hl7.fhir.report/pom.xml index 14605cc43..dda6b248f 100644 --- a/org.hl7.fhir.report/pom.xml +++ b/org.hl7.fhir.report/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir org.hl7.fhir.core - 6.3.24-SNAPSHOT + 6.3.27-SNAPSHOT ../pom.xml @@ -89,7 +89,7 @@ org.sonatype.plugins nexus-staging-maven-plugin - true + true diff --git a/org.hl7.fhir.utilities/pom.xml b/org.hl7.fhir.utilities/pom.xml index 76ea1bc06..a2e86d2a1 100644 --- a/org.hl7.fhir.utilities/pom.xml +++ b/org.hl7.fhir.utilities/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir org.hl7.fhir.core - 6.3.24-SNAPSHOT + 6.3.27-SNAPSHOT ../pom.xml 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 c56787430..4042ee2f1 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 @@ -1491,7 +1491,7 @@ public class Utilities { } public static boolean startsWithInList(String s, Collection list) { - if (s == null) { + if (s == null || list == null) { return false; } for (String l : list) { @@ -1819,9 +1819,14 @@ public class Utilities { private static Object applyDatePrecision(String v, int precision) { switch (precision) { - case 4: return v.substring(0, 4); - case 6: return v.substring(0, 7); - case 8: return v.substring(0, 10); + case 4: + return v.substring(0, 4); + case 6: + case 7: + return v.substring(0, 7); + case 8: + case 10: + return v.substring(0, 10); case 14: return v.substring(0, 17); case 17: return v; } @@ -2304,4 +2309,16 @@ public class Utilities { } } + public static boolean listValueStartsWith(String s, Set list) { + if (s == null || list == null) { + return false; + } + for (String l : list) { + if (l.startsWith(s)) { + return true; + } + } + return false; + } + } diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/i18n/I18nBase.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/i18n/I18nBase.java index 09b7782f3..6470514c6 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/i18n/I18nBase.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/i18n/I18nBase.java @@ -125,7 +125,7 @@ public abstract class I18nBase { if (Objects.nonNull(theMessageArguments) && theMessageArguments.length > 0) { message = MessageFormat.format(messages.getString(theMessage).trim(), theMessageArguments); } else { - message = MessageFormat.format(messages.getString(theMessage).trim(), null); + message = MessageFormat.format(messages.getString(theMessage).trim(), (Object) null); } } return message; 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 db81c97c3..e8af42a88 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 @@ -1108,4 +1108,7 @@ public class I18nConstants { public static final String SM_TARGET_TYPE_UNKNOWN = "SM_TARGET_TYPE_UNKNOWN"; public static final String XHTML_XHTML_ATTRIBUTE_XML_SPACE = "XHTML_XHTML_ATTRIBUTE_XML_SPACE"; public static final String VALIDATION_HL7_PUBLISHER_MULTIPLE_WGS = "VALIDATION_HL7_PUBLISHER_MULTIPLE_WGS"; + public static final String SD_BASE_EXPERIMENTAL = "SD_BASE_EXPERIMENTAL"; + public static final String SD_ED_EXPERIMENTAL_BINDING = "SD_ED_EXPERIMENTAL_BINDING"; + public static final String VALIDATION_NO_EXPERIMENTAL_CONTENT = "VALIDATION_NO_EXPERIMENTAL_CONTENT"; } diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/FilesystemPackageCacheManager.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/FilesystemPackageCacheManager.java index df192cc19..ec0495874 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/FilesystemPackageCacheManager.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/FilesystemPackageCacheManager.java @@ -210,26 +210,30 @@ public class FilesystemPackageCacheManager extends BasePackageCacheManager imple Utilities.createDirectory(cacheFolder.getAbsolutePath()); createIniFile(); } else { - if (!isCacheFolderValid()) { + if (!iniFileExists()) { + createIniFile(); + } + if (!isIniFileCurrentVersion()) { clearCache(); createIniFile(); - } else { - deleteOldTempDirectories(); } + deleteOldTempDirectories(); } return null; }); } - private boolean isCacheFolderValid() throws IOException { + private boolean iniFileExists() throws IOException { String iniPath = getPackagesIniPath(); File iniFile = ManagedFileAccess.file(iniPath); - if (!(iniFile.exists())) { - return false; - } + return iniFile.exists(); + } + + private boolean isIniFileCurrentVersion() throws IOException { + String iniPath = getPackagesIniPath(); IniFile ini = new IniFile(iniPath); - String v = ini.getStringProperty("cache", "version"); - return CACHE_VERSION.equals(v); + String version = ini.getStringProperty("cache", "version"); + return CACHE_VERSION.equals(version); } private void deleteOldTempDirectories() throws IOException { diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/NpmPackage.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/NpmPackage.java index 5ab8a9113..54c8ee917 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/NpmPackage.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/NpmPackage.java @@ -237,9 +237,11 @@ public class NpmPackage { public List listFiles() { List res = new ArrayList<>(); if (folder != null) { - for (File f : folder.listFiles()) { - if (!f.isDirectory() && !Utilities.existsInList(f.getName(), "package.json", ".index.json", ".index.db", ".oids.json", ".oids.db")) { - res.add(f.getName()); + if (folder.exists()) { + for (File f : folder.listFiles()) { + if (!f.isDirectory() && !Utilities.existsInList(f.getName(), "package.json", ".index.json", ".index.db", ".oids.json", ".oids.db")) { + res.add(f.getName()); + } } } } else { @@ -648,7 +650,17 @@ public class NpmPackage { } - + /** + * Create a package .index.json file for a package folder. + *

+ * See the FHIR specification for details on .index.json + * format and usage. + * + * @param desc + * @param folder + * @throws FileNotFoundException + * @throws IOException + */ public void indexFolder(String desc, NpmPackageFolder folder) throws FileNotFoundException, IOException { List remove = new ArrayList<>(); NpmPackageIndexBuilder indexer = new NpmPackageIndexBuilder(); diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/PackageHacker.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/PackageHacker.java index 6aba70e60..225bdd409 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/PackageHacker.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/PackageHacker.java @@ -30,61 +30,74 @@ public class PackageHacker { private static boolean useSecureReferences = false; public static void main(String[] args) throws FileNotFoundException, IOException { - new PackageHacker().massEdit(new File("/Users/grahamegrieve/web/hl7.org/fhir")); - // new PackageHacker().edit("/Users/grahamegrieve/web/hl7.org/fhir/us/vitals/2020Sep/package.tgz"); +// new PackageHacker().massEdit(new File("/Users/grahamegrieve/web/hl7.org/fhir")); +// new PackageHacker().edit("/Users/grahamegrieve/web/hl7.org/fhir/6.0.0-ballot1/hl7.fhir.r6.core.tgz"); +// new PackageHacker().edit("/Users/grahamegrieve/web/hl7.org/fhir/6.0.0-ballot1/hl7.fhir.r6.corexml.tgz"); +// new PackageHacker().edit("/Users/grahamegrieve/web/hl7.org/fhir/6.0.0-ballot1/hl7.fhir.r6.examples.tgz"); +// new PackageHacker().edit("/Users/grahamegrieve/web/hl7.org/fhir/6.0.0-ballot1/hl7.fhir.r6.expansions.tgz"); +// new PackageHacker().edit("/Users/grahamegrieve/web/hl7.org/fhir/6.0.0-ballot1/hl7.fhir.r6.search.tgz"); +// new PackageHacker().edit("/Users/grahamegrieve/web/hl7.org/fhir/6.0.0-ballot2/hl7.fhir.r6.core.tgz"); +// new PackageHacker().edit("/Users/grahamegrieve/web/hl7.org/fhir/6.0.0-ballot2/hl7.fhir.r6.corexml.tgz"); +// new PackageHacker().edit("/Users/grahamegrieve/web/hl7.org/fhir/6.0.0-ballot2/hl7.fhir.r6.examples.tgz"); +// new PackageHacker().edit("/Users/grahamegrieve/web/hl7.org/fhir/6.0.0-ballot2/hl7.fhir.r6.expansions.tgz"); +// new PackageHacker().edit("/Users/grahamegrieve/web/hl7.org/fhir/6.0.0-ballot2/hl7.fhir.r6.search.tgz"); + +// new PackageHacker().edit("/Users/grahamegrieve/web/hl7.org/fhir/us/core/v311/package.tgz", "http://hl7.org/fhir/us/core/STU3.1.1"); + new PackageHacker().edit("/Users/grahamegrieve/web/hl7.org/fhir/us/core/v700/package.tgz", "http://hl7.org/fhir/us/core/STU7"); } - private void massEdit(File dir) throws IOException { - System.out.println("process "+dir.getAbsolutePath()); - for (File f : dir.listFiles()) { - if (f.isDirectory()) { - massEdit(f); - } else if (f.getName().equals("package.tgz")) { - try { - FileInputStream fs = ManagedFileAccess.inStream(f); - NpmPackage pck = NpmPackage.fromPackage(fs); - if ("fhir.core".equals(pck.getNpm().str("type"))) { - System.out.println("!!change "+f.getAbsolutePath()); - pck.getNpm().remove("type"); - pck.getNpm().set("type", "Core"); - FileOutputStream fso = ManagedFileAccess.outStream(f); - try { - pck.save(fso); - } finally { - fso.close(); - } - } - } catch (Exception e) { - System.out.println("!!Error: "+e.getMessage()); - } - } else if (f.getName().startsWith("hl7.fhir.r") && f.getName().endsWith(".examples.tgz")) { - try { - FileInputStream fs = ManagedFileAccess.inStream(f); - NpmPackage pck = NpmPackage.fromPackage(fs); - if ("fhir.examples".equals(pck.getNpm().str("type"))) { - System.out.println("!!change "+f.getAbsolutePath()); - pck.getNpm().remove("type"); - pck.getNpm().set("type", "Examples"); - FileOutputStream fso = ManagedFileAccess.outStream(f); - try { - pck.save(fso); - } finally { - fso.close(); - } - } - } catch (Exception e) { - System.out.println("!!Error: "+e.getMessage()); - } +// private void massEdit(File dir) throws IOException { +// System.out.println("process "+dir.getAbsolutePath()); +// for (File f : dir.listFiles()) { +// if (f.isDirectory()) { +// massEdit(f); +// } else if (f.getName().equals("package.tgz")) { +// try { +// FileInputStream fs = ManagedFileAccess.inStream(f); +// NpmPackage pck = NpmPackage.fromPackage(fs); +// if ("fhir.core".equals(pck.getNpm().str("type"))) { +// System.out.println("!!change "+f.getAbsolutePath()); +// pck.getNpm().remove("type"); +// pck.getNpm().set("type", "Core"); +// FileOutputStream fso = ManagedFileAccess.outStream(f); +// try { +// pck.save(fso); +// } finally { +// fso.close(); +// } +// } +// } catch (Exception e) { +// System.out.println("!!Error: "+e.getMessage()); +// } +// } else if (f.getName().startsWith("hl7.fhir.r") && f.getName().endsWith(".examples.tgz")) { +// try { +// FileInputStream fs = ManagedFileAccess.inStream(f); +// NpmPackage pck = NpmPackage.fromPackage(fs); +// if ("fhir.examples".equals(pck.getNpm().str("type"))) { +// System.out.println("!!change "+f.getAbsolutePath()); +// pck.getNpm().remove("type"); +// pck.getNpm().set("type", "Examples"); +// FileOutputStream fso = ManagedFileAccess.outStream(f); +// try { +// pck.save(fso); +// } finally { +// fso.close(); +// } +// } +// } catch (Exception e) { +// System.out.println("!!Error: "+e.getMessage()); +// } +// +// } +// } +// } - } - } - } - - private void edit(String name) throws FileNotFoundException, IOException { + private void edit(String name, String path) throws FileNotFoundException, IOException { File f = ManagedFileAccess.file(name); if (!f.exists()) throw new Error("Unable to find "+f.getAbsolutePath()); + System.out.println("Loading Package "+f.getAbsolutePath()); NpmPackage pck = null; FileInputStream fs = ManagedFileAccess.inStream(f); try { @@ -95,7 +108,7 @@ public class PackageHacker { System.out.println("Altering Package "+f.getAbsolutePath()); System.out.println(nice(pck.getNpm())); - change(pck.getNpm()); + if (change(pck.getNpm(), path)) { System.out.println("Revised Package"); System.out.println("======================="); @@ -111,7 +124,8 @@ public class PackageHacker { } finally { fso.close(); } - } + } + } } private void fixExampleContent(Map content) { @@ -129,10 +143,15 @@ public class PackageHacker { return JsonParser.compose(json, true); } - private void change(JsonObject npm) throws FileNotFoundException, IOException { - // fixVersions(npm, ver); - npm.remove("notForPublication"); - npm.set("name", "hl7.fhir.us.vitals"); + private boolean change(JsonObject npm, String path) throws FileNotFoundException, IOException { + npm.remove("url"); + npm.add("url", path); + return true; +// if (npm.has("notForPublication")) { +// npm.remove("notForPublication"); +// return true; +// } +// return false; } private void fixVersionInContent(Map content) { diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/xhtml/HierarchicalTableGenerator.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/xhtml/HierarchicalTableGenerator.java index 9fc5f29ff..b4cb4bc5d 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/xhtml/HierarchicalTableGenerator.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/xhtml/HierarchicalTableGenerator.java @@ -560,7 +560,6 @@ public class HierarchicalTableGenerator { } return b.toString(); } - } public class TableModel { diff --git a/org.hl7.fhir.utilities/src/main/resources/Messages.properties b/org.hl7.fhir.utilities/src/main/resources/Messages.properties index bae41d4af..35811c33e 100644 --- a/org.hl7.fhir.utilities/src/main/resources/Messages.properties +++ b/org.hl7.fhir.utilities/src/main/resources/Messages.properties @@ -1140,4 +1140,6 @@ XHTML_XHTML_ATTRIBUTE_XML_SPACE = The attribute 'xml:space' is legal but has a f VALIDATION_HL7_PUBLISHER_MULTIPLE_WGS = This resource has more than workgroup extension (http://hl7.org/fhir/StructureDefinition/structuredefinition-wg) NO_VALID_DISPLAY_FOUND_NONE_FOR_LANG = Wrong Display Name ''{0}'' for {1}#{2}. There are no valid display names found for language(s) ''{3}''. Default display is ''{4}'' NO_VALID_DISPLAY_AT_ALL = Cannot validate display Name ''{0}'' for {1}#{2}: No displays are known - +SD_BASE_EXPERIMENTAL = The definition builds on ''{0}'' which is experimental, but this definition is not labeled as experimental +SD_ED_EXPERIMENTAL_BINDING = The definition for the element ''{0}'' binds to the value set ''{1}'' which is experimental, but this structure is not labeled as experimental +VALIDATION_NO_EXPERIMENTAL_CONTENT = Experimental content is not allowed in this context diff --git a/org.hl7.fhir.utilities/src/test/java/org/hl7/fhir/utilities/npm/FilesystemPackageManagerTests.java b/org.hl7.fhir.utilities/src/test/java/org/hl7/fhir/utilities/npm/FilesystemPackageManagerTests.java index 96754c2b8..eba7b198a 100644 --- a/org.hl7.fhir.utilities/src/test/java/org/hl7/fhir/utilities/npm/FilesystemPackageManagerTests.java +++ b/org.hl7.fhir.utilities/src/test/java/org/hl7/fhir/utilities/npm/FilesystemPackageManagerTests.java @@ -1,22 +1,25 @@ package org.hl7.fhir.utilities.npm; +import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; import java.io.File; +import java.io.FileWriter; import java.io.IOException; import java.nio.file.Files; import java.util.ArrayList; import java.util.List; import java.util.Random; +import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Stream; import javax.annotation.Nonnull; +import org.hl7.fhir.utilities.IniFile; import org.hl7.fhir.utilities.filesystem.ManagedFileAccess; -import org.junit.jupiter.api.RepeatedTest; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.condition.DisabledOnOs; import org.junit.jupiter.api.condition.EnabledOnOs; @@ -100,7 +103,6 @@ public class FilesystemPackageManagerTests { @DisabledOnOs(OS.WINDOWS) public void testSystemCacheDirectory() throws IOException { File folder = new FilesystemPackageCacheManager.Builder().withSystemCacheFolder().getCacheFolder(); - assertEquals( "/var/lib/.fhir/packages", folder.getAbsolutePath()); } @@ -124,6 +126,118 @@ public class FilesystemPackageManagerTests { return params.stream(); } + private void createDummyTemp(File cacheDirectory, String lowerCase) throws IOException { + createDummyPackage(cacheDirectory, lowerCase); + } + + private void createDummyPackage(File cacheDirectory, String packageName, String packageVersion) throws IOException { + String directoryName = packageName + "#" + packageVersion; + createDummyPackage(cacheDirectory, directoryName); + } + + private static void createDummyPackage(File cacheDirectory, String directoryName) throws IOException { + File packageDirectory = ManagedFileAccess.file(cacheDirectory.getAbsolutePath(), directoryName); + packageDirectory.mkdirs(); + + File dummyContentFile = ManagedFileAccess.file(packageDirectory.getAbsolutePath(), "dummy.txt"); + FileWriter wr = new FileWriter(dummyContentFile); + wr.write("Ain't nobody here but us chickens"); + wr.flush(); + wr.close(); + } + + private void assertThatDummyTempExists(File cacheDirectory, String dummyTempPackage) throws IOException { + File dummyTempDirectory = ManagedFileAccess.file(cacheDirectory.getAbsolutePath(), dummyTempPackage); + assertThat(dummyTempDirectory).exists(); + + File dummyContentFile = ManagedFileAccess.file(dummyTempDirectory.getAbsolutePath(), "dummy.txt"); + assertThat(dummyContentFile).exists(); + } + + @Test + public void testCreatesIniIfDoesntExistAndCacheStaysIntact() throws IOException { + File cacheDirectory = ManagedFileAccess.fromPath(Files.createTempDirectory("fpcm-multithreadingTest")); + File cacheIni = ManagedFileAccess.file(cacheDirectory.getAbsolutePath(), "packages.ini"); + + createDummyPackage(cacheDirectory, "example.fhir.uv.myig", "1.2.3"); + + String dummyTempPackage = UUID.randomUUID().toString().toLowerCase(); + createDummyTemp(cacheDirectory, dummyTempPackage); + assertThatDummyTempExists(cacheDirectory, dummyTempPackage); + + assertThat(cacheIni).doesNotExist(); + FilesystemPackageCacheManager filesystemPackageCacheManager = new FilesystemPackageCacheManager.Builder().withCacheFolder(cacheDirectory.getAbsolutePath()).build(); + assertInitializedTestCacheIsValid(cacheDirectory, true); + } + + + + @Test + public void testClearsCacheIfVersionIsWrong() throws IOException { + File cacheDirectory = ManagedFileAccess.fromPath(Files.createTempDirectory("fpcm-multithreadingTest")); + File cacheIni = ManagedFileAccess.file(cacheDirectory.getAbsolutePath(), "packages.ini"); + + createDummyPackage(cacheDirectory, "example.fhir.uv.myig", "1.2.3"); + String dummyTempPackage = UUID.randomUUID().toString().toLowerCase(); + createDummyTemp(cacheDirectory, dummyTempPackage); + assertThatDummyTempExists(cacheDirectory, dummyTempPackage); + + + IniFile ini = new IniFile(cacheIni.getAbsolutePath()); + ini.setStringProperty("cache", "version", "2", null); + ini.save(); + + assertThat(cacheIni).exists(); + FilesystemPackageCacheManager filesystemPackageCacheManager = new FilesystemPackageCacheManager.Builder().withCacheFolder(cacheDirectory.getAbsolutePath()).build(); + assertInitializedTestCacheIsValid(cacheDirectory, false); + } + + @Test + public void testCacheStaysIntactIfVersionIsTheSame() throws IOException { + File cacheDirectory = ManagedFileAccess.fromPath(Files.createTempDirectory("fpcm-multithreadingTest")); + File cacheIni = ManagedFileAccess.file(cacheDirectory.getAbsolutePath(), "packages.ini"); + + createDummyPackage(cacheDirectory, "example.fhir.uv.myig", "1.2.3"); + String dummyTempPackage = UUID.randomUUID().toString().toLowerCase(); + createDummyTemp(cacheDirectory, dummyTempPackage); + assertThatDummyTempExists(cacheDirectory, dummyTempPackage); + + + IniFile ini = new IniFile(cacheIni.getAbsolutePath()); + ini.setStringProperty("cache", "version", "3", null); + ini.save(); + + assertThat(cacheIni).exists(); + FilesystemPackageCacheManager filesystemPackageCacheManager = new FilesystemPackageCacheManager.Builder().withCacheFolder(cacheDirectory.getAbsolutePath()).build(); + assertInitializedTestCacheIsValid(cacheDirectory, true); + } + + private void assertInitializedTestCacheIsValid(File cacheDirectory, boolean dummyPackageShouldExist) throws IOException { + assertThat(cacheDirectory).exists(); + File iniFile = ManagedFileAccess.file(cacheDirectory.getAbsolutePath(), "packages.ini"); + assertThat(ManagedFileAccess.file(cacheDirectory.getAbsolutePath(), "packages.ini")).exists(); + IniFile ini = new IniFile(iniFile.getAbsolutePath()); + String version = ini.getStringProperty("cache", "version"); + assertThat(version).isEqualTo("3"); + + File[] files = cacheDirectory.listFiles(); + if (dummyPackageShouldExist) { + // Check that only packages.ini and our dummy package are in the cache. Our previous temp should be deleted. + assertThat(files).hasSize(2); // packages.ini and example.fhir.uv.myig#1.2.3 (directory) + + File dummyPackage = ManagedFileAccess.file(cacheDirectory.getAbsolutePath(), "example.fhir.uv.myig#1.2.3"); + assertThat(dummyPackage).exists(); + + File dummyContentFile = ManagedFileAccess.file(dummyPackage.getAbsolutePath(), "dummy.txt"); + assertThat(dummyContentFile).exists(); + } else { + // Check that only packages.ini is in the cache. + assertThat(files).hasSize(1); + } + + + } + @MethodSource("packageCacheMultiThreadTestParams") @ParameterizedTest public void packageCacheMultiThreadTest(final int threadTotal, final int packageCacheManagerTotal) throws IOException { diff --git a/org.hl7.fhir.validation.cli/pom.xml b/org.hl7.fhir.validation.cli/pom.xml index e6da91b3d..de8286041 100644 --- a/org.hl7.fhir.validation.cli/pom.xml +++ b/org.hl7.fhir.validation.cli/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir org.hl7.fhir.core - 6.3.24-SNAPSHOT + 6.3.27-SNAPSHOT ../pom.xml @@ -405,7 +405,7 @@ org.sonatype.plugins nexus-staging-maven-plugin - true + true diff --git a/org.hl7.fhir.validation/pom.xml b/org.hl7.fhir.validation/pom.xml index 9bf7272b5..19fe4ae82 100644 --- a/org.hl7.fhir.validation/pom.xml +++ b/org.hl7.fhir.validation/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir org.hl7.fhir.core - 6.3.24-SNAPSHOT + 6.3.27-SNAPSHOT ../pom.xml @@ -119,37 +119,6 @@ true - - - info.cqframework - cql - ${info_cqframework_version} - - - info.cqframework - model - ${info_cqframework_version} - - - info.cqframework - elm - ${info_cqframework_version} - - - info.cqframework - cql-to-elm - ${info_cqframework_version} - - - info.cqframework - quick - ${info_cqframework_version} - - - info.cqframework - qdm - ${info_cqframework_version} - com.squareup.okhttp3 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 a242ca2e9..46f5d948b 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 @@ -226,6 +226,8 @@ public class ValidationEngine implements IValidatorResourceFetcher, IValidationP @Getter @Setter private boolean allowDoubleQuotesInFHIRPath; @Getter @Setter private boolean checkIPSCodes; @Getter @Setter private BestPracticeWarningLevel bestPracticeLevel; + @Getter @Setter private boolean unknownCodeSystemsCauseErrors; + @Getter @Setter private boolean noExperimentalContent; @Getter @Setter private Locale locale; @Getter @Setter private List igs = new ArrayList<>(); @Getter @Setter private List extensionDomains = new ArrayList<>(); @@ -289,6 +291,7 @@ public class ValidationEngine implements IValidatorResourceFetcher, IValidationP fhirPathEngine = other.fhirPathEngine; igLoader = other.igLoader; jurisdiction = other.jurisdiction; + unknownCodeSystemsCauseErrors = other.unknownCodeSystemsCauseErrors; } /** @@ -906,6 +909,8 @@ public class ValidationEngine implements IValidatorResourceFetcher, IValidationP if (policyAdvisor != null) { validator.setPolicyAdvisor(policyAdvisor); } + validator.setUnknownCodeSystemsCauseErrors(unknownCodeSystemsCauseErrors); + validator.setNoExperimentalContent(noExperimentalContent); return validator; } diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/model/CliContext.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/model/CliContext.java index f719f029b..418526071 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/model/CliContext.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/model/CliContext.java @@ -163,6 +163,12 @@ public class CliContext { @JsonProperty("bestPracticeLevel") private BestPracticeWarningLevel bestPracticeLevel = BestPracticeWarningLevel.Warning; + @JsonProperty("unknownCodeSystemsCauseErrors") + private boolean unknownCodeSystemsCauseErrors; + + @JsonProperty("noExperimentalContent") + private boolean noExperimentalContent; + @JsonProperty("baseEngine") public String getBaseEngine() { return baseEngine; @@ -832,6 +838,8 @@ public class CliContext { Objects.equals(watchMode, that.watchMode) && Objects.equals(bestPracticeLevel, that.bestPracticeLevel) && Objects.equals(watchScanDelay, that.watchScanDelay) && + Objects.equals(unknownCodeSystemsCauseErrors, that.unknownCodeSystemsCauseErrors) && + Objects.equals(noExperimentalContent, that.noExperimentalContent) && Objects.equals(watchSettleTime, that.watchSettleTime) ; } @@ -839,8 +847,8 @@ public class CliContext { public int hashCode() { return Objects.hash(baseEngine, doNative, extensions, hintAboutNonMustSupport, recursive, doDebug, assumeValidRestReferences, canDoNative, noInternalCaching, noExtensibleBindingMessages, noInvariants, displayWarnings, wantInvariantsInMessages, map, output, outputSuffix, htmlOutput, txServer, sv, txLog, txCache, mapLog, lang, srcLang, tgtLang, fhirpath, snomedCT, - targetVer, igs, questionnaireMode, level, profiles, sources, inputs, mode, locale, locations, crumbTrails, forPublication, showTimes, allowExampleUrls, outputStyle, jurisdiction, noUnicodeBiDiControlChars, watchMode, watchScanDelay, watchSettleTime, bestPracticeLevel, - htmlInMarkdownCheck, allowDoubleQuotesInFHIRPath, checkIPSCodes); + targetVer, igs, questionnaireMode, level, profiles, sources, inputs, mode, locale, locations, crumbTrails, forPublication, showTimes, allowExampleUrls, outputStyle, jurisdiction, noUnicodeBiDiControlChars, + watchMode, watchScanDelay, watchSettleTime, bestPracticeLevel, unknownCodeSystemsCauseErrors, noExperimentalContent, htmlInMarkdownCheck, allowDoubleQuotesInFHIRPath, checkIPSCodes); } @Override @@ -899,6 +907,8 @@ public class CliContext { ", bestPracticeLevel=" + bestPracticeLevel + ", watchSettleTime=" + watchSettleTime + ", watchScanDelay=" + watchScanDelay + + ", unknownCodeSystemsCauseErrors=" + unknownCodeSystemsCauseErrors + + ", noExperimentalContent=" + noExperimentalContent + '}'; } @@ -956,4 +966,28 @@ public class CliContext { return this; } + + @JsonProperty("unknownCodeSystemsCauseErrors") + public boolean isUnknownCodeSystemsCauseErrors() { + return unknownCodeSystemsCauseErrors; + } + + + @JsonProperty("unknownCodeSystemsCauseErrors") + public void setUnknownCodeSystemsCauseErrors(boolean unknownCodeSystemsCauseErrors) { + this.unknownCodeSystemsCauseErrors = unknownCodeSystemsCauseErrors; + } + + @JsonProperty("noExperimentalContent") + public boolean isNoExperimentalContent() { + return noExperimentalContent; + } + + + @JsonProperty("noExperimentalContent") + public void setNoExperimentalContent(boolean noExperimentalContent) { + this.noExperimentalContent = noExperimentalContent; + } + + } \ No newline at end of file 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 fcdea6386..82abdff63 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 @@ -581,6 +581,8 @@ public class ValidationService { } validationEngine.getBundleValidationRules().addAll(cliContext.getBundleValidationRules()); validationEngine.setJurisdiction(CodeSystemUtilities.readCoding(cliContext.getJurisdiction())); + validationEngine.setUnknownCodeSystemsCauseErrors(cliContext.isUnknownCodeSystemsCauseErrors()); + validationEngine.setNoExperimentalContent(cliContext.isNoExperimentalContent()); TerminologyCache.setNoCaching(cliContext.isNoInternalCaching()); validationEngine.prepare(); // generate any missing snapshots System.out.println(" go (" + timeTracker.milestone() + ")"); diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/utils/Params.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/utils/Params.java index 23136344d..0b220f5f8 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/utils/Params.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/utils/Params.java @@ -94,8 +94,8 @@ public class Params { public static final String DISABLE_DEFAULT_RESOURCE_FETCHER = "-disable-default-resource-fetcher"; public static final String CHECK_IPS_CODES = "-check-ips-codes"; public static final String BEST_PRACTICE = "-best-practice"; - - + public static final String UNKNOWN_CODESYSTEMS_CAUSE_ERROR = "-unknown-codesystems-cause-errors"; + public static final String NO_EXPERIMENTAL_CONTENT = "-no-experimental-content"; public static final String RUN_TESTS = "-run-tests"; @@ -320,6 +320,10 @@ public class Params { cliContext.setCrumbTrails(true); } else if (args[i].equals(FOR_PUBLICATION)) { cliContext.setForPublication(true); + } else if (args[i].equals(UNKNOWN_CODESYSTEMS_CAUSE_ERROR)) { + cliContext.setUnknownCodeSystemsCauseErrors(true); + } else if (args[i].equals(NO_EXPERIMENTAL_CONTENT)) { + cliContext.setNoExperimentalContent(true); } else if (args[i].equals(VERBOSE)) { cliContext.setCrumbTrails(true); } else if (args[i].equals(ALLOW_EXAMPLE_URLS)) { 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 071efc120..5c191c7c9 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 @@ -46,7 +46,7 @@ import javax.annotation.Nonnull; import org.apache.commons.lang3.NotImplementedException; import org.apache.commons.lang3.StringUtils; import org.fhir.ucum.Decimal; -import org.hl7.elm.r1.Code; + import org.hl7.fhir.exceptions.DefinitionException; import org.hl7.fhir.exceptions.FHIRException; import org.hl7.fhir.exceptions.PathEngineException; @@ -598,6 +598,8 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat private boolean example ; private IDigitalSignatureServices signatureServices; private ContextUtilities cu; + private boolean unknownCodeSystemsCauseErrors; + private boolean noExperimentalContent; public InstanceValidator(@Nonnull IWorkerContext theContext, @Nonnull IEvaluationContext hostServices, @Nonnull XVerExtensionManager xverManager) { super(theContext, xverManager, false); @@ -1125,7 +1127,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat timeTracker.tx(t, "vc "+system+"#"+code+" '"+display+"'"); if (s == null) return true; - ok = processTxIssues(errors, s, element, path, null, "no binding on code", false, null) & ok; + ok = processTxIssues(errors, s, element, path, false, null, null) & ok; if (s.isOk()) { if (s.getMessage() != null && !s.messageIsInIssues()) { @@ -1381,7 +1383,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat if (cc.hasCoding()) { long t = System.nanoTime(); ValidationResult vr = checkCodeOnServer(stack, null, cc); - bh.see(processTxIssues(errors, vr, element, path, org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity.INFORMATION, null, false, null)); + bh.see(processTxIssues(errors, vr, element, path, false, null, null)); timeTracker.tx(t, "vc " + cc.toString()); } } catch (CheckCodeOnServerException e) { @@ -1465,7 +1467,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat } else { checked.set(true); ValidationResult vr = checkCodeOnServer(stack, valueset, cc); - bh.see(processTxIssues(errors, vr, element, path, notFoundSeverityForBinding(strength), notFoundSeverityNoteForBinding(strength), false, vsRef)); + bh.see(processTxIssues(errors, vr, element, path, false, vsRef, strength)); if (!vr.isOk()) { bindingsOk = false; if (vr.getErrorClass() != null && vr.getErrorClass() == TerminologyServiceErrorClass.NOSERVICE) { @@ -1533,33 +1535,34 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat return checkDisp; } - private String notFoundSeverityNoteForBinding(BindingStrength strength) { - if (strength == BindingStrength.REQUIRED) { - return "error because this is a required binding"; - } else { - return null; - } - } +// private String notFoundSeverityNoteForBinding(BindingStrength strength, Set systems) { +// if (strength == BindingStrength.REQUIRED && +// (Utilities.listValueStartsWith("http://hl7.org/fhir", systems) || Utilities.listValueStartsWith("http://terminology.hl7.org", systems))) { +// return "error because this is a required binding to an HL7 code system"; +// } else { +// return null; +// } +// } +// +// /** +// * The terminology server will report an error for an unknown code system or version, or a dependent valueset +// * +// * but we only care for validation if the binding strength is strong enough. +// * @param binding +// * @return +// */ +// private org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity notFoundSeverityForBinding(BindingStrength strength, String systems) { +// if (strength == BindingStrength.REQUIRED && +// (Utilities.listValueStartsWith("http://hl7.org/fhir", systems) || Utilities.listValueStartsWith("http://terminology.hl7.org", systems))) { +// return org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity.ERROR; +// } else if (strength == BindingStrength.REQUIRED || strength == BindingStrength.EXTENSIBLE) { +// return org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity.WARNING; +// } else { +// return org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity.INFORMATION; +// } +// } - /** - * The terminology server will report an error for an unknown code system or version, or a dependent valueset - * - * but we only care for validation if the binding strength is strong enough. - * @param binding - * @return - */ - private org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity notFoundSeverityForBinding(BindingStrength strength) { - if (strength == BindingStrength.REQUIRED) { - return org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity.ERROR; - } else if (strength == BindingStrength.EXTENSIBLE) { - return org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity.WARNING; - } else { - return org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity.INFORMATION; - } - } - - private boolean processTxIssues(List errors, ValidationResult vr, Element element, String path, - org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity notFoundLevel, String notFoundNote, boolean ignoreCantInfer, String vsurl) { + private boolean processTxIssues(List errors, ValidationResult vr, Element element, String path, boolean ignoreCantInfer, String vsurl, BindingStrength bs) { boolean ok = true; if (vr != null) { for (OperationOutcomeIssueComponent iss : vr.getIssues()) { @@ -1567,12 +1570,35 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat && !iss.getDetails().hasCoding("http://hl7.org/fhir/tools/CodeSystem/tx-issue-type", "this-code-not-in-vs") && !(ignoreCantInfer || iss.getDetails().hasCoding("http://hl7.org/fhir/tools/CodeSystem/tx-issue-type", "cannot-infer"))) { OperationOutcomeIssueComponent i = iss.copy(); - if (i.getDetails().hasCoding("http://hl7.org/fhir/tools/CodeSystem/tx-issue-type", "not-found")) { - if (notFoundLevel != null && i.getSeverity().isHigherThan(notFoundLevel) || (vsurl != null && i.getDetails().getText().contains(vsurl))) { - i.setSeverity(notFoundLevel); + if (i.getDetails().hasCoding("http://hl7.org/fhir/tools/CodeSystem/tx-issue-type", "not-found")) { + String msg = iss.getDetails().getText(); + boolean isHL7 = msg == null ? false : msg.contains("http://hl7.org/fhir") || msg.contains("http://terminology.hl7.org"); + org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity notFoundLevel = null; + String notFoundNote = null; + if (bs == null) { + notFoundLevel = org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity.WARNING; + notFoundNote = null; // "binding=null"; + } else if (bs == BindingStrength.REQUIRED && isHL7) { + notFoundLevel = org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity.ERROR; + notFoundNote = "error because this is a required binding to an HL7 code system"; + } else if (bs == BindingStrength.REQUIRED && unknownCodeSystemsCauseErrors) { + notFoundLevel = org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity.ERROR; + notFoundNote = "error because this is a required binding"; + } else if (bs == BindingStrength.REQUIRED) { + notFoundLevel = org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity.WARNING; + notFoundNote = null; // "binding=required"; + } else if (bs == BindingStrength.EXTENSIBLE) { + notFoundLevel = org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity.WARNING; + notFoundNote = null; // "binding=extensible"; + } else { + notFoundLevel = org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity.WARNING; + notFoundNote = null; // "binding="+bs.toCode(); } - if (notFoundNote != null) { - i.getDetails().setText(i.getDetails().getText()+" ("+notFoundNote+")"); + if (notFoundLevel != null && i.getSeverity().isHigherThan(notFoundLevel)) { // && (vsurl != null && i.getDetails().getText().contains(vsurl))) { + i.setSeverity(notFoundLevel); + if (notFoundNote != null) { + i.getDetails().setText(i.getDetails().getText()+" ("+notFoundNote+")"); + } } } if (baseOptions.isDisplayWarningMode() && i.getSeverity() == org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity.ERROR && i.getDetails().hasCoding("http://hl7.org/fhir/tools/CodeSystem/tx-issue-type", "invalid-display")) { @@ -1592,7 +1618,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 = processTxIssues(errors, vr, element, path, null, "ex-checkBindings", false, null) && ok; + ok = processTxIssues(errors, vr, element, path, false, null, null) && ok; if (vr.getSeverity() != null && !vr.messageIsInIssues()) { if (vr.getSeverity() == IssueSeverity.INFORMATION) { @@ -1721,7 +1747,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat if (strength == BindingStrength.REQUIRED) { removeTrackedMessagesForLocation(errors, element, path); } - ok = processTxIssues(errors, vr, element, path, notFoundSeverityForBinding(strength), notFoundSeverityNoteForBinding(strength), false, vsRef) && ok; + ok = processTxIssues(errors, vr, element, path, false, vsRef, strength) && ok; timeTracker.tx(t, "vc "+system+"#"+code+" '"+display+"'"); if (vr != null && !vr.isOk()) { if (vr.IsNoService()) @@ -1766,6 +1792,21 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat return ok; } + private Set getUnknownSystems(ValidationResult vr) { + if (vr == null) { + return null; + } + if (vr.getUnknownSystems() != null && !vr.getUnknownSystems().isEmpty()) { + return vr.getUnknownSystems(); + } + if (vr.getSystem() != null) { + Set set = new HashSet(); + set.add(vr.getSystem()); + return set; + } + return null; + } + private boolean convertCDACodeToCodeableConcept(List errors, String path, Element element, StructureDefinition logical, CodeableConcept cc) { boolean ok = true; cc.setText(element.getNamedChildValue("originalText", false)); @@ -1851,7 +1892,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat try { long t = System.nanoTime(); ValidationResult vr = checkCodeOnServer(stack, valueset, cc); - ok = processTxIssues(errors, vr, element, path, null, "ex-checkMaxValueSet", false, maxVSUrl) && ok; + ok = processTxIssues(errors, vr, element, path, false, maxVSUrl, null) && ok; timeTracker.tx(t, "vc "+cc.toString()); if (!vr.isOk()) { if (vr.getErrorClass() != null && vr.getErrorClass().isInfrastructure()) @@ -1890,7 +1931,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat try { long t = System.nanoTime(); ValidationResult vr = checkCodeOnServer(stack, valueset, c); - ok = processTxIssues(errors, vr, element, path, null, "ex-checkMaxValueSet-2", false, maxVSUrl) && ok; + ok = processTxIssues(errors, vr, element, path, false, maxVSUrl, null) && ok; timeTracker.tx(t, "vc "+c.getSystem()+"#"+c.getCode()+" '"+c.getDisplay()+"'"); if (!vr.isOk()) { @@ -1921,7 +1962,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat try { long t = System.nanoTime(); ValidationResult vr = checkCodeOnServer(stack, valueset, value, baseOptions); - ok = processTxIssues(errors, vr, element, path, null, "ex-checkMaxValueSet-3", false, maxVSUrl) && ok; + ok = processTxIssues(errors, vr, element, path, false, maxVSUrl, null) && ok; timeTracker.tx(t, "vc "+value); if (!vr.isOk()) { if (vr.getErrorClass() != null && vr.getErrorClass().isInfrastructure()) @@ -2045,7 +2086,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat checked.set(true); vr = checkCodeOnServer(stack, valueset, c); } - ok = processTxIssues(errors, vr, element, path, notFoundSeverityForBinding(strength), notFoundSeverityNoteForBinding(strength), strength == BindingStrength.EXTENSIBLE, vsRef) && ok; + ok = processTxIssues(errors, vr, element, path, strength == BindingStrength.EXTENSIBLE, vsRef, strength) && ok; timeTracker.tx(t, "vc "+c.getSystem()+"#"+c.getCode()+" '"+c.getDisplay()+"'"); if (strength == BindingStrength.REQUIRED) { @@ -3510,7 +3551,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat } vr = checkCodeOnServer(stack, vs, value, options); } - ok = processTxIssues(errors, vr, element, path, notFoundSeverityForBinding(binding.getStrength()), notFoundSeverityNoteForBinding(binding.getStrength()), binding.getStrength() != BindingStrength.REQUIRED, binding.getValueSet()) && ok; + ok = processTxIssues(errors, vr, element, path, binding.getStrength() != BindingStrength.REQUIRED, binding.getValueSet(), binding.getStrength()) && ok; timeTracker.tx(t, "vc "+value+""); if (binding.getStrength() == BindingStrength.REQUIRED) { @@ -5678,6 +5719,10 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat hint(errors, "2023-08-14", IssueType.BUSINESSRULE, element.line(), element.col(), stack.getLiteralPath(), statusCodesDeeplyConsistent(status, standardsStatus), I18nConstants.VALIDATION_VAL_STATUS_INCONSISTENT_HINT, status, standardsStatus); } } + if (noExperimentalContent) { + String exp = element.getNamedChildValue("experimental"); + ok = rule(errors, "2024-09-17", IssueType.BUSINESSRULE, element.line(), element.col(), stack.getLiteralPath(), !"true".equals(exp), I18nConstants.VALIDATION_NO_EXPERIMENTAL_CONTENT) && ok; + } if (isHL7Core(element) && !isExample()) { ok = checkPublisherConsistency(valContext, errors, element, stack, contained) && ok; @@ -7791,4 +7836,22 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat this.fetcher = value; return this; } + + public boolean isUnknownCodeSystemsCauseErrors() { + return unknownCodeSystemsCauseErrors; + } + + public void setUnknownCodeSystemsCauseErrors(boolean unknownCodeSystemsCauseErrors) { + this.unknownCodeSystemsCauseErrors = unknownCodeSystemsCauseErrors; + } + + public boolean isNoExperimentalContent() { + return noExperimentalContent; + } + + public void setNoExperimentalContent(boolean noExperimentalContent) { + this.noExperimentalContent = noExperimentalContent; + } + + } diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/ConceptMapValidator.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/ConceptMapValidator.java index 0d6892c17..b3aeb1c4c 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/ConceptMapValidator.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/ConceptMapValidator.java @@ -34,9 +34,9 @@ public class ConceptMapValidator extends BaseValidator { private static final int TOO_MANY_CODES_TO_VALIDATE = 500; public static class PropertyDefinition { - private String type; - private String system; - private CodeSystem cs; + private final String type; + private final String system; + private final CodeSystem cs; protected PropertyDefinition(String type, String system, CodeSystem cs) { super(); this.type = type; @@ -94,7 +94,7 @@ public class ConceptMapValidator extends BaseValidator { public class CMCodingValidationRequest extends CodingValidationRequest { - private NodeStack stack; + private final NodeStack stack; public CMCodingValidationRequest(NodeStack stack, Coding code, ValueSet vs) { super(code, vs); @@ -106,7 +106,7 @@ public class ConceptMapValidator extends BaseValidator { } } - private List batch = new ArrayList<>(); + private final List batch = new ArrayList<>(); public ConceptMapValidator(BaseValidator parent) { super(parent); @@ -237,7 +237,7 @@ public class ConceptMapValidator extends BaseValidator { } else { warning(errors, "2023-03-05", IssueType.NOTFOUND, grp.line(), grp.col(), stack.push(e, -1, null, null).getLiteralPath(), sourceScope != null, I18nConstants.CONCEPTMAP_GROUP_SOURCE_UNKNOWN, e.getValue()); } - if (ctxt.source.version == null && ctxt.source.cs != null && !CodeSystemUtilities.isExemptFromMultipleVersionChecking(ctxt.source.url)) { + if (ctxt.source.version == null && ctxt.source.cs != null && !CodeSystemUtilities.isExemptFromMultipleVersionChecking(ctxt.source.url) && fetcher != null) { Set possibleVersions = fetcher.fetchCanonicalResourceVersions(null, valContext.getAppContext(), ctxt.source.url); warning(errors, NO_RULE_DATE, IssueType.INVALID, grp.line(), grp.col(), stack.getLiteralPath(), possibleVersions.size() <= 1, I18nConstants.TYPE_SPECIFIC_CHECKS_DT_CANONICAL_MULTIPLE_POSSIBLE_VERSIONS, ctxt.source.url, ctxt.source.cs.getVersion(), CommaSeparatedStringBuilder.join(", ", Utilities.sorted(possibleVersions))); 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 09f0be183..0df6dd68f 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 @@ -85,6 +85,7 @@ public class StructureDefinitionValidator extends BaseValidator { List snapshot = sd.getSnapshot().getElement(); sd.setSnapshot(null); typeName = sd.getTypeName(); + boolean experimental = "true".equals(src.getNamedChildValue("experimental", false)); StructureDefinition base = context.fetchResource(StructureDefinition.class, sd.getBaseDefinition()); if (warning(errors, NO_RULE_DATE, IssueType.NOTFOUND, stack.getLiteralPath(), base != null, I18nConstants.UNABLE_TO_FIND_BASE__FOR_, sd.getBaseDefinition(), "StructureDefinition, so can't check the differential")) { if (rule(errors, NO_RULE_DATE, IssueType.NOTFOUND, stack.getLiteralPath(), sd.hasDerivation(), I18nConstants.SD_MUST_HAVE_DERIVATION, sd.getUrl())) { @@ -129,6 +130,7 @@ public class StructureDefinitionValidator extends BaseValidator { ok = rule(errors, "2022-11-02", IssueType.NOTFOUND, stack.getLiteralPath(), base.getKindElement().primitiveValue().equals(src.getChildValue("kind")), I18nConstants.SD_DERIVATION_KIND_MISMATCH, base.getKindElement().primitiveValue(), src.getChildValue("kind")) && ok; } + warning(errors, "2024-09-17", IssueType.BUSINESSRULE, stack.getLiteralPath(), !base.getExperimental() || experimental, I18nConstants.SD_BASE_EXPERIMENTAL, sd.getBaseDefinition()); } List differentials = src.getChildrenByName("differential"); @@ -136,10 +138,10 @@ public class StructureDefinitionValidator extends BaseValidator { boolean logical = "logical".equals(src.getNamedChildValue("kind", false)); boolean constraint = "constraint".equals(src.getNamedChildValue("derivation", false)); for (Element differential : differentials) { - ok = validateElementList(errors, differential, stack.push(differential, -1, null, null), false, snapshots.size() > 0, sd, typeName, logical, constraint, src.getNamedChildValue("type", false), src.getNamedChildValue("url", false), src.getNamedChildValue("type", false), base) && ok; + ok = validateElementList(errors, differential, stack.push(differential, -1, null, null), false, snapshots.size() > 0, sd, typeName, logical, constraint, src.getNamedChildValue("type", false), src.getNamedChildValue("url", false), src.getNamedChildValue("type", false), base, experimental) && ok; } for (Element snapshotE : snapshots) { - ok = validateElementList(errors, snapshotE, stack.push(snapshotE, -1, null, null), true, true, sd, typeName, logical, constraint, src.getNamedChildValue("type", false), src.getNamedChildValue("url", false), src.getNamedChildValue("type", false), base) && ok; + ok = validateElementList(errors, snapshotE, stack.push(snapshotE, -1, null, null), true, true, sd, typeName, logical, constraint, src.getNamedChildValue("type", false), src.getNamedChildValue("url", false), src.getNamedChildValue("type", false), base, experimental) && ok; } // obligation profile support @@ -189,6 +191,7 @@ public class StructureDefinitionValidator extends BaseValidator { } } } catch (Exception e) { + e.printStackTrace(); rule(errors, NO_RULE_DATE, IssueType.EXCEPTION, stack.getLiteralPath(), false, I18nConstants.ERROR_GENERATING_SNAPSHOT, e.getMessage()); ok = false; } @@ -409,19 +412,19 @@ public class StructureDefinitionValidator extends BaseValidator { } } - private boolean validateElementList(List errors, Element elementList, NodeStack stack, boolean snapshot, boolean hasSnapshot, StructureDefinition sd, String typeName, boolean logical, boolean constraint, String rootPath, String profileUrl, String profileType, StructureDefinition base) { + private boolean validateElementList(List errors, Element elementList, NodeStack stack, boolean snapshot, boolean hasSnapshot, StructureDefinition sd, String typeName, boolean logical, boolean constraint, String rootPath, String profileUrl, String profileType, StructureDefinition base, boolean experimental) { Map invariantMap = new HashMap<>(); boolean ok = true; List elements = elementList.getChildrenByName("element"); int cc = 0; for (Element element : elements) { - ok = validateElementDefinition(errors, elements, element, stack.push(element, cc, null, null), snapshot, hasSnapshot, sd, typeName, logical, constraint, invariantMap, rootPath, profileUrl, profileType, base) && ok; + ok = validateElementDefinition(errors, elements, element, stack.push(element, cc, null, null), snapshot, hasSnapshot, sd, typeName, logical, constraint, invariantMap, rootPath, profileUrl, profileType, base, experimental) && ok; cc++; } return ok; } - private boolean validateElementDefinition(List errors, List elements, Element element, NodeStack stack, boolean snapshot, boolean hasSnapshot, StructureDefinition sd, String typeName, boolean logical, boolean constraint, Map invariantMap, String rootPath, String profileUrl, String profileType, StructureDefinition base) { + private boolean validateElementDefinition(List errors, List elements, Element element, NodeStack stack, boolean snapshot, boolean hasSnapshot, StructureDefinition sd, String typeName, boolean logical, boolean constraint, Map invariantMap, String rootPath, String profileUrl, String profileType, StructureDefinition base, boolean experimental) { boolean ok = true; boolean typeMustSupport = false; String path = element.getNamedChildValue("path", false); @@ -522,7 +525,7 @@ public class StructureDefinitionValidator extends BaseValidator { ok = rule(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, stack.getLiteralPath(), characteristics.contains("can-bind") , I18nConstants.SD_ILLEGAL_CHARACTERISTICS, "Binding", typeCodes) && ok; } Element binding = element.getNamedChild("binding", false); - ok = validateBinding(errors, binding, stack.push(binding, -1, null, null), typeCodes, snapshot, path) && ok; + ok = validateBinding(errors, binding, stack.push(binding, -1, null, null), typeCodes, snapshot, path, experimental) && ok; } else { // this is a good idea but there's plenty of cases where the rule isn't met; maybe one day it's worth investing the time to exclude these cases and bring this rule back // String bt = boundType(typeCodes); @@ -986,7 +989,7 @@ public class StructureDefinitionValidator extends BaseValidator { return null; } - private boolean validateBinding(List errors, Element binding, NodeStack stack, Set typeCodes, boolean snapshot, String path) { + private boolean validateBinding(List errors, Element binding, NodeStack stack, Set typeCodes, boolean snapshot, String path, boolean experimental) { boolean ok = true; if (bindableType(typeCodes) == null) { ok = rule(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, stack.getLiteralPath(), !snapshot, I18nConstants.SD_ED_BIND_NO_BINDABLE, path, typeCodes.toString()) && ok; @@ -1006,7 +1009,12 @@ public class StructureDefinitionValidator extends BaseValidator { if (warning(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, stack.getLiteralPath(), vs != null || serverSupportsValueSet(ref), I18nConstants.SD_ED_BIND_UNKNOWN_VS, path, ref)) { if (vs != null) { - ok = rule(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, stack.getLiteralPath(), vs instanceof ValueSet, I18nConstants.SD_ED_BIND_NOT_VS, path, ref, vs.fhirType()) && ok; + if (rule(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, stack.getLiteralPath(), vs instanceof ValueSet, I18nConstants.SD_ED_BIND_NOT_VS, path, ref, vs.fhirType())) { + ValueSet vsr = (ValueSet) vs; + warning(errors, "2024-09-17", IssueType.BUSINESSRULE, stack.getLiteralPath(), !vsr.getExperimental() || experimental, I18nConstants.SD_ED_EXPERIMENTAL_BINDING, path, ref); + } else { + ok = false; + } } } } diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/utils/FHIRPathExpressionFixer.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/utils/FHIRPathExpressionFixer.java index c4437511c..55376a293 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/utils/FHIRPathExpressionFixer.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/utils/FHIRPathExpressionFixer.java @@ -61,7 +61,7 @@ public class FHIRPathExpressionFixer { } // con-3 in R4 if (expr.equals("clinicalStatus.exists() or verificationStatus.coding.where(system='http://terminology.hl7.org/CodeSystem/condition-ver-status' and code = 'entered-in-error').exists() or category.select($this='problem-list-item').empty()")) { - return "clinicalStatus.exists() or verificationStatus.coding.where(system='http://terminology.hl7.org/CodeSystem/condition-ver-status' and code = 'entered-in-error').exists() or category.coding.exists(system='http://terminology.hl7.org/CodeSystem/condition-category' and code ='problem-list-item').empty()"; + return "(verificationStatus.coding.where(system='http://terminology.hl7.org/CodeSystem/condition-ver-status' and code = 'entered-in-error').exists() and category.coding.exists(system='http://terminology.hl7.org/CodeSystem/condition-category' and code ='problem-list-item').empty()) implies (clinicalStatus.exists())"; } // R5 ballot diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/special/TxTesterSorters.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/special/TxTesterSorters.java index 35d069e8a..a85c4db8b 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/special/TxTesterSorters.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/special/TxTesterSorters.java @@ -8,10 +8,10 @@ import java.util.Collections; import java.util.Comparator; import java.util.List; -import org.hl7.fhir.ParametersParameter; + import org.hl7.fhir.r5.formats.IParser.OutputStyle; import org.hl7.fhir.r5.formats.JsonParser; -import org.hl7.fhir.r5.model.Base; + import org.hl7.fhir.r5.model.Extension; import org.hl7.fhir.r5.model.OperationOutcome; import org.hl7.fhir.r5.model.OperationOutcome.OperationOutcomeIssueComponent; diff --git a/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/validation/tests/ValidationEngineTests.java b/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/validation/tests/ValidationEngineTests.java index bd27a6f41..320f1dd30 100644 --- a/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/validation/tests/ValidationEngineTests.java +++ b/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/validation/tests/ValidationEngineTests.java @@ -247,9 +247,9 @@ public class ValidationEngineTests { Assertions.assertTrue(checkOutcomes("testObs102", op, "Observation.text.div null error/invalid: Wrong namespace on the XHTML ('null', should be 'http://www.w3.org/1999/xhtml')\n"+ "Observation.category null information/business-rule: Reference to experimental CodeSystem http://hl7.org/fhir/observation-category\n"+ - "Observation.code.coding[2].system null information/not-found: A definition for CodeSystem 'http://acme.org/devices/clinical-codes' could not be found, so the code cannot be validated\n"+ "Observation null warning/invalid: Best Practice Recommendation: In general, all observations should have a performer\n"+ - "Observation null warning/invalid: Best Practice Recommendation: In general, all observations should have an effective[x] ()")); + "Observation null warning/invalid: Best Practice Recommendation: In general, all observations should have an effective[x] ()\n"+ + "Observation.code.coding[2].system null warning/not-found: A definition for CodeSystem 'http://acme.org/devices/clinical-codes' could not be found, so the code cannot be validated")); verifyNoTerminologyRequests(logger); } @@ -265,8 +265,8 @@ public class ValidationEngineTests { System.out.println(" .. load USCore"); OperationOutcome op = ve.validate(FhirFormat.XML, TestingUtilities.loadTestResourceStream("validator", "observation301.xml"), null); Assertions.assertTrue(checkOutcomes("test301", op, - "Observation.code.coding[3].system null information/not-found: A definition for CodeSystem 'http://acme.org/devices/clinical-codes' could not be found, so the code cannot be validated\n"+ - "Observation null warning/invalid: Best Practice Recommendation: In general, all observations should have a performer")); + "Observation null warning/invalid: Best Practice Recommendation: In general, all observations should have a performer\n"+ + "Observation.code.coding[3].system null warning/not-found: A definition for CodeSystem 'http://acme.org/devices/clinical-codes' could not be found, so the code cannot be validated")); verifyNoTerminologyRequests(logger); } diff --git a/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/validation/tests/ValidationTests.java b/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/validation/tests/ValidationTests.java index 880fb2f9c..c43b88da0 100644 --- a/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/validation/tests/ValidationTests.java +++ b/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/validation/tests/ValidationTests.java @@ -362,6 +362,9 @@ public class ValidationTests implements IEvaluationContext, IValidatorResourceFe if (content.has("security-checks")) { val.setSecurityChecks(content.get("security-checks").getAsBoolean()); } + if (content.has("no-experimental-content")) { + val.setNoExperimentalContent(content.get("no-experimental-content").getAsBoolean()); + } if (content.has("noHtmlInMarkdown")) { val.setHtmlInMarkdownCheck(HtmlInMarkdownCheck.ERROR); } diff --git a/pom.xml b/pom.xml index 15f288cc3..883b784e5 100644 --- a/pom.xml +++ b/pom.xml @@ -14,14 +14,14 @@ HAPI FHIR --> org.hl7.fhir.core - 6.3.24-SNAPSHOT + 6.3.27-SNAPSHOT pom 1.26.0 32.0.1-jre 6.4.1 - 1.5.20 + 1.5.23-SNAPSHOT 2.17.0 5.9.2 1.8.2 @@ -418,7 +418,7 @@ org.apache.maven.plugins maven-compiler-plugin - 3.10.1 + 3.13.0 11 @@ -428,7 +428,7 @@ while if true it will use an executable. --> true 512m - 4000m + 5632m true @@ -717,7 +717,7 @@ org.sonatype.plugins nexus-staging-maven-plugin - 1.6.13 + 1.7.0 true ossrh diff --git a/pull-request-pipeline.yml b/pull-request-pipeline.yml index 2f1a97d58..2ecaa863f 100644 --- a/pull-request-pipeline.yml +++ b/pull-request-pipeline.yml @@ -154,7 +154,7 @@ jobs: sourceFolder: '$(System.DefaultWorkingDirectory)/org.hl7.fhir.${{ module }}_target/' contents: '**' targetFolder: '$(System.DefaultWorkingDirectory)/org.hl7.fhir.${{ module }}/target/' - - task: Maven@3 + - task: Maven@4 inputs: mavenPomFile: 'pom.xml' options: '-P JACOCO' diff --git a/release-branch-pipeline.yml b/release-branch-pipeline.yml index 3ff7caff5..3fcbcdf96 100644 --- a/release-branch-pipeline.yml +++ b/release-branch-pipeline.yml @@ -13,7 +13,7 @@ jobs: - job: check_all_dependencies_are_releases timeoutInMinutes: 5 steps: - - task: Maven@3 + - task: Maven@4 inputs: mavenPomFile: 'pom.xml' options: '-DcheckForSnapshotDependencies' @@ -136,7 +136,7 @@ jobs: version_from_pom: $[ dependencies.get_release_version.outputs['setOutput.version_from_pom'] ] steps: # Runs 'mvn clean package' - - task: Maven@3 + - task: Maven@4 inputs: mavenPomFile: 'pom.xml' mavenOptions: '-Xmx768m -Dmaven.resolver.transport=wagon' diff --git a/setup-and-cache-job-template.yml b/setup-and-cache-job-template.yml index 311b0ce8d..1844f946b 100644 --- a/setup-and-cache-job-template.yml +++ b/setup-and-cache-job-template.yml @@ -21,7 +21,7 @@ jobs: script: mkdir -p $(MAVEN_CACHE_FOLDER); pwd; ls -al $(MAVEN_CACHE_FOLDER) - ${{ if eq(parameters.signArtifacts, true) }}: - template: setup-signing-tasks-template.yml - - task: Maven@3 + - task: Maven@4 inputs: mavenPomFile: 'pom.xml' ${{ if eq(parameters.signArtifacts, true) }}: diff --git a/test-cli-exec-job-template.yml b/test-cli-exec-job-template.yml index 003a4fd4b..4e1516247 100644 --- a/test-cli-exec-job-template.yml +++ b/test-cli-exec-job-template.yml @@ -19,7 +19,7 @@ jobs: modules: - org.hl7.fhir.validation.cli # Runs 'mvn exec' - - task: Maven@3 + - task: Maven@4 inputs: mavenPomFile: 'pom.xml' mavenOptions: '-Xmx768m -Dmaven.resolver.transport=wagon' diff --git a/test-unit-jobs-template.yml b/test-unit-jobs-template.yml index 9a77bbe2b..1b7e47685 100644 --- a/test-unit-jobs-template.yml +++ b/test-unit-jobs-template.yml @@ -24,7 +24,7 @@ jobs: modules: - org.hl7.fhir.${{ value }} # Runs 'mvn install' - - task: Maven@3 + - task: Maven@4 inputs: mavenPomFile: 'pom.xml' options: '-Dmaven.repo.local=$(MAVEN_CACHE_FOLDER) -pl org.hl7.fhir.${{value}} -Djacoco.skip=${{unit.skipJaCoCo}} -P JACOCO'